Bug #65562 String::shrink should be a no-op when alloced=0
Submitted: 7 Jun 2012 17:44 Modified: 22 Aug 2012 13:48
Reporter: Mark Callaghan Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Data Types Severity:S3 (Non-critical)
Version:5.1.52 OS:Any
Assigned to: Tor Didriksen CPU Architecture:Any

[7 Jun 2012 17:44] Mark Callaghan
Description:
I think the problem is still in trunk. This is an accident waiting to happen -- current code can't trigger a problem but if you use the fix for http://bugs.mysql.com/bug.php?id=64353, then you will hit the problem.

String doesn't own the memory referenced by Ptr when alloced=0, it should not free it. But shrink() can free it in the call to my_realloc. The call stack to the accident (double-free) is:
      String::shrink - called because my_b_read call fails
      String::append(IO_CACHE* file, uint32 arg_length)
      Log_event::read_log_event
    In the call stack above the my_b_read call fails because the end of the binlog
    is corrupt on crash recovery. Newer versions of MySQL truncate the end of the
    binlog when it is corrupt after a crash.
    
    An earlier change by me to add rpl_event_buffer_size makes this possible because
    with that change, the instance of String named "packet" in mysql_binlog_send
    provides a buffer to "packet", thus "packet" doesn't own the buffer. But in the
    call stack above it will attempt to free it.

How to repeat:
see above

Suggested fix:
diff --git a/sql/sql_string.h b/sql/sql_string.h
index fd644cb..0d95343 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -212,6 +212,15 @@ public:
   bool realloc(uint32 arg_length);
   inline void shrink(uint32 arg_length)                // Shrink buffer
   {
+    if (!alloced)
+    {
+      /*
+        Either the buffer is NULL or this class doesn't own the
+        buffer memory and cannot shrink it.
+      */
+      return;
+    }
+

It wouldn't hurt to add a few comments to sql_string.h. It is really unkind to write base classes that many people will try to use and then have no comments.
[7 Jun 2012 19:40] Guilhem Bichot
Confirmed.
   char foo[3];
   foo[0]=foo[1]=foo[2]=0;
   String foos(foo, 3, &my_charset_bin);
   foos.shrink(1);
crashes.
[22 Aug 2012 13:48] Paul DuBois
Fixed in 5.1.66, 5.5.28, 5.6.7, 5.7.0.

Code cleanup. No user-visible cases. No changelog entry needed.