Skip to content

Commit

Permalink
types: fix undefined behavior in numeric types cast (cast 1<<64 to ui…
Browse files Browse the repository at this point in the history
…nt64) (#11968) (#16239)
  • Loading branch information
sre-bot authored Apr 10, 2020
1 parent d82cf4c commit f03ea0f
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 3 deletions.
4 changes: 4 additions & 0 deletions expression/builtin_cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,10 @@ func (b *builtinCastRealAsIntSig) evalInt(row chunk.Row) (res int64, isNull bool
uintVal, err = types.ConvertFloatToUint(sc, val, types.IntergerUnsignedUpperBound(mysql.TypeLonglong), mysql.TypeLonglong)
res = int64(uintVal)
}
err = b.ctx.GetSessionVars().StmtCtx.HandleOverflow(err, err)
if err != nil {
return res, false, err
}
return res, isNull, err
}

Expand Down
7 changes: 7 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2213,6 +2213,13 @@ func (s *testIntegrationSuite) TestBuiltin(c *C) {
c.Assert(last, Equals, "bigint")
tk.MustExec(`drop table tb5;`)

tk.MustExec(`create table tb5(a double(64));`)
tk.MustExec(`insert into test.tb5 (a) values (18446744073709551616);`)
tk.MustExec(`insert into test.tb5 (a) values (184467440737095516160);`)
result = tk.MustQuery(`select cast(a as unsigned) from test.tb5;`)
result.Check(testkit.Rows("9223372036854775807", "9223372036854775807"))
tk.MustExec(`drop table tb5`)

// test builtinCastIntAsDecimalSig
tk.MustExec(`create table tb5(a bigint(64) unsigned, b decimal(64, 10));`)
tk.MustExec(`insert into tb5 (a, b) values (9223372036854775808, 9223372036854775808);`)
Expand Down
8 changes: 6 additions & 2 deletions types/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,12 @@ func ConvertFloatToUint(sc *stmtctx.StatementContext, fval float64, upperBound u
return uint64(int64(val)), overflow(val, tp)
}

if val > float64(upperBound) {
return upperBound, overflow(val, tp)
ubf := float64(upperBound)
if val == ubf {
return uint64(math.MaxInt64), nil
}
if val > ubf {
return uint64(math.MaxInt64), overflow(val, tp)
}
return uint64(val), nil
}
Expand Down
2 changes: 1 addition & 1 deletion types/convert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ func (s *testTypeConvertSuite) TestConvert(c *C) {
unsignedAccept(c, mysql.TypeLonglong, -1, "18446744073709551615")
unsignedAccept(c, mysql.TypeLonglong, 0, "0")
unsignedAccept(c, mysql.TypeLonglong, uint64(math.MaxUint64), strvalue(uint64(math.MaxUint64)))
unsignedDeny(c, mysql.TypeLonglong, math.MaxUint64*1.1, strvalue(uint64(math.MaxUint64)))
unsignedDeny(c, mysql.TypeLonglong, math.MaxUint64*1.1, strvalue(uint64(math.MaxInt64)))

// integer from string
signedAccept(c, mysql.TypeLong, " 234 ", "234")
Expand Down

0 comments on commit f03ea0f

Please sign in to comment.