diff mbox

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

Message ID 557FEBC9.8080002@suse.cz
State New
Headers show

Commit Message

Martin Liška June 16, 2015, 9:26 a.m. UTC
On 06/15/2015 07:31 PM, Marc Glisse wrote:
> On Mon, 15 Jun 2015, Martin Liška wrote:
> 
>> Ah, I overlooked that it's not a placement new, but just static casting.
>> Anyway, if I added:
>>
>> cselib_val () {}
>>
>> to struct cselib_val and changed the cast to placement new:
>>  char *ptr = (char *) header;
>>  return new (ptr) T ();
>>
>> I got following compilation error:
>>
>> In file included from ../../gcc/alias.c:46:0:
>> ../../gcc/alloc-pool.h: In instantiation of ‘T* pool_allocator<T>::allocate() [with T = cselib_val]’:
>> ../../gcc/cselib.h:51:27:   required from here
>> ../../gcc/alloc-pool.h:416:23: error: no matching function for call to ‘cselib_val::operator new(sizetype, char*&)’
>>   return new (ptr) T ();
>>                       ^
>> In file included from ../../gcc/alias.c:47:0:
>> ../../gcc/cselib.h:49:16: note: candidate: static void* cselib_val::operator new(size_t)
>>   inline void *operator new (size_t)
>>                ^
>> ../../gcc/cselib.h:49:16: note:   candidate expects 1 argument, 2 provided
> 
> #include <new>
> 

Hi.

<new> header file is not missing (explicit addition of the file does not help).
Feel free to play with following patch which should fix cselib.h compilation error.

Thanks,
Martin

Comments

Richard Biener June 16, 2015, 1:17 p.m. UTC | #1
On Tue, Jun 16, 2015 at 11:26 AM, Martin Liška <mliska@suse.cz> wrote:
> On 06/15/2015 07:31 PM, Marc Glisse wrote:
>> On Mon, 15 Jun 2015, Martin Liška wrote:
>>
>>> Ah, I overlooked that it's not a placement new, but just static casting.
>>> Anyway, if I added:
>>>
>>> cselib_val () {}
>>>
>>> to struct cselib_val and changed the cast to placement new:
>>>  char *ptr = (char *) header;
>>>  return new (ptr) T ();
>>>
>>> I got following compilation error:
>>>
>>> In file included from ../../gcc/alias.c:46:0:
>>> ../../gcc/alloc-pool.h: In instantiation of ‘T* pool_allocator<T>::allocate() [with T = cselib_val]’:
>>> ../../gcc/cselib.h:51:27:   required from here
>>> ../../gcc/alloc-pool.h:416:23: error: no matching function for call to ‘cselib_val::operator new(sizetype, char*&)’
>>>   return new (ptr) T ();
>>>                       ^
>>> In file included from ../../gcc/alias.c:47:0:
>>> ../../gcc/cselib.h:49:16: note: candidate: static void* cselib_val::operator new(size_t)
>>>   inline void *operator new (size_t)
>>>                ^
>>> ../../gcc/cselib.h:49:16: note:   candidate expects 1 argument, 2 provided
>>
>> #include <new>
>>
>
> Hi.
>
> <new> header file is not missing (explicit addition of the file does not help).
> Feel free to play with following patch which should fix cselib.h compilation error.

cselib_val overrides the new operator but fails to provide an overload
for the placement new
form.  Fix that and it should work (of course it gets quite awkward
with its 'new' calling
pool.allocate and its placement new doing value-construction then...)

Richard.

> Thanks,
> Martin
Martin Liška June 16, 2015, 1:38 p.m. UTC | #2
On 06/16/2015 03:17 PM, Richard Biener wrote:
> On Tue, Jun 16, 2015 at 11:26 AM, Martin Liška <mliska@suse.cz> wrote:
>> On 06/15/2015 07:31 PM, Marc Glisse wrote:
>>> On Mon, 15 Jun 2015, Martin Liška wrote:
>>>
>>>> Ah, I overlooked that it's not a placement new, but just static casting.
>>>> Anyway, if I added:
>>>>
>>>> cselib_val () {}
>>>>
>>>> to struct cselib_val and changed the cast to placement new:
>>>>  char *ptr = (char *) header;
>>>>  return new (ptr) T ();
>>>>
>>>> I got following compilation error:
>>>>
>>>> In file included from ../../gcc/alias.c:46:0:
>>>> ../../gcc/alloc-pool.h: In instantiation of ‘T* pool_allocator<T>::allocate() [with T = cselib_val]’:
>>>> ../../gcc/cselib.h:51:27:   required from here
>>>> ../../gcc/alloc-pool.h:416:23: error: no matching function for call to ‘cselib_val::operator new(sizetype, char*&)’
>>>>   return new (ptr) T ();
>>>>                       ^
>>>> In file included from ../../gcc/alias.c:47:0:
>>>> ../../gcc/cselib.h:49:16: note: candidate: static void* cselib_val::operator new(size_t)
>>>>   inline void *operator new (size_t)
>>>>                ^
>>>> ../../gcc/cselib.h:49:16: note:   candidate expects 1 argument, 2 provided
>>>
>>> #include <new>
>>>
>>
>> Hi.
>>
>> <new> header file is not missing (explicit addition of the file does not help).
>> Feel free to play with following patch which should fix cselib.h compilation error.
> 
> cselib_val overrides the new operator but fails to provide an overload
> for the placement new
> form.  Fix that and it should work (of course it gets quite awkward
> with its 'new' calling
> pool.allocate and its placement new doing value-construction then...)
> 
> Richard.

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;
+  }

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;
  }
}

Thanks,
Martin



> 
>> Thanks,
>> Martin
Richard Biener June 16, 2015, 2:02 p.m. UTC | #3
On Tue, Jun 16, 2015 at 3:38 PM, Martin Liška <mliska@suse.cz> wrote:
> On 06/16/2015 03:17 PM, Richard Biener wrote:
>> On Tue, Jun 16, 2015 at 11:26 AM, Martin Liška <mliska@suse.cz> wrote:
>>> On 06/15/2015 07:31 PM, Marc Glisse wrote:
>>>> On Mon, 15 Jun 2015, Martin Liška wrote:
>>>>
>>>>> Ah, I overlooked that it's not a placement new, but just static casting.
>>>>> Anyway, if I added:
>>>>>
>>>>> cselib_val () {}
>>>>>
>>>>> to struct cselib_val and changed the cast to placement new:
>>>>>  char *ptr = (char *) header;
>>>>>  return new (ptr) T ();
>>>>>
>>>>> I got following compilation error:
>>>>>
>>>>> In file included from ../../gcc/alias.c:46:0:
>>>>> ../../gcc/alloc-pool.h: In instantiation of ‘T* pool_allocator<T>::allocate() [with T = cselib_val]’:
>>>>> ../../gcc/cselib.h:51:27:   required from here
>>>>> ../../gcc/alloc-pool.h:416:23: error: no matching function for call to ‘cselib_val::operator new(sizetype, char*&)’
>>>>>   return new (ptr) T ();
>>>>>                       ^
>>>>> In file included from ../../gcc/alias.c:47:0:
>>>>> ../../gcc/cselib.h:49:16: note: candidate: static void* cselib_val::operator new(size_t)
>>>>>   inline void *operator new (size_t)
>>>>>                ^
>>>>> ../../gcc/cselib.h:49:16: note:   candidate expects 1 argument, 2 provided
>>>>
>>>> #include <new>
>>>>
>>>
>>> Hi.
>>>
>>> <new> header file is not missing (explicit addition of the file does not help).
>>> Feel free to play with following patch which should fix cselib.h compilation error.
>>
>> cselib_val overrides the new operator but fails to provide an overload
>> for the placement new
>> form.  Fix that and it should work (of course it gets quite awkward
>> with its 'new' calling
>> pool.allocate and its placement new doing value-construction then...)
>>
>> Richard.
>
> 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?)

Richard.

> }
>
> Thanks,
> Martin
>
>
>
>>
>>> Thanks,
>>> Martin
>
Marc Glisse June 16, 2015, 6:28 p.m. UTC | #4
On Tue, 16 Jun 2015, Martin Liška wrote:

> On 06/15/2015 07:31 PM, Marc Glisse wrote:
>> On Mon, 15 Jun 2015, Martin Liška wrote:
>>
>>> Ah, I overlooked that it's not a placement new, but just static casting.
>>> Anyway, if I added:
>>>
>>> cselib_val () {}
>>>
>>> to struct cselib_val and changed the cast to placement new:
>>>  char *ptr = (char *) header;
>>>  return new (ptr) T ();
>>>
>>> I got following compilation error:
>>>
>>> In file included from ../../gcc/alias.c:46:0:
>>> ../../gcc/alloc-pool.h: In instantiation of ‘T* pool_allocator<T>::allocate() [with T = cselib_val]’:
>>> ../../gcc/cselib.h:51:27:   required from here
>>> ../../gcc/alloc-pool.h:416:23: error: no matching function for call to ‘cselib_val::operator new(sizetype, char*&)’
>>>   return new (ptr) T ();
>>>                       ^
>>> In file included from ../../gcc/alias.c:47:0:
>>> ../../gcc/cselib.h:49:16: note: candidate: static void* cselib_val::operator new(size_t)
>>>   inline void *operator new (size_t)
>>>                ^
>>> ../../gcc/cselib.h:49:16: note:   candidate expects 1 argument, 2 provided
>>
>> #include <new>
>
> Hi.
>
> <new> header file is not missing (explicit addition of the file does not help).
> Feel free to play with following patch which should fix cselib.h compilation error.

-  return (T *)(header);
+  return ::new (header) T ();

compiles just fine for me (without touching cselib.h).
(the discussion has moved on so this might not be relevant anymore)
diff mbox

Patch

diff --git a/gcc/alloc-pool.h b/gcc/alloc-pool.h
index 1785df5..4b4bc56 100644
--- a/gcc/alloc-pool.h
+++ b/gcc/alloc-pool.h
@@ -413,7 +413,8 @@  pool_allocator<T>::allocate ()
   VALGRIND_DISCARD (VALGRIND_MAKE_MEM_UNDEFINED (header, size));
 
   /* Call default constructor.  */
-  return (T *)(header);
+  char *ptr = (char *) header;
+  return new (ptr) T ();
 }
 
 /* Puts PTR back on POOL's free list.  */
diff --git a/gcc/cselib.h b/gcc/cselib.h
index cdd06ad..a0da27f 100644
--- a/gcc/cselib.h
+++ b/gcc/cselib.h
@@ -42,6 +42,9 @@  struct cselib_val
 
   struct cselib_val *next_containing_mem;
 
+  /* Default constructor.  */
+  cselib_val () {}
+
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {
@@ -67,6 +70,9 @@  struct elt_loc_list {
   /* The insn that made the equivalence.  */
   rtx_insn *setting_insn;
 
+  /* Default constructor.  */
+  elt_loc_list () {}
+
   /* Pool allocation new operator.  */
   inline void *operator new (size_t)
   {