Bug #32297 sql_string String() copy constructor fails to copy allocated memory
Submitted: 12 Nov 2007 21:54 Modified: 13 Nov 2007 16:05
Reporter: Bill Mitchell Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version:5.1 OS:Any
Assigned to: CPU Architecture:Any
Tags: Contribution

[12 Nov 2007 21:54] Bill Mitchell
Description:
In writing a storage engine with the 5.1.22-rc version, I tried using the String class defined in sql_string.h to return an object from a called method to the caller.  This code fails as a result of heap corruption.  The essential problem is that the copy constructor and the assignment operator fail to make a copy of the string owned by the source object when that string is in allocated memory.  Of course, the copy constructor and assignment operator are frequently used in C++ as shown in the code fragment below to return an object itself from a called function/method to the caller.  When the String copy constructor or assignment operator is passed a source object that has allocated the string memory, they need to allocate a new cell and place a pointer to that cell in the created/assigned object.  Otherwise the new String object points to a piece of memory that is immediately deallocated at the end of the copy or assignment operation.  

Obviously a workaround is to point only to memory allocated with thd_alloc, so it is not owned by the source String object.  

How to repeat:
A sample code fragment looks something like this:  

static String computeFilename () {
    String s(10);
    s.append("xyzzy");
    return s;
}

...
    String y = computeFilename();
...

Suggested fix:
The original code of the Copy constructor:
  String(const String &str)
  { 
    Ptr=str.Ptr ; str_length=str.str_length ;
    Alloced_length=str.Alloced_length; alloced=0; 
    str_charset=str.str_charset;
  }
should be replaced with:
  String(const String &str)
  { 
    alloced=0;
    str_length=str.str_length ;
    if (str.alloced && str.str_length) {
      Ptr=0;
      Alloced_length=0;
      (void)copy(str.Ptr,str.str_length,str.str_charset);
    } else {
      Ptr=str.Ptr; 
      Alloced_length=str.Alloced_length; 
      str_charset=str.str_charset;
    }
  }

Similarly, the original code of the assignment operator:
  inline String& operator = (const String &s)
  {
    if (&s != this)
    {
      /*
        It is forbidden to do assignments like 
        some_string = substring_of_that_string
       */
      DBUG_ASSERT(!s.uses_buffer_owned_by(this));
      free();
      Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length;
      alloced=0;
    }
    return *this;
  }
should be replaced with this:
  inline String& operator = (const String &s)
  {
    if (&s != this)
    {
      /*
        It is forbidden to do assignments like 
        some_string = substring_of_that_string
       */
      DBUG_ASSERT(!s.uses_buffer_owned_by(this));
      free();
      alloced=0;
      str_length=s.str_length;
      if (s.alloced && s.str_length) {
        Ptr=0;
        Alloced_length=0;
        (void)copy(s.Ptr,s.str_length,s.str_charset);
      } else {
        Ptr=s.Ptr; 
        Alloced_length=s.Alloced_length; 
        str_charset=s.str_charset;
      }
    }
    return *this;
  }

Of course, a more sophisticated solution could be implemented that involved keeping the strings in reference counted memory, so that the copy/assignment operators could point to the same memory and increment the use count, and the free() operator would decrement the use count and release the memory only when the count reaches zero.  The quick fix above has the anomalous behavior of returning a String pointing to zero if the memory allocation in copy() fails.
[13 Nov 2007 16:05] MySQL Verification Team
Thank you for the bug report. I have discussed this issue with 2 developers
and the conclusion is would be an unexpected behavior of the current implementation, what I suggest you is to use a more appropriate forum to
discuss this like the Internal MySQL list: http://lists.mysql.com/#internals

Internals
    A list for people who work on the MySQL code. On this list one can also discuss MySQL development and post patches.

Thanks in advance.