New type-based pool allocator code miscompiled due to aliasing issue?

Martin Liška mliska@suse.cz
Wed Jun 17 15:32:00 GMT 2015


On 06/17/2015 01:29 PM, Richard Biener wrote:
> On Wed, Jun 17, 2015 at 1:22 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>> On Wed, Jun 17, 2015 at 11:13:58AM +0200, Martin Jambor wrote:
>>>>>> Do you mean Richard following changes:
>>>>>>
>>>>>> alloc-pool.h (allocate):
>>>>>> ...
>>>>>> +  /* Placement new contructor.  */
>>>>>> +  inline void *operator new (size_t, elt_loc_list *&ptr)
>>>>>> +  {
>>>>>> +    return ptr;
>>>>>> +  }
>>>>>
>>>>> That should be there with including <new>
>>>>>
>>>>>> and e.g. cselib.h:
>>>>>>
>>>>>> struct cselib_val
>>>>>> {
>>>>>>   /* Pool allocation new operator.  */
>>>>>>   inline void *operator new (size_t)
>>>>>>   {
>>>>>>     return pool.allocate ();
>>>>>>   }
>>>>>>
>>>>>>   /* Placement new contructor.  */
>>>>>>   inline void *operator new (size_t, char *&ptr)
>>>>>>   {
>>>>>>     return ptr;
>>>>>>   }
>>>>>
>>>>> Yes, though I wonder whether cselib_val should really have undefined
>>>>> contents after
>>>>> allocating it?  (or does the pool allocator zero the memory?)
>>
>> IMHO if you want to put placement new into allocate, then you probably need
>> two different methods, one that will return you just void * to the
>> allocated memory chunk that you should use
>> inline void *operator new (size_t) { return pool.allocate (); } on,
>> and another method that will use that and additionally invoke a placement
>> new on it and return you the constructed pointer, which you'd use elsewhere.
>> Otherwise you'd construct the object twice...
> 
> Note that in the case of cselib_val a
> 
>   new cselib_val;
> 
> will already invoke the constructor.  I think it's just too much
> (partly) C++-ification here.
> Either all alloc-pool users have to work that way or none.
> 
> Richard.
> 
>>         Jakub

Hello.

You are right that we should call ::new just for classes that have m_ignore_type_size == false.
I've come up with following patch, that I tested slightly:

diff --git a/gcc/alloc-pool.h b/gcc/alloc-pool.h
index 1785df5..7da5f7a 100644
--- a/gcc/alloc-pool.h
+++ b/gcc/alloc-pool.h
@@ -412,8 +412,16 @@ pool_allocator<T>::allocate ()
 #endif
   VALGRIND_DISCARD (VALGRIND_MAKE_MEM_UNDEFINED (header, size));
 
+  T *ptr = (T *)header;
+
   /* Call default constructor.  */
-  return (T *)(header);
+  if (!m_ignore_type_size)
+    {
+      memset (header + sizeof (T), 0, m_extra_size);
+      return ::new (ptr) T;
+    }
+  else
+    return ptr;
 }
 
 /* Puts PTR back on POOL's free list.  */

Would it be suitable?
Martin



More information about the Gcc-patches mailing list