From f03ea0f7a2d20598de1c795fb49a0a83e485cd5d Mon Sep 17 00:00:00 2001 From: pingcap-github-bot Date: Fri, 10 Apr 2020 14:11:58 +0800 Subject: [PATCH] types: fix undefined behavior in numeric types cast (cast 1<<64 to uint64) (#11968) (#16239) --- expression/builtin_cast.go | 4 ++++ expression/integration_test.go | 7 +++++++ types/convert.go | 8 ++++++-- types/convert_test.go | 2 +- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index 2e6aa0c7a2b64..7154fa8cd4ae9 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -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 } diff --git a/expression/integration_test.go b/expression/integration_test.go index 27173fe636c4a..bfce9c40b1c2f 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -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);`) diff --git a/types/convert.go b/types/convert.go index 344db78681d7f..a2a4293687187 100644 --- a/types/convert.go +++ b/types/convert.go @@ -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 } diff --git a/types/convert_test.go b/types/convert_test.go index 664e8fb107ec6..deff299acdf24 100644 --- a/types/convert_test.go +++ b/types/convert_test.go @@ -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")