summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatjana Azundris Nuernberg <tatjana.nuernberg@oracle.com>2011-05-12 04:05:12 +0100
committerTatjana Azundris Nuernberg <tatjana.nuernberg@oracle.com>2011-05-12 04:05:12 +0100
commite0c0bf323bd26c011842c7d97ab7ec5ee4b5d80d (patch)
treec05960ee2cf34663d49c4cbf04a9eb7ee6e3712a
parent99a8398f42270ac106b8b7893b76deb0603d2b70 (diff)
parent9990ab901bbe1a99538d062d7b13c29ad84823a9 (diff)
downloadmariadb-git-e0c0bf323bd26c011842c7d97ab7ec5ee4b5d80d.tar.gz
auto-merge Bug#11762799/Bug#55436
-rw-r--r--mysql-test/r/type_newdecimal.result13
-rw-r--r--mysql-test/t/type_newdecimal.test15
-rw-r--r--sql/field.cc6
-rw-r--r--sql/my_decimal.cc11
-rw-r--r--sql/my_decimal.h3
-rw-r--r--strings/decimal.c5
6 files changed, 42 insertions, 11 deletions
diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result
index 819e41f41c5..c9db73c5f85 100644
--- a/mysql-test/r/type_newdecimal.result
+++ b/mysql-test/r/type_newdecimal.result
@@ -1920,4 +1920,17 @@ SELECT SUM(DISTINCT a) FROM t1;
SUM(DISTINCT a)
0.0000
DROP TABLE t1;
+#
+# Bug#55436: buffer overflow in debug binary of dbug_buff in
+# Field_new_decimal::store_value
+#
+SET SQL_MODE='';
+CREATE TABLE t1(f1 DECIMAL(44,24)) ENGINE=MYISAM;
+INSERT INTO t1 SET f1 = -64878E-85;
+Warnings:
+Note 1265 Data truncated for column 'f1' at row 1
+SELECT f1 FROM t1;
+f1
+0.000000000000000000000000
+DROP TABLE IF EXISTS t1;
End of 5.1 tests
diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test
index bd70e64b1ad..f1eeabbd924 100644
--- a/mysql-test/t/type_newdecimal.test
+++ b/mysql-test/t/type_newdecimal.test
@@ -1519,4 +1519,19 @@ SELECT AVG(DISTINCT a) FROM t1;
SELECT SUM(DISTINCT a) FROM t1;
DROP TABLE t1;
+--echo #
+--echo # Bug#55436: buffer overflow in debug binary of dbug_buff in
+--echo # Field_new_decimal::store_value
+--echo #
+
+# this threw memory warnings on Windows. Also make sure future changes
+# don't change these results, as per usual.
+SET SQL_MODE='';
+CREATE TABLE t1(f1 DECIMAL(44,24)) ENGINE=MYISAM;
+INSERT INTO t1 SET f1 = -64878E-85;
+SELECT f1 FROM t1;
+DROP TABLE IF EXISTS t1;
+
+
+
--echo End of 5.1 tests
diff --git a/sql/field.cc b/sql/field.cc
index 01c4459c06c..0d831aef8b3 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2608,7 +2608,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
DBUG_ENTER("Field_new_decimal::store_value");
#ifndef DBUG_OFF
{
- char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
+ char dbug_buff[DECIMAL_MAX_STR_LENGTH+2];
DBUG_PRINT("enter", ("value: %s", dbug_decimal_as_string(dbug_buff, decimal_value)));
}
#endif
@@ -2623,7 +2623,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
}
#ifndef DBUG_OFF
{
- char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
+ char dbug_buff[DECIMAL_MAX_STR_LENGTH+2];
DBUG_PRINT("info", ("saving with precision %d scale: %d value %s",
(int)precision, (int)dec,
dbug_decimal_as_string(dbug_buff, decimal_value)));
@@ -2692,7 +2692,7 @@ int Field_new_decimal::store(const char *from, uint length,
}
#ifndef DBUG_OFF
- char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
+ char dbug_buff[DECIMAL_MAX_STR_LENGTH+2];
DBUG_PRINT("enter", ("value: %s",
dbug_decimal_as_string(dbug_buff, &decimal_value)));
#endif
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index a5b60739b26..3b5fa81eab9 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -99,10 +99,11 @@ int my_decimal2string(uint mask, const my_decimal *d,
UNSIGNED. Hence the buffer for a ZEROFILLed value is the length
the user requested, plus one for a possible decimal point, plus
one if the user only wanted decimal places, but we force a leading
- zero on them. Because the type is implicitly UNSIGNED, we do not
- need to reserve a character for the sign. For all other cases,
- fixed_prec will be 0, and my_decimal_string_length() will be called
- instead to calculate the required size of the buffer.
+ zero on them, plus one for the '\0' terminator. Because the type
+ is implicitly UNSIGNED, we do not need to reserve a character for
+ the sign. For all other cases, fixed_prec will be 0, and
+ my_decimal_string_length() will be called instead to calculate the
+ required size of the buffer.
*/
int length= (fixed_prec
? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1)
@@ -332,7 +333,7 @@ print_decimal_buff(const my_decimal *dec, const uchar* ptr, int length)
const char *dbug_decimal_as_string(char *buff, const my_decimal *val)
{
- int length= DECIMAL_MAX_STR_LENGTH;
+ int length= DECIMAL_MAX_STR_LENGTH + 1; /* minimum size for buff */
if (!val)
return "NULL";
(void)decimal2string((decimal_t*) val, buff, &length, 0,0,0);
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index e2f5c95dac2..1ff93c9dab3 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -62,7 +62,7 @@ typedef struct st_mysql_time MYSQL_TIME;
/**
maximum length of string representation (number of maximum decimal
- digits + 1 position for sign + 1 position for decimal point)
+ digits + 1 position for sign + 1 position for decimal point, no terminator)
*/
#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2)
@@ -243,6 +243,7 @@ inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
inline
int my_decimal_string_length(const my_decimal *d)
{
+ /* length of string representation including terminating '\0' */
return decimal_string_size(d);
}
diff --git a/strings/decimal.c b/strings/decimal.c
index e081c063033..3b72ddb82c6 100644
--- a/strings/decimal.c
+++ b/strings/decimal.c
@@ -312,8 +312,8 @@ int decimal_actual_fraction(decimal_t *from)
from - value to convert
to - points to buffer where string representation
should be stored
- *to_len - in: size of to buffer
- out: length of the actually written string
+ *to_len - in: size of to buffer (incl. terminating '\0')
+ out: length of the actually written string (excl. '\0')
fixed_precision - 0 if representation can be variable length and
fixed_decimals will not be checked in this case.
Put number as with fixed point position with this
@@ -330,6 +330,7 @@ int decimal2string(decimal_t *from, char *to, int *to_len,
int fixed_precision, int fixed_decimals,
char filler)
{
+ /* {intg_len, frac_len} output widths; {intg, frac} places in input */
int len, intg, frac= from->frac, i, intg_len, frac_len, fill;
/* number digits before decimal point */
int fixed_intg= (fixed_precision ?