From: Martin Hansson Date: January 13 2011 8:08am Subject: bzr commit into mysql-5.5 branch (martin.hansson:3233) Bug#58165 List-Archive: http://lists.mysql.com/commits/128586 X-Bug: 58165 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1057025819==" --===============1057025819== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///data0/martin/bzrroot/bug58165/5.5/ based on revid:bjorn.munch@stripped 3233 Martin Hansson 2011-01-13 [merge] Merge of fix for Bug#58165. modified: mysql-test/r/func_str.result mysql-test/t/func_str.test sql/item_strfunc.cc sql/item_strfunc.h sql/sql_string.cc sql/sql_string.h === modified file 'mysql-test/r/func_str.result' --- a/mysql-test/r/func_str.result 2010-12-14 16:26:18 +0000 +++ b/mysql-test/r/func_str.result 2011-01-13 08:07:21 +0000 @@ -2615,6 +2615,22 @@ CONVERT(('' IN (REVERSE(CAST(('') AS DEC 1 Warnings: Warning 1292 Truncated incorrect DECIMAL value: '' +# +# Bug#58165: "my_empty_string" gets modified and causes LOAD DATA to fail +# and other crashes +# +CREATE TABLE t1 ( a TEXT ); +SELECT 'aaaaaaaaaaaaaa' INTO OUTFILE 'bug58165.txt'; +SELECT insert( substring_index( 'a', 'a', 'b' ), 1, 0, 'x' ); +insert( substring_index( 'a', 'a', 'b' ), 1, 0, 'x' ) +x +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'b' +LOAD DATA INFILE 'bug58165.txt' INTO TABLE t1; +SELECT * FROM t1; +a +aaaaaaaaaaaaaa +DROP TABLE t1; End of 5.1 tests Start of 5.4 tests SELECT format(12345678901234567890.123, 3); === modified file 'mysql-test/t/func_str.test' --- a/mysql-test/t/func_str.test 2010-12-14 16:26:18 +0000 +++ b/mysql-test/t/func_str.test 2011-01-13 08:07:21 +0000 @@ -1370,6 +1370,17 @@ DROP TABLE t1; SELECT '1' IN ('1', SUBSTRING(-9223372036854775809, 1)); SELECT CONVERT(('' IN (REVERSE(CAST(('') AS DECIMAL)), '')), CHAR(3)); +--echo # +--echo # Bug#58165: "my_empty_string" gets modified and causes LOAD DATA to fail +--echo # and other crashes +--echo # +CREATE TABLE t1 ( a TEXT ); +SELECT 'aaaaaaaaaaaaaa' INTO OUTFILE 'bug58165.txt'; +SELECT insert( substring_index( 'a', 'a', 'b' ), 1, 0, 'x' ); +LOAD DATA INFILE 'bug58165.txt' INTO TABLE t1; +SELECT * FROM t1; +DROP TABLE t1; + --echo End of 5.1 tests --echo Start of 5.4 tests === modified file 'sql/item_strfunc.cc' --- a/sql/item_strfunc.cc 2010-12-17 11:11:34 +0000 +++ b/sql/item_strfunc.cc 2011-01-13 08:07:21 +0000 @@ -56,6 +56,9 @@ C_MODE_START #include "../mysys/my_static.h" // For soundex_map C_MODE_END +/** + @todo Remove this. It is not safe to use a shared String object. + */ String my_empty_string("",default_charset_info); /* @@ -642,7 +645,7 @@ String *Item_func_des_encrypt::val_str(S if ((null_value= args[0]->null_value)) return 0; // ENCRYPT(NULL) == NULL if ((res_length=res->length()) == 0) - return &my_empty_string; + return make_empty_result(); if (arg_count == 1) { /* Protect against someone doing FLUSH DES_KEY_FILE */ @@ -832,7 +835,7 @@ String *Item_func_concat_ws::val_str(Str } if (i == arg_count) - return &my_empty_string; + return make_empty_result(); for (i++; i < arg_count ; i++) { @@ -978,7 +981,7 @@ String *Item_func_reverse::val_str(Strin return 0; /* An empty string is a special case as the string pointer may be null */ if (!res->length()) - return &my_empty_string; + return make_empty_result(); if (tmp_value.alloced_length() < res->length() && tmp_value.realloc(res->length())) { @@ -1311,8 +1314,7 @@ String *Item_func_left::val_str(String * /* if "unsigned_flag" is set, we have a *huge* positive number. */ if ((length <= 0) && (!args[1]->unsigned_flag)) - return &my_empty_string; - + return make_empty_result(); if ((res->length() <= (ulonglong) length) || (res->length() <= (char_pos= res->charpos((int) length)))) return res; @@ -1357,7 +1359,7 @@ String *Item_func_right::val_str(String /* if "unsigned_flag" is set, we have a *huge* positive number. */ if ((length <= 0) && (!args[1]->unsigned_flag)) - return &my_empty_string; /* purecov: inspected */ + return make_empty_result(); /* purecov: inspected */ if (res->length() <= (ulonglong) length) return res; /* purecov: inspected */ @@ -1397,7 +1399,7 @@ String *Item_func_substr::val_str(String /* Negative or zero length, will return empty string. */ if ((arg_count == 3) && (length <= 0) && (length == 0 || !args[2]->unsigned_flag)) - return &my_empty_string; + return make_empty_result(); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Set here so that rest of code sees out-of-bound value as such. */ @@ -1408,12 +1410,12 @@ String *Item_func_substr::val_str(String /* Assumes that the maximum length of a String is < INT_MAX32. */ if ((!args[1]->unsigned_flag && (start < INT_MIN32 || start > INT_MAX32)) || (args[1]->unsigned_flag && ((ulonglong) start > INT_MAX32))) - return &my_empty_string; + return make_empty_result(); start= ((start < 0) ? res->numchars() + start : start - 1); start= res->charpos((int) start); if ((start < 0) || ((uint) start + 1 > res->length())) - return &my_empty_string; + return make_empty_result(); length= res->charpos((int) length, (uint32) start); tmp_length= res->length() - start; @@ -1476,7 +1478,7 @@ String *Item_func_substr_index::val_str( null_value=0; uint delimiter_length= delimiter->length(); if (!res->length() || !delimiter_length || !count) - return &my_empty_string; // Wrong parameters + return make_empty_result(); // Wrong parameters res->set_charset(collation.collation); @@ -1826,7 +1828,7 @@ String *Item_func_password::val_str_asci if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return &my_empty_string; + return make_empty_result(); my_make_scrambled_password(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, &my_charset_latin1); return str; @@ -1850,7 +1852,7 @@ String *Item_func_old_password::val_str_ if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return &my_empty_string; + return make_empty_result(); my_make_scrambled_password_323(tmp_value, res->ptr(), res->length()); str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, &my_charset_latin1); return str; @@ -1878,8 +1880,7 @@ String *Item_func_encrypt::val_str(Strin if ((null_value=args[0]->null_value)) return 0; if (res->length() == 0) - return &my_empty_string; - + return make_empty_result(); if (arg_count == 1) { // generate random salt time_t timestamp=current_thd->query_start(); @@ -2141,7 +2142,7 @@ String *Item_func_soundex::val_str(Strin for ( ; ; ) /* Skip pre-space */ { if ((rc= cs->cset->mb_wc(cs, &wc, (uchar*) from, (uchar*) end)) <= 0) - return &my_empty_string; /* EOL or invalid byte sequence */ + return make_empty_result(); /* EOL or invalid byte sequence */ if (rc == 1 && cs->ctype) { @@ -2166,7 +2167,7 @@ String *Item_func_soundex::val_str(Strin { /* Extra safety - should not really happen */ DBUG_ASSERT(false); - return &my_empty_string; + return make_empty_result(); } to+= rc; break; @@ -2507,7 +2508,7 @@ String *Item_func_make_set::val_str(Stri else { if (tmp_str.copy(*res)) // Don't use 'str' - return &my_empty_string; + return make_empty_result(); result= &tmp_str; } } @@ -2517,11 +2518,11 @@ String *Item_func_make_set::val_str(Stri { // Copy data to tmp_str if (tmp_str.alloc(result->length()+res->length()+1) || tmp_str.copy(*result)) - return &my_empty_string; + return make_empty_result(); result= &tmp_str; } if (tmp_str.append(STRING_WITH_LEN(","), &my_charset_bin) || tmp_str.append(*res)) - return &my_empty_string; + return make_empty_result(); } } } @@ -2666,7 +2667,7 @@ String *Item_func_repeat::val_str(String null_value= 0; if (count <= 0 && (count == 0 || !args[1]->unsigned_flag)) - return &my_empty_string; + return make_empty_result(); /* Assumes that the maximum length of a String is < INT_MAX32. */ /* Bounds check on count: If this is triggered, we will error. */ @@ -2948,7 +2949,7 @@ String *Item_func_conv::val_str(String * ptr= longlong2str(dec, ans, to_base); if (str->copy(ans, (uint32) (ptr-ans), default_charset())) - return &my_empty_string; + return make_empty_result(); return str; } @@ -3115,7 +3116,7 @@ String *Item_func_hex::val_str_ascii(Str return 0; ptr= longlong2str(dec,ans,16); if (str->copy(ans,(uint32) (ptr-ans), &my_charset_numeric)) - return &my_empty_string; // End of memory + return make_empty_result(); // End of memory return str; } === modified file 'sql/item_strfunc.h' --- a/sql/item_strfunc.h 2010-11-26 10:44:39 +0000 +++ b/sql/item_strfunc.h 2011-01-13 08:07:21 +0000 @@ -27,6 +27,16 @@ class MY_LOCALE; class Item_str_func :public Item_func { +protected: + /** + Sets the result value of the function an empty string, using the current + character set. No memory is allocated. + @retval A pointer to the str_value member. + */ + String *make_empty_result() { + str_value.set("", 0, collation.collation); + return &str_value; + } public: Item_str_func() :Item_func() { decimals=NOT_FIXED_DEC; } Item_str_func(Item *a) :Item_func(a) {decimals=NOT_FIXED_DEC; } === modified file 'sql/sql_string.cc' --- a/sql/sql_string.cc 2010-08-25 15:57:53 +0000 +++ b/sql/sql_string.cc 2011-01-13 08:07:21 +0000 @@ -51,11 +51,33 @@ bool String::real_alloc(uint32 length) } -/* -** Check that string is big enough. Set string[alloc_length] to 0 -** (for C functions) -*/ +/** + Allocates a new buffer on the heap for this String. + + - If the String's internal buffer is privately owned and heap allocated, + one of the following is performed. + + - If the requested length is greater than what fits in the buffer, a new + buffer is allocated, data moved and the old buffer freed. + + - If the requested length is less or equal to what fits in the buffer, a + null character is inserted at the appropriate position. + - If the String does not keep a private buffer on the heap, such a buffer + will be allocated and the string copied accoring to its length, as found + in String::length(). + + For C compatibility, the new string buffer is null terminated. + + @param alloc_length The requested string size in characters, excluding any + null terminator. + + @retval false Either the copy operation is complete or, if the size of the + new buffer is smaller than the currently allocated buffer (if one exists), + no allocation occured. + + @retval true An error occured when attempting to allocate memory. +*/ bool String::realloc(uint32 alloc_length) { uint32 len=ALIGN_SIZE(alloc_length+1); @@ -128,6 +150,17 @@ bool String::copy() return FALSE; } +/** + Copies the internal buffer from str. If this String has a private heap + allocated buffer where new data does not fit, a new buffer is allocated + before copying and the old buffer freed. Character set information is also + copied. + + @param str The string whose internal buffer is to be copied. + + @retval false Success. + @retval true Memory allocation failed. +*/ bool String::copy(const String &str) { if (alloc(str.str_length)) === modified file 'sql/sql_string.h' --- a/sql/sql_string.h 2010-10-19 22:51:34 +0000 +++ b/sql/sql_string.h 2011-01-13 08:07:21 +0000 @@ -148,6 +148,16 @@ public: Alloced_length=0; str_charset=str.str_charset; } + + + /** + Points the internal buffer to the supplied one. The old buffer is freed. + @param str Pointer to the new buffer. + @param arg_length Length of the new buffer in characters, excluding any + null character. + @param cs Character set to use for interpreting string data. + @note The new buffer will not be null terminated. + */ inline void set(char *str,uint32 arg_length, CHARSET_INFO *cs) { free(); --===============1057025819== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/martin.hansson@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: martin.hansson@stripped\ # bu92czxpaw9nht9k # target_branch: file:///data0/martin/bzrroot/bug58165/5.5/ # testament_sha1: 6d4476a02021cd87d46c44af99ce5e28afcce08e # timestamp: 2011-01-13 09:08:12 +0100 # source_branch: file:///data0/martin/bzrroot/bug58165/5.1/ # base_revision_id: bjorn.munch@stripped\ # 3zw6jvo3jywfqsva # # Begin bundle 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 3D9i7g== --===============1057025819==--