summaryrefslogtreecommitdiff
path: root/sql/item_cmpfunc.cc
diff options
context:
space:
mode:
authorAlexey Kopytov <Alexey.Kopytov@Sun.com>2010-08-25 19:57:53 +0400
committerAlexey Kopytov <Alexey.Kopytov@Sun.com>2010-08-25 19:57:53 +0400
commitdf389d0135d65ae7a05e2265fd54c7172dbb9e47 (patch)
tree292d0e6b8e59f907d31b95a53b5d1b4251630aad /sql/item_cmpfunc.cc
parent593c6db2993b03c120e3210f44eeceed071e0791 (diff)
downloadmariadb-git-df389d0135d65ae7a05e2265fd54c7172dbb9e47.tar.gz
Bug#55077: Assertion failed: width > 0 && to != ((void *)0),
file .\dtoa.c The assertion failure was correct because the 'width' argument of my_gcvt() has the signed integer type, whereas the unsigned value UINT_MAX32 was being passed by the caller (Field_double::val_str()) leading to a negative width in my_gcvt(). The following chain of problems was found by further analysis: 1. The display width for a floating point number is calculated in Field_double::val_str() as either field_length or the maximum possible length of string representation of a floating point number, whichever is greater. Since in the bug's test case field_length is UINT_MAX32, we get the same value as the display width. This does not make any sense because for numeric values field_length only matters for ZEROFILL columns, otherwise it does not make sense to allocate that much memory just to print a number. Field_float::val_str() has a similar problem. 2. Even if the above wasn't the case, we would still get a crash on a slightly different test case when trying to allocate UINT_MAX32 bytes with String::alloc() because the latter does not handle such large input values correctly due to alignment overflows. 3. Even when String::alloc() is fixed to return an error when an alignment overflow occurs, there is still a problem because almost no callers check its return value, and Field_double::val_str() is not an exception (same for Field_float::val_str()). 4. Even if all of the above wasn't the case, creating a Field_double object with UINT_MAX32 as its field_length does not make much sense either, since the .frm code limits it to MAX_FIELD_CHARLENGTH (255) bytes. Such a beast can only be created by create_tmp_field_from_item() from an Item with REAL_RESULT as its result_type() and UINT_MAX32 as its max_length. 5. For the bug's test case, the above condition (REAL_RESULT Item with max_length = UINT_MAX32) was a result of Item_func_if::fix_length_and_dec() "shortcutting" aggregation of argument types when one of the arguments was a constant NULL. In this case, the attributes of the aggregated type were simply copied from the other, non-NULL argument, but max_length was still calculated as per the general, non-shortcut case, by choosing the greatest of argument's max_length, which is obviously not correct. The patch addresses all of the above problems, even though fixing the assertion failure for the particular test case would require only a subset of the above problems to be solved.
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r--sql/item_cmpfunc.cc27
1 files changed, 15 insertions, 12 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 641d3726aca..8c0f22b0947 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2560,27 +2560,30 @@ Item_func_if::fix_length_and_dec()
cached_result_type= arg2_type;
collation.set(args[2]->collation.collation);
cached_field_type= args[2]->field_type();
+ max_length= args[2]->max_length;
+ return;
}
- else if (null2)
+
+ if (null2)
{
cached_result_type= arg1_type;
collation.set(args[1]->collation.collation);
cached_field_type= args[1]->field_type();
+ max_length= args[1]->max_length;
+ return;
+ }
+
+ agg_result_type(&cached_result_type, args + 1, 2);
+ if (cached_result_type == STRING_RESULT)
+ {
+ if (agg_arg_charsets_for_string_result(collation, args + 1, 2))
+ return;
}
else
{
- agg_result_type(&cached_result_type, args+1, 2);
- if (cached_result_type == STRING_RESULT)
- {
- if (agg_arg_charsets_for_string_result(collation, args + 1, 2))
- return;
- }
- else
- {
- collation.set_numeric(); // Number
- }
- cached_field_type= agg_field_type(args + 1, 2);
+ collation.set_numeric(); // Number
}
+ cached_field_type= agg_field_type(args + 1, 2);
uint32 char_length;
if ((cached_result_type == DECIMAL_RESULT )