From: Tor Didriksen Date: March 3 2011 2:25pm Subject: bzr commit into mysql-5.5 branch (tor.didriksen:3369) Bug#11792200 List-Archive: http://lists.mysql.com/commits/132377 X-Bug: 11792200 Message-Id: <20110303142545.1724E37E4@atum07.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============3983834311193387525==" --===============3983834311193387525== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/didrik/repo/5.5/ based on revid:alexander.barkov@stripped 3369 Tor Didriksen 2011-03-03 Bug #11792200 - DIVIDING LARGE NUMBERS CAUSES STACK CORRUPTIONS This was a buffer overrun in do_div_mod(), overwriting the internal buffer of auto variable 'tmp' in Item_func_int_div::val_int. Result on windows: 'this' is set to zero, and crash. Ran fine on other platforms (no valgrind warnings), but this is undefined behaviour on any platform of course. @ include/decimal.h Add const qualifiers to function prototypes which are used by sql/my_decimal.h @ mysql-test/r/func_math.result New test case. @ mysql-test/t/func_math.test New test case. @ sql/my_decimal.h Remove several C-style casts: - some of the were up-casts, and thus un-necessary - some of them should have been const-casts, but it is better to make the underlying library functions in (decimal.[h|c]) const instead. @ strings/decimal.c Check for buffer overrun in do_div_mod() Add const qualifiers to functions which are used by sql/my_decimal.h modified: include/decimal.h mysql-test/r/func_math.result mysql-test/t/func_math.test sql/my_decimal.h strings/decimal.c === modified file 'include/decimal.h' --- a/include/decimal.h 2007-05-24 10:24:36 +0000 +++ b/include/decimal.h 2011-03-03 14:25:41 +0000 @@ -29,14 +29,14 @@ typedef struct st_decimal_t { int internal_str2dec(const char *from, decimal_t *to, char **end, my_bool fixed); -int decimal2string(decimal_t *from, char *to, int *to_len, +int decimal2string(const decimal_t *from, char *to, int *to_len, int fixed_precision, int fixed_decimals, char filler); int decimal2ulonglong(decimal_t *from, ulonglong *to); int ulonglong2decimal(ulonglong from, decimal_t *to); int decimal2longlong(decimal_t *from, longlong *to); int longlong2decimal(longlong from, decimal_t *to); -int decimal2double(decimal_t *from, double *to); +int decimal2double(const decimal_t *from, double *to); int double2decimal(double from, decimal_t *to); int decimal_actual_fraction(decimal_t *from); int decimal2bin(decimal_t *from, uchar *to, int precision, int scale); @@ -47,17 +47,17 @@ int decimal_bin_size(int precision, int int decimal_result_size(decimal_t *from1, decimal_t *from2, char op, int param); -int decimal_intg(decimal_t *from); -int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to); -int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to); -int decimal_cmp(decimal_t *from1, decimal_t *from2); -int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to); -int decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to, +int decimal_intg(const decimal_t *from); +int decimal_add(const decimal_t *from1, const decimal_t *from2, decimal_t *to); +int decimal_sub(const decimal_t *from1, const decimal_t *from2, decimal_t *to); +int decimal_cmp(const decimal_t *from1, const decimal_t *from2); +int decimal_mul(const decimal_t *from1, const decimal_t *from2, decimal_t *to); +int decimal_div(const decimal_t *from1, const decimal_t *from2, decimal_t *to, int scale_incr); -int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to); -int decimal_round(decimal_t *from, decimal_t *to, int new_scale, +int decimal_mod(const decimal_t *from1, const decimal_t *from2, decimal_t *to); +int decimal_round(const decimal_t *from, decimal_t *to, int new_scale, decimal_round_mode mode); -int decimal_is_zero(decimal_t *from); +int decimal_is_zero(const decimal_t *from); void max_decimal(int precision, int frac, decimal_t *to); #define string2decimal(A,B,C) internal_str2dec((A), (B), (C), 0) === modified file 'mysql-test/r/func_math.result' --- a/mysql-test/r/func_math.result 2011-01-14 14:03:37 +0000 +++ b/mysql-test/r/func_math.result 2011-03-03 14:25:41 +0000 @@ -656,3 +656,11 @@ Warning 1366 Incorrect decimal value: '' SELECT 1 div null; 1 div null NULL +# +# Bug #11792200 - DIVIDING LARGE NUMBERS CAUSES STACK CORRUPTIONS +# +select (1.175494351E-37 div 1.7976931348623157E+308); +(1.175494351E-37 div 1.7976931348623157E+308) +0 +Warnings: +Warning 1292 Truncated incorrect DECIMAL value: '' === modified file 'mysql-test/t/func_math.test' --- a/mysql-test/t/func_math.test 2011-01-14 14:03:37 +0000 +++ b/mysql-test/t/func_math.test 2011-03-03 14:25:41 +0000 @@ -500,3 +500,8 @@ SELECT ((@a:=@b:=1.0) div (@b:=@a:=get_f --echo # Bug #59498 div function broken in mysql-trunk --echo # SELECT 1 div null; + +--echo # +--echo # Bug #11792200 - DIVIDING LARGE NUMBERS CAUSES STACK CORRUPTIONS +--echo # +select (1.175494351E-37 div 1.7976931348623157E+308); === modified file 'sql/my_decimal.h' --- a/sql/my_decimal.h 2011-01-14 09:05:14 +0000 +++ b/sql/my_decimal.h 2011-03-03 14:25:41 +0000 @@ -178,7 +178,7 @@ void max_my_decimal(my_decimal *to, int { DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&& (frac <= DECIMAL_MAX_SCALE)); - max_decimal(precision, frac, (decimal_t*) to); + max_decimal(precision, frac, to); } inline void max_internal_decimal(my_decimal *to) @@ -277,14 +277,19 @@ inline int binary2my_decimal(uint mask, const uchar *bin, my_decimal *d, int prec, int scale) { - return check_result(mask, bin2decimal(bin, (decimal_t*) d, prec, scale)); + return check_result(mask, bin2decimal(bin, d, prec, scale)); } inline int my_decimal_set_zero(my_decimal *d) { - decimal_make_zero(((decimal_t*) d)); + /* + We need the up-cast here, since my_decimal has sign() member functions, + which conflicts with decimal_t::size + (and decimal_make_zero is a macro, rather than a funcion). + */ + decimal_make_zero(static_cast(d)); return 0; } @@ -292,7 +297,7 @@ int my_decimal_set_zero(my_decimal *d) inline bool my_decimal_is_zero(const my_decimal *decimal_value) { - return decimal_is_zero((decimal_t*) decimal_value); + return decimal_is_zero(decimal_value); } @@ -300,7 +305,7 @@ inline int my_decimal_round(uint mask, const my_decimal *from, int scale, bool truncate, my_decimal *to) { - return check_result(mask, decimal_round((decimal_t*) from, to, scale, + return check_result(mask, decimal_round(from, to, scale, (truncate ? TRUNCATE : HALF_UP))); } @@ -308,14 +313,14 @@ int my_decimal_round(uint mask, const my inline int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to) { - return check_result(mask, decimal_round((decimal_t*) from, to, 0, FLOOR)); + return check_result(mask, decimal_round(from, to, 0, FLOOR)); } inline int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to) { - return check_result(mask, decimal_round((decimal_t*) from, to, 0, CEILING)); + return check_result(mask, decimal_round(from, to, 0, CEILING)); } @@ -337,7 +342,7 @@ int my_decimal2int(uint mask, const my_d { my_decimal rounded; /* decimal_round can return only E_DEC_TRUNCATED */ - decimal_round((decimal_t*)d, &rounded, 0, HALF_UP); + decimal_round(d, &rounded, 0, HALF_UP); return check_result(mask, (unsigned_flag ? decimal2ulonglong(&rounded, (ulonglong *)l) : decimal2longlong(&rounded, l))); @@ -348,15 +353,14 @@ inline int my_decimal2double(uint, const my_decimal *d, double *result) { /* No need to call check_result as this will always succeed */ - return decimal2double((decimal_t*) d, result); + return decimal2double(d, result); } inline int str2my_decimal(uint mask, const char *str, my_decimal *d, char **end) { - return check_result_and_overflow(mask, string2decimal(str,(decimal_t*)d,end), - d); + return check_result_and_overflow(mask, string2decimal(str, d, end), d); } @@ -379,7 +383,7 @@ my_decimal *date2my_decimal(MYSQL_TIME * inline int double2my_decimal(uint mask, double val, my_decimal *d) { - return check_result_and_overflow(mask, double2decimal(val, (decimal_t*)d), d); + return check_result_and_overflow(mask, double2decimal(val, d), d); } @@ -409,7 +413,7 @@ int my_decimal_add(uint mask, my_decimal const my_decimal *b) { return check_result_and_overflow(mask, - decimal_add((decimal_t*)a,(decimal_t*)b,res), + decimal_add(a, b, res), res); } @@ -419,7 +423,7 @@ int my_decimal_sub(uint mask, my_decimal const my_decimal *b) { return check_result_and_overflow(mask, - decimal_sub((decimal_t*)a,(decimal_t*)b,res), + decimal_sub(a, b, res), res); } @@ -429,7 +433,7 @@ int my_decimal_mul(uint mask, my_decimal const my_decimal *b) { return check_result_and_overflow(mask, - decimal_mul((decimal_t*)a,(decimal_t*)b,res), + decimal_mul(a, b, res), res); } @@ -439,8 +443,7 @@ int my_decimal_div(uint mask, my_decimal const my_decimal *b, int div_scale_inc) { return check_result_and_overflow(mask, - decimal_div((decimal_t*)a,(decimal_t*)b,res, - div_scale_inc), + decimal_div(a, b, res, div_scale_inc), res); } @@ -450,7 +453,7 @@ int my_decimal_mod(uint mask, my_decimal const my_decimal *b) { return check_result_and_overflow(mask, - decimal_mod((decimal_t*)a,(decimal_t*)b,res), + decimal_mod(a, b, res), res); } @@ -462,14 +465,14 @@ int my_decimal_mod(uint mask, my_decimal inline int my_decimal_cmp(const my_decimal *a, const my_decimal *b) { - return decimal_cmp((decimal_t*) a, (decimal_t*) b); + return decimal_cmp(a, b); } inline int my_decimal_intg(const my_decimal *a) { - return decimal_intg((decimal_t*) a); + return decimal_intg(a); } === modified file 'strings/decimal.c' --- a/strings/decimal.c 2011-01-19 13:31:17 +0000 +++ b/strings/decimal.c 2011-03-03 14:25:41 +0000 @@ -248,7 +248,7 @@ void max_decimal(int precision, int frac } -static dec1 *remove_leading_zeroes(decimal_t *from, int *intg_result) +static dec1 *remove_leading_zeroes(const decimal_t *from, int *intg_result) { int intg= from->intg, i; dec1 *buf0= from->buf; @@ -326,7 +326,7 @@ int decimal_actual_fraction(decimal_t *f E_DEC_OK/E_DEC_TRUNCATED/E_DEC_OVERFLOW */ -int decimal2string(decimal_t *from, char *to, int *to_len, +int decimal2string(const decimal_t *from, char *to, int *to_len, int fixed_precision, int fixed_decimals, char filler) { @@ -942,7 +942,7 @@ fatal_error: E_DEC_OK/E_DEC_OVERFLOW/E_DEC_TRUNCATED */ -int decimal2double(decimal_t *from, double *to) +int decimal2double(const decimal_t *from, double *to) { char strbuf[FLOATING_POINT_BUFFER], *end; int len= sizeof(strbuf); @@ -1461,7 +1461,7 @@ int decimal_bin_size(int precision, int */ int -decimal_round(decimal_t *from, decimal_t *to, int scale, +decimal_round(const decimal_t *from, decimal_t *to, int scale, decimal_round_mode mode) { int frac0=scale>0 ? ROUND_UP(scale) : scale/DIG_PER_DEC1, @@ -1695,7 +1695,7 @@ int decimal_result_size(decimal_t *from1 return -1; /* shut up the warning */ } -static int do_add(decimal_t *from1, decimal_t *from2, decimal_t *to) +static int do_add(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg), frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac), @@ -1777,7 +1777,7 @@ static int do_add(decimal_t *from1, deci /* to=from1-from2. if to==0, return -1/0/+1 - the result of the comparison */ -static int do_sub(decimal_t *from1, decimal_t *from2, decimal_t *to) +static int do_sub(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg), frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac); @@ -1846,7 +1846,7 @@ static int do_sub(decimal_t *from1, deci /* ensure that always from1 > from2 (and intg1 >= intg2) */ if (carry) { - swap_variables(decimal_t *,from1,from1); + swap_variables(const decimal_t *, from1, from2); swap_variables(dec1 *,start1, start2); swap_variables(int,intg1,intg2); swap_variables(int,frac1,frac2); @@ -1912,35 +1912,35 @@ static int do_sub(decimal_t *from1, deci return error; } -int decimal_intg(decimal_t *from) +int decimal_intg(const decimal_t *from) { int res; remove_leading_zeroes(from, &res); return res; } -int decimal_add(decimal_t *from1, decimal_t *from2, decimal_t *to) +int decimal_add(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { if (likely(from1->sign == from2->sign)) return do_add(from1, from2, to); return do_sub(from1, from2, to); } -int decimal_sub(decimal_t *from1, decimal_t *from2, decimal_t *to) +int decimal_sub(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { if (likely(from1->sign == from2->sign)) return do_sub(from1, from2, to); return do_add(from1, from2, to); } -int decimal_cmp(decimal_t *from1, decimal_t *from2) +int decimal_cmp(const decimal_t *from1, const decimal_t *from2) { if (likely(from1->sign == from2->sign)) return do_sub(from1, from2, 0); return from1->sign > from2->sign ? -1 : 1; } -int decimal_is_zero(decimal_t *from) +int decimal_is_zero(const decimal_t *from) { dec1 *buf1=from->buf, *end=buf1+ROUND_UP(from->intg)+ROUND_UP(from->frac); @@ -1971,7 +1971,7 @@ int decimal_is_zero(decimal_t *from) XXX if this library is to be used with huge numbers of thousands of digits, fast multiplication must be implemented. */ -int decimal_mul(decimal_t *from1, decimal_t *from2, decimal_t *to) +int decimal_mul(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { int intg1=ROUND_UP(from1->intg), intg2=ROUND_UP(from2->intg), frac1=ROUND_UP(from1->frac), frac2=ROUND_UP(from2->frac), @@ -2095,8 +2095,8 @@ int decimal_mul(decimal_t *from1, decima changed to malloc (or at least fallback to malloc if alloca() fails) but then, decimal_mul() should be rewritten too :( */ -static int do_div_mod(decimal_t *from1, decimal_t *from2, - decimal_t *to, decimal_t *mod, int scale_incr) +static int do_div_mod(const decimal_t *from1, const decimal_t *from2, + decimal_t *to, decimal_t *mod, int scale_incr) { int frac1=ROUND_UP(from1->frac)*DIG_PER_DEC1, prec1=from1->intg+frac1, frac2=ROUND_UP(from2->frac)*DIG_PER_DEC1, prec2=from2->intg+frac2, @@ -2181,9 +2181,12 @@ static int do_div_mod(decimal_t *from1, } buf0=to->buf; stop0=buf0+intg0+frac0; + DBUG_ASSERT(stop0 <= &to->buf[to->len]); if (likely(div_mod)) - while (dintg++ < 0) + while (dintg++ < 0 && buf0 < &to->buf[to->len]) + { *buf0++=0; + } len1=(i=ROUND_UP(prec1))+ROUND_UP(2*frac2+scale_incr+1) + 1; set_if_bigger(len1, 3); @@ -2355,7 +2358,8 @@ done: */ int -decimal_div(decimal_t *from1, decimal_t *from2, decimal_t *to, int scale_incr) +decimal_div(const decimal_t *from1, const decimal_t *from2, decimal_t *to, + int scale_incr) { return do_div_mod(from1, from2, to, 0, scale_incr); } @@ -2387,7 +2391,7 @@ decimal_div(decimal_t *from1, decimal_t thus, there's no requirement for M or N to be integers */ -int decimal_mod(decimal_t *from1, decimal_t *from2, decimal_t *to) +int decimal_mod(const decimal_t *from1, const decimal_t *from2, decimal_t *to) { return do_div_mod(from1, from2, 0, to, 0); } --===============3983834311193387525== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/tor.didriksen@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: tor.didriksen@stripped\ # wdomckpmfo3evs52 # target_branch: file:///export/home/didrik/repo/5.5/ # testament_sha1: d1d5961cfb9360d9657bcd1aa51ca4b905f61ebc # timestamp: 2011-03-03 15:25:44 +0100 # source_branch: file:///export/home/didrik/repo/trunk/ # base_revision_id: alexander.barkov@stripped\ # kzo1k4uqpw01m2ud # # Begin bundle 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 --===============3983834311193387525==--