mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Decimal field fix overflow
This commit is contained in:
35
sql/field.cc
35
sql/field.cc
@ -41,6 +41,11 @@
|
||||
#include <floatingpoint.h>
|
||||
#endif
|
||||
|
||||
// Maximum allowed exponent value for converting string to decimal
|
||||
#define MAX_EXPONENT 1024
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Instansiate templates and static variables
|
||||
*****************************************************************************/
|
||||
@ -367,7 +372,6 @@ void Field_decimal::store(const char *from,uint len)
|
||||
/* The pointer where the field value starts (i.e., "where to write") */
|
||||
char *to=ptr;
|
||||
uint tmp_dec, tmp_uint;
|
||||
ulonglong tmp_ulonglong;
|
||||
/*
|
||||
The sign of the number : will be 0 (means positive but sign not
|
||||
specified), '+' or '-'
|
||||
@ -381,8 +385,7 @@ void Field_decimal::store(const char *from,uint len)
|
||||
const char *frac_digits_from, *frac_digits_end;
|
||||
/* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
|
||||
char expo_sign_char=0;
|
||||
uint exponent=0; // value of the exponent
|
||||
ulonglong exponent_ulonglong=0;
|
||||
uint exponent=0; // value of the exponent
|
||||
/*
|
||||
Pointers used when digits move from the left of the '.' to the
|
||||
right of the '.' (explained below)
|
||||
@ -485,14 +488,13 @@ void Field_decimal::store(const char *from,uint len)
|
||||
*/
|
||||
for (;from!=end && isdigit(*from); from++)
|
||||
{
|
||||
exponent_ulonglong=10*exponent_ulonglong+(ulonglong)(*from-'0');
|
||||
if (exponent_ulonglong>(ulonglong)UINT_MAX)
|
||||
exponent=10*exponent+(*from-'0');
|
||||
if (exponent>MAX_EXPONENT)
|
||||
{
|
||||
exponent_ulonglong=(ulonglong)UINT_MAX;
|
||||
exponent=MAX_EXPONENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
exponent=(uint)(exponent_ulonglong);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -534,21 +536,21 @@ void Field_decimal::store(const char *from,uint len)
|
||||
*/
|
||||
|
||||
/*
|
||||
Below tmp_ulongulong cannot overflow,
|
||||
Below tmp_uint cannot overflow with small enough MAX_EXPONENT setting,
|
||||
as int_digits_added_zeros<=exponent<4G and
|
||||
(ulonglong)(int_digits_end-int_digits_from)<=max_allowed_packet<=2G and
|
||||
(ulonglong)(frac_digits_from-int_digits_tail_from)<=max_allowed_packet<=2G
|
||||
*/
|
||||
|
||||
if (!expo_sign_char)
|
||||
tmp_ulonglong=(ulonglong)tmp_dec+(ulonglong)(int_digits_end-int_digits_from);
|
||||
tmp_uint=tmp_dec+(uint)(int_digits_end-int_digits_from);
|
||||
else if (expo_sign_char == '-')
|
||||
{
|
||||
tmp_uint=min(exponent,(uint)(int_digits_end-int_digits_from));
|
||||
frac_digits_added_zeros=exponent-tmp_uint;
|
||||
int_digits_end -= tmp_uint;
|
||||
frac_digits_head_end=int_digits_end+tmp_uint;
|
||||
tmp_ulonglong=(ulonglong)tmp_dec+(ulonglong)(int_digits_end-int_digits_from);
|
||||
tmp_uint=tmp_dec+(uint)(int_digits_end-int_digits_from);
|
||||
}
|
||||
else // (expo_sign_char=='+')
|
||||
{
|
||||
@ -575,9 +577,9 @@ void Field_decimal::store(const char *from,uint len)
|
||||
int_digits_added_zeros=0;
|
||||
}
|
||||
}
|
||||
tmp_ulonglong=(ulonglong)tmp_dec+(ulonglong)(int_digits_end-int_digits_from)
|
||||
+(ulonglong)(frac_digits_from-int_digits_tail_from)+
|
||||
(ulonglong)int_digits_added_zeros;
|
||||
tmp_uint=tmp_dec+(int_digits_end-int_digits_from)
|
||||
+(uint)(frac_digits_from-int_digits_tail_from)+
|
||||
int_digits_added_zeros;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -588,7 +590,7 @@ void Field_decimal::store(const char *from,uint len)
|
||||
If the sign is defined and '-', we need one position for it
|
||||
*/
|
||||
|
||||
if ((ulonglong)field_length < tmp_ulonglong + (ulonglong) (sign_char == '-'))
|
||||
if (field_length < tmp_uint + (sign_char == '-'))
|
||||
//the rightmost sum above cannot overflow
|
||||
{
|
||||
// too big number, change to max or min number
|
||||
@ -596,11 +598,6 @@ void Field_decimal::store(const char *from,uint len)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
If the above test was ok, then tmp_ulonglong<4G and the following cast is valid
|
||||
*/
|
||||
tmp_uint=(uint)tmp_ulonglong;
|
||||
|
||||
/*
|
||||
Tmp_left_pos is the position where the leftmost digit of
|
||||
the int_% parts will be written
|
||||
|
Reference in New Issue
Block a user