Skip to content

Commit

Permalink
MDEV-25402 Assertion `!str || str != Ptr' failed in String::copy
Browse files Browse the repository at this point in the history
The assert inside String::copy() prevents copying from from "str"
if its own String::Ptr also points to the same memory.

The idea of the assert is that copy() performs memory reallocation,
and this reallocation can free (and thus invalidate) the memory pointed by Ptr,
which can lead to further copying from a freed memory.

The assert was incomplete: copy() can free the memory pointed by its Ptr
only if String::alloced is true!

If the String is not alloced, it is still safe to copy even from
the location pointed by Ptr.

This scenario demonstrates a safe copy():
  const char *tmp= "123";
  String str1(tmp, 3);
  String str2(tmp, 3);
  // This statement is safe:
  str2.copy(str1->ptr(), str1->length(), str1->charset(), cs_to, &errors);

Inside the copy() the parameter "str" is equal to String::Ptr in this example.
But it's still ok to reallocate the memory for str2, because str2
was a constant before the copy() call. Thus reallocation does not
make the memory pointed by str1->ptr() invalid.

Adjusting the assert condition to allow copying for constant strings.
  • Loading branch information
abarkov committed Oct 27, 2021
1 parent 4b8340d commit 2ed148c
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 1 deletion.
22 changes: 22 additions & 0 deletions mysql-test/r/ctype_utf32_uca.result
Original file line number Diff line number Diff line change
Expand Up @@ -7919,5 +7919,27 @@ a b
DROP TABLE t1;
SET NAMES utf8;
#
# MDEV-25402 Assertion `!str || str != Ptr' failed in String::copy
#
SET @c:="SET SESSION collation_connection=utf32_spanish_ci";
PREPARE s FROM @c;
EXECUTE s;
CREATE PROCEDURE p (IN i INT) EXECUTE s;
SET SESSION character_set_connection=latin1;
SET @c:="SET @b=get_format(DATE,'EUR')";
PREPARE s FROM @c;
EXECUTE s;
CALL p (@a);
DEALLOCATE PREPARE s;
DROP PROCEDURE p;
SET NAMES utf8;
SET @c:="SET @b=get_format(DATE,'EUR')";
PREPARE s FROM @c;
EXECUTE s;
SET collation_connection=utf32_spanish_ci;
EXECUTE s;
DEALLOCATE PREPARE s;
SET NAMES utf8;
#
# End of 10.2 tests
#
26 changes: 26 additions & 0 deletions mysql-test/t/ctype_utf32_uca.test
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,32 @@ SET NAMES utf8, collation_connection=utf32_unicode_520_nopad_ci;
SET NAMES utf8;


--echo #
--echo # MDEV-25402 Assertion `!str || str != Ptr' failed in String::copy
--echo #

SET @c:="SET SESSION collation_connection=utf32_spanish_ci";
PREPARE s FROM @c;
EXECUTE s;
CREATE PROCEDURE p (IN i INT) EXECUTE s;
SET SESSION character_set_connection=latin1;
SET @c:="SET @b=get_format(DATE,'EUR')";
PREPARE s FROM @c;
EXECUTE s;
CALL p (@a);
DEALLOCATE PREPARE s;
DROP PROCEDURE p;

SET NAMES utf8;
SET @c:="SET @b=get_format(DATE,'EUR')";
PREPARE s FROM @c;
EXECUTE s;
SET collation_connection=utf32_spanish_ci;
EXECUTE s;
DEALLOCATE PREPARE s;
SET NAMES utf8;


--echo #
--echo # End of 10.2 tests
--echo #
2 changes: 1 addition & 1 deletion sql/sql_string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ bool String::copy(const char *str, uint32 arg_length,
{
uint32 offset;

DBUG_ASSERT(!str || str != Ptr);
DBUG_ASSERT(!str || str != Ptr || !alloced);

if (!needs_conversion(arg_length, from_cs, to_cs, &offset))
{
Expand Down

0 comments on commit 2ed148c

Please sign in to comment.