Boost C++ Libraries: Ticket #2200: Bad memory management in algorithm::is_any_of https://svn.boost.org/trac10/ticket/2200 <p> The is_any_of predicate has been modified to use either a fixed buffer or dynamic memory allocation, depending on its size. There are two major problems when it uses dynamic memory allocation. See the code in boost_1_36_0\boost\algorithm\string\detail\classification.hpp. </p> <blockquote> <p> 1) It allocates memory with the command </p> <pre class="wiki"> m_Storage.m_dynSet=new set_value_type[m_Size]; </pre><blockquote> <p> but it deallocates with the command </p> <pre class="wiki"> delete m_Storage.m_dynSet; </pre></blockquote> <p> This should be </p> <pre class="wiki"> delete[] m_Storage.m_dynSet; </pre><p> or else we will have undefined behavior. </p> </blockquote> <blockquote> <p> 2) The first line of its assignment operator is </p> <pre class="wiki"> m_Storage.m_dynSet=0; </pre><blockquote> <p> This means that if m_dynSet has had memory allocated that memory will leak. Also, this means that it is unsafe under self-assignment. </p> </blockquote> </blockquote> <p> Here is some untested code that should help with the assignment problem: </p> <pre class="wiki">is_any_ofF&amp; operator=(const is_any_ofF&amp; Other) { const set_value_type* SrcStorage=0; set_value_type* DestStorage=0; if (Other.m_Size &lt;= FIXED_STORAGE_SIZE) { SrcStorage = &amp;Other.m_Storage.m_fixSet[0]; if (m_Size &gt; FIXED_STORAGE_SIZE) { m_Storage.m_dynSet = new set_value_typ[Other.m_Size]; DestStorage = m_Storage.m_dynSet; } else { DestStorage = &amp;m_Storage.m_fixSet[0]; } } else { SrcStorage = Other.m_Storage.m_dynSet; if (m_Size&lt;= FIXED_STORAGE_SIZE) { m_Storage.m_dynSet = new set_value_type[Other.m_Size]; } else if (m_Size &lt;= Other.m_Size) { //We already have enough space allocated, so no new allocation required } else { //Use temporary var for strong exception safety set_value_type *temp = new set_value_type[Other.m_Size]; delete[] m_Storage.m_dynSet; m_Storage.m_dynSet = temp; } DestStorage = m_Storage.m_dynSet; } m_Size = Other.m_Size; ::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size); return *this; } </pre> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/2200 Trac 1.4.3 Marshall Clow Mon, 18 Aug 2008 17:13:58 GMT component, milestone changed; owner set https://svn.boost.org/trac10/ticket/2200#comment:1 https://svn.boost.org/trac10/ticket/2200#comment:1 <ul> <li><strong>owner</strong> set to <span class="trac-author">Pavol Droba</span> </li> <li><strong>component</strong> <span class="trac-field-old">None</span> → <span class="trac-field-new">string_algo</span> </li> <li><strong>milestone</strong> <span class="trac-field-old">Boost 1.36.0</span> → <span class="trac-field-new">To Be Determined</span> </li> </ul> Ticket Pavol Droba Mon, 18 Aug 2008 18:34:44 GMT status changed; resolution set https://svn.boost.org/trac10/ticket/2200#comment:2 https://svn.boost.org/trac10/ticket/2200#comment:2 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> <p> Thanks for spotting that out. I have just commited a fix into the trunk. </p> Ticket Joe Gottman <jgottman@…> Thu, 21 Aug 2008 11:46:42 GMT <link>https://svn.boost.org/trac10/ticket/2200#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2200#comment:3</guid> <description> <blockquote> <p> This doesn't fix the self-assignment problem. If we have code like </p> <pre class="wiki"> is_any_of&lt;char&gt; foo("abcdefghijklmnopqrstuvwxyz"); foo = foo; </pre></blockquote> <blockquote> <p> then the operator= as currently written will delete this-&gt;m_Storage.m_dynSet (which is the same thing as Other.m_Storage.m_dynSet), and replace it with garbage. There are two possible ways to fix this. The first is to put the following code at the beginning of operator= </p> <pre class="wiki"> if (this == &amp;Other) return *this; </pre></blockquote> <blockquote> <p> The second is to do the following: If *this and Other both allocate memory, check whether Other-&gt;m_Size is less than or equal to this-&gt;m_Size. If it is, then we don't have to reallocate this-&gt;m_Storage.m_dynSet. It will already have enough space allocated to hold the string from Other. It might have more space allocated than necessary, but that is no big deal. This saves us an unnecessary reallocation in some cases, including the self-assignment case. </p> </blockquote> </description> <category>Ticket</category> </item> <item> <dc:creator>Pavol Droba</dc:creator> <pubDate>Thu, 21 Aug 2008 14:50:04 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/2200#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/2200#comment:4</guid> <description> <p> Ok, I have used the combination of both. Self assignment case is tested at the beginning and the new space is not allocate if <code>newsize &lt;= size &lt; 2*newsize.</code> </p> </description> <category>Ticket</category> </item> </channel> </rss>