summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2021-10-27 10:50:15 +0400
committerAlexander Barkov <bar@mariadb.com>2021-10-27 10:50:15 +0400
commit2ed148c8d7b0133ecd17377587facadc7e76e9e8 (patch)
treeba0d743fa1d29bef3cb32c6ebfcf4f165f43da91
parent4b8340d89990a8105561888059ec6e3543bed41d (diff)
downloadmariadb-git-2ed148c8d7b0133ecd17377587facadc7e76e9e8.tar.gz
MDEV-25402 Assertion `!str || str != Ptr' failed in String::copy
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.
-rw-r--r--mysql-test/r/ctype_utf32_uca.result22
-rw-r--r--mysql-test/t/ctype_utf32_uca.test26
-rw-r--r--sql/sql_string.cc2
3 files changed, 49 insertions, 1 deletions
diff --git a/mysql-test/r/ctype_utf32_uca.result b/mysql-test/r/ctype_utf32_uca.result
index da23fa30ab4..46ca6e7baee 100644
--- a/mysql-test/r/ctype_utf32_uca.result
+++ b/mysql-test/r/ctype_utf32_uca.result
@@ -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
#
diff --git a/mysql-test/t/ctype_utf32_uca.test b/mysql-test/t/ctype_utf32_uca.test
index 334d8fd1d48..2969480b0ef 100644
--- a/mysql-test/t/ctype_utf32_uca.test
+++ b/mysql-test/t/ctype_utf32_uca.test
@@ -266,5 +266,31 @@ 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 #
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 4e0c7aea84b..ff6b2163630 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -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))
{