Skip to content

Commit

Permalink
Fixed #7997: Unexpected results when comparing integer with string co…
Browse files Browse the repository at this point in the history
…ntaining integer value out of bigint range

(cherry picked from commit 7531251)
  • Loading branch information
AlexPeshkoff committed Mar 12, 2024
1 parent 728f8ee commit 3940641
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 18 deletions.
37 changes: 25 additions & 12 deletions src/common/cvt.cpp
Expand Up @@ -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)
{
/**************************************
*
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -2758,9 +2767,9 @@ class RetValue : public RetPtr

lb10 compareLimitBy10()
{
if (value > Traits::UPPER_LIMIT_BY_10)
if (static_cast<typename Traits::UnsignedType>(value) > Traits::UPPER_LIMIT_BY_10)
return RETVAL_OVERFLOW;
if (value == Traits::UPPER_LIMIT_BY_10)
if (static_cast<typename Traits::UnsignedType>(value) == Traits::UPPER_LIMIT_BY_10)
return RETVAL_POSSIBLE_OVERFLOW;
return RETVAL_NO_OVERFLOW;
}
Expand Down Expand Up @@ -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;
};

Expand All @@ -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;
};

Expand All @@ -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)
{
/**************************************
*
Expand All @@ -2864,14 +2876,15 @@ SSHORT CVT_decompose(const char* str, USHORT len, SINT64* val, ErrorFunction err
**************************************/

RetValue<SINT64Traits> value(val);
return cvt_decompose(str, len, &value, err);
return cvt_decompose(str, len, &value, err, overflow);
}


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;
};
Expand Down Expand Up @@ -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)
{
/**************************************
*
Expand Down Expand Up @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions src/common/cvt.h
Expand Up @@ -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*);
Expand Down
4 changes: 2 additions & 2 deletions src/jrd/cvt.cpp
Expand Up @@ -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<FB_UINT64>(value) >= NUMERIC_LIMIT)
{
// possibility of an overflow
if ((value > NUMERIC_LIMIT) || (*p > '8' && sign == -1) || (*p > '7' && sign != -1))
if ((static_cast<FB_UINT64>(value) > NUMERIC_LIMIT) || (*p > '8' && sign == -1) || (*p > '7' && sign != -1))
over = true;
}

Expand Down
14 changes: 12 additions & 2 deletions src/jrd/cvt2.cpp
Expand Up @@ -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)
Expand Down

0 comments on commit 3940641

Please sign in to comment.