From 39406410e768aafcd2d2df3a390019dce2c0b2d8 Mon Sep 17 00:00:00 2001 From: AlexPeshkoff Date: Fri, 9 Feb 2024 20:08:34 +0300 Subject: [PATCH] Fixed #7997: Unexpected results when comparing integer with string containing integer value out of bigint range (cherry picked from commit 7531251a051fd2585e2e2429b517103db74ab722) --- src/common/cvt.cpp | 37 +++++++++++++++++++++++++------------ src/common/cvt.h | 4 ++-- src/jrd/cvt.cpp | 4 ++-- src/jrd/cvt2.cpp | 14 ++++++++++++-- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/common/cvt.cpp b/src/common/cvt.cpp index 7f7efabf03b..d805ebc6f85 100644 --- a/src/common/cvt.cpp +++ b/src/common/cvt.cpp @@ -2502,7 +2502,8 @@ static void hex_to_value(const char*& string, const char* end, RetPtr* retValue) static SSHORT cvt_decompose(const char* string, USHORT length, RetPtr* return_value, - ErrorFunction err) + ErrorFunction err, + int* overflow = nullptr) { /************************************** * @@ -2600,15 +2601,23 @@ static SSHORT cvt_decompose(const char* string, if (p >= end) continue; } - err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); + if (overflow) + *overflow = 1; + else + err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); return 0; + case RetPtr::RETVAL_POSSIBLE_OVERFLOW: if ((*p > '8' && sign == -1) || (*p > '7' && sign != -1)) { - err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); + if (overflow) + *overflow = 1; + else + err(Arg::Gds(isc_arith_except) << Arg::Gds(isc_numeric_out_of_range)); return 0; } break; + default: break; } @@ -2758,9 +2767,9 @@ class RetValue : public RetPtr lb10 compareLimitBy10() { - if (value > Traits::UPPER_LIMIT_BY_10) + if (static_cast(value) > Traits::UPPER_LIMIT_BY_10) return RETVAL_OVERFLOW; - if (value == Traits::UPPER_LIMIT_BY_10) + if (static_cast(value) == Traits::UPPER_LIMIT_BY_10) return RETVAL_POSSIBLE_OVERFLOW; return RETVAL_NO_OVERFLOW; } @@ -2791,7 +2800,8 @@ class SSHORTTraits { public: typedef SSHORT ValueType; - static const SSHORT UPPER_LIMIT_BY_10 = MAX_SSHORT / 10; + typedef USHORT UnsignedType; + static const USHORT UPPER_LIMIT_BY_10 = MAX_SSHORT / 10; static const SSHORT LOWER_LIMIT = MIN_SSHORT; }; @@ -2818,7 +2828,8 @@ class SLONGTraits { public: typedef SLONG ValueType; - static const SLONG UPPER_LIMIT_BY_10 = MAX_SLONG / 10; + typedef ULONG UnsignedType; + static const ULONG UPPER_LIMIT_BY_10 = MAX_SLONG / 10; static const SLONG LOWER_LIMIT = MIN_SLONG; }; @@ -2845,11 +2856,12 @@ class SINT64Traits { public: typedef SINT64 ValueType; - static const SINT64 UPPER_LIMIT_BY_10 = MAX_SINT64 / 10; + typedef FB_UINT64 UnsignedType; + static const FB_UINT64 UPPER_LIMIT_BY_10 = MAX_SINT64 / 10; static const SINT64 LOWER_LIMIT = MIN_SINT64; }; -SSHORT CVT_decompose(const char* str, USHORT len, SINT64* val, ErrorFunction err) +SSHORT CVT_decompose(const char* str, USHORT len, SINT64* val, ErrorFunction err, int* overflow) { /************************************** * @@ -2864,7 +2876,7 @@ SSHORT CVT_decompose(const char* str, USHORT len, SINT64* val, ErrorFunction err **************************************/ RetValue value(val); - return cvt_decompose(str, len, &value, err); + return cvt_decompose(str, len, &value, err, overflow); } @@ -2872,6 +2884,7 @@ class I128Traits { public: typedef Int128 ValueType; + typedef Int128 UnsignedType; // To be fixed when adding int256 static const CInt128 UPPER_LIMIT_BY_10; static const CInt128 LOWER_LIMIT; }; @@ -3457,7 +3470,7 @@ SQUAD CVT_get_quad(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunc } -SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err) +SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFunction err, int* overflow) { /************************************** * @@ -3559,7 +3572,7 @@ SINT64 CVT_get_int64(const dsc* desc, SSHORT scale, DecimalStatus decSt, ErrorFu { USHORT length = CVT_make_string(desc, ttype_ascii, &p, &buffer, sizeof(buffer), decSt, err); - scale -= CVT_decompose(p, length, &value, err); + scale -= CVT_decompose(p, length, &value, err, overflow); } break; diff --git a/src/common/cvt.h b/src/common/cvt.h index a2e9dd36654..d130d3cf7e1 100644 --- a/src/common/cvt.h +++ b/src/common/cvt.h @@ -99,11 +99,11 @@ void CVT_move_common(const dsc*, dsc*, Firebird::DecimalStatus, Firebird::Callba void CVT_move(const dsc*, dsc*, Firebird::DecimalStatus, ErrorFunction); SSHORT CVT_decompose(const char*, USHORT, SSHORT*, ErrorFunction); SSHORT CVT_decompose(const char*, USHORT, SLONG*, ErrorFunction); -SSHORT CVT_decompose(const char*, USHORT, SINT64*, ErrorFunction); +SSHORT CVT_decompose(const char*, USHORT, SINT64*, ErrorFunction, int* overflow = nullptr); SSHORT CVT_decompose(const char*, USHORT, Firebird::Int128*, ErrorFunction); USHORT CVT_get_string_ptr(const dsc*, USHORT*, UCHAR**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction); USHORT CVT_get_string_ptr_common(const dsc*, USHORT*, UCHAR**, vary*, USHORT, Firebird::DecimalStatus, Firebird::Callbacks*); -SINT64 CVT_get_int64(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction); +SINT64 CVT_get_int64(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction, int* overflow = nullptr); SQUAD CVT_get_quad(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction); void CVT_string_to_datetime(const dsc*, ISC_TIMESTAMP_TZ*, bool*, const Firebird::EXPECT_DATETIME, bool, Firebird::Callbacks*); diff --git a/src/jrd/cvt.cpp b/src/jrd/cvt.cpp index 3c5c1ce24e9..aece34b571f 100644 --- a/src/jrd/cvt.cpp +++ b/src/jrd/cvt.cpp @@ -236,10 +236,10 @@ UCHAR CVT_get_numeric(const UCHAR* string, const USHORT length, SSHORT* scale, v if (!over) { - if (value >= NUMERIC_LIMIT) + if (static_cast(value) >= NUMERIC_LIMIT) { // possibility of an overflow - if ((value > NUMERIC_LIMIT) || (*p > '8' && sign == -1) || (*p > '7' && sign != -1)) + if ((static_cast(value) > NUMERIC_LIMIT) || (*p > '8' && sign == -1) || (*p > '7' && sign != -1)) over = true; } diff --git a/src/jrd/cvt2.cpp b/src/jrd/cvt2.cpp index 6ed5ed14e29..32c23d3fc0d 100644 --- a/src/jrd/cvt2.cpp +++ b/src/jrd/cvt2.cpp @@ -543,8 +543,18 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt scale = MIN(arg1->dsc_scale, arg2->dsc_scale); else scale = arg1->dsc_scale; - const SINT64 temp1 = CVT_get_int64(arg1, scale, decSt, ERR_post); - const SINT64 temp2 = CVT_get_int64(arg2, scale, decSt, ERR_post); + + int overflow = 0; + const SINT64 temp1 = CVT_get_int64(arg1, scale, decSt, ERR_post, &overflow); + const SINT64 temp2 = CVT_get_int64(arg2, scale, decSt, ERR_post, &overflow); + + if (overflow) + { + const Int128 temp1 = CVT_get_int128(arg1, scale, decSt, ERR_post); + const Int128 temp2 = CVT_get_int128(arg2, scale, decSt, ERR_post); + return temp1.compare(temp2); + } + if (temp1 == temp2) return 0; if (temp1 > temp2)