summaryrefslogtreecommitdiff
path: root/libmysql
diff options
context:
space:
mode:
authorunknown <gkodinov/kgeorge@magare.gmz>2007-06-22 15:34:28 +0300
committerunknown <gkodinov/kgeorge@magare.gmz>2007-06-22 15:34:28 +0300
commit0200ffc78c8a037625aa914f3381e92bfb95d0c2 (patch)
tree489db1dd8ff5294126205a9d66cd22a190c7c023 /libmysql
parent716d8653968df03efdd277285b61c2c182ddc1b7 (diff)
downloadmariadb-git-0200ffc78c8a037625aa914f3381e92bfb95d0c2.tar.gz
Bug #27383: Crash in test "mysql_client_test"
The C optimizer may decide that data access operations through pointer of different type are not related to the original data (strict aliasing). This is what happens in fetch_long_with_conversion(), when called as part of mysql_stmt_fetch() : it tries to check for truncation errors by first storing float (and other types of data) into a char * buffer and then accesses them through a float pointer. This is done to prevent the effects of excess precision when using FPU registers. However the doublestore() macro converts a double pointer to an union pointer. This violates the strict aliasing rule. Fixed by making the intermediary variables volatile ( to not re-introduce the excess precision bug) and using the intermediary value instead of the char * buffer. Note that there can be loss of precision for both signed and unsigned 64 bit integers converted to double and back, so the check must stay there (even for compatibility reasons). Based on the excellent analysis in bug 28400. libmysql/libmysql.c: Bug #27383: avoid pointer aliasing problems while not re-violating the Intel FPU gcc bug.
Diffstat (limited to 'libmysql')
-rw-r--r--libmysql/libmysql.c27
1 files changed, 16 insertions, 11 deletions
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index e426d2c549e..cb60fb20863 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -3663,33 +3663,38 @@ static void fetch_long_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
case MYSQL_TYPE_FLOAT:
{
/*
- We need to store data in the buffer before the truncation check to
+ We need to mark the local variable volatile to
workaround Intel FPU executive precision feature.
(See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 for details)
- AFAIU it does not guarantee to work.
*/
- float data;
+ volatile float data;
if (is_unsigned)
+ {
data= (float) ulonglong2double(value);
+ *param->error= ((ulonglong) value) != ((ulonglong) data);
+ }
else
- data= (float) value;
+ {
+ data= (float)value;
+ *param->error= value != ((longlong) data);
+ }
floatstore(buffer, data);
- *param->error= is_unsigned ?
- ((ulonglong) value) != ((ulonglong) (*(float*) buffer)) :
- ((longlong) value) != ((longlong) (*(float*) buffer));
break;
}
case MYSQL_TYPE_DOUBLE:
{
- double data;
+ volatile double data;
if (is_unsigned)
+ {
data= ulonglong2double(value);
+ *param->error= ((ulonglong) value) != ((ulonglong) data);
+ }
else
+ {
data= (double)value;
+ *param->error= value != ((longlong) data);
+ }
doublestore(buffer, data);
- *param->error= is_unsigned ?
- ((ulonglong) value) != ((ulonglong) (*(double*) buffer)) :
- ((longlong) value) != ((longlong) (*(double*) buffer));
break;
}
case MYSQL_TYPE_TIME: