From: Martin Hansson Date: December 30 2010 1:00pm Subject: bzr commit into mysql-trunk-bugfixing branch (martin.hansson:3475) Bug#58165 List-Archive: http://lists.mysql.com/commits/127717 X-Bug: 58165 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0399580265==" --===============0399580265== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///data0/martin/bzrroot/bug58165/t-bf/ based on revid:dao-gang.qu@stripped 3475 Martin Hansson 2010-12-30 [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:29:15 +0000 +++ b/mysql-test/r/func_str.result 2010-12-30 12:59:51 +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:29:15 +0000 +++ b/mysql-test/t/func_str.test 2010-12-30 12:59:51 +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-20 10:28:06 +0000 +++ b/sql/item_strfunc.cc 2010-12-30 12:59:51 +0000 @@ -57,6 +57,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); /* @@ -739,7 +742,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 */ @@ -929,7 +932,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++) { @@ -1075,7 +1078,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())) { @@ -1408,7 +1411,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)))) @@ -1454,7 +1457,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 */ @@ -1494,7 +1497,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. */ @@ -1505,12 +1508,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; @@ -1573,7 +1576,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); @@ -1923,7 +1926,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; @@ -1947,7 +1950,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; @@ -1975,7 +1978,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 @@ -2238,7 +2241,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) { @@ -2263,7 +2266,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; @@ -2604,7 +2607,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; } } @@ -2614,11 +2617,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(); } } } @@ -2763,7 +2766,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. */ @@ -3045,7 +3048,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; } @@ -3264,7 +3267,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-12-02 13:44:21 +0000 +++ b/sql/item_strfunc.h 2010-12-30 12:59:51 +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-12-14 13:26:35 +0000 +++ b/sql/sql_string.cc 2010-12-30 12:59:51 +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-27 14:46:44 +0000 +++ b/sql/sql_string.h 2010-12-30 12:59:51 +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(); --===============0399580265== 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\ # hxjrjjsqqa2svt84 # target_branch: file:///data0/martin/bzrroot/bug58165/t-bf/ # testament_sha1: 3da740c07459732ee47a295061aeed479d5d791f # timestamp: 2010-12-30 14:00:26 +0100 # source_branch: file:///data0/martin/bzrroot/bug58165/5.5bt/ # base_revision_id: dao-gang.qu@stripped\ # 6jamezb1vubx5t3r # # Begin bundle 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 xZ1oOgR7H/xdyRThQkD9rVKM --===============0399580265==--