On Sun, Jan 11, 2009 at 7:59 PM, Raoul Gough <raoulgo...@yahoo.co.uk> wrote:
> Richard Guenther wrote:
>>
>> On Sat, Jan 10, 2009 at 12:55 PM, Richard Guenther
>> <richard.guent...@gmail.com> wrote:
>>
>>>
>>> On Sat, Jan 10, 2009 at 12:19 PM, Raoul Gough <raoulgo...@clara.co.uk>
>>> wrote:
>>>
>
> [snip]
>>>>
>>>> Here we pass into bar a pointer to int and double at the same storage
>>>> location. So now, if the compiler goes ahead and reorders the read and
>>>> write
>>>> in function bar, the assertion would fail. Note that this code does
>>>> *not*
>>>> write one type into a union and read another. It writes an int, reads an
>>>> int
>>>> and then writes a double. All that's happening is that the storage is
>>>> being
>>>> *reused* for a different type. However, this re-use takes place within
>>>> function bar, which doesn't necessarily know about the union (especially
>>>> if
>>>> it's in a different compilation unit).
>>>>
>>>> So, my question is, does the salias analysis indicate that the compiler
>>>> thinks it can reorder the operations in function bar?
>>>>
>>>
>>> There is a defect report about this and I'm sure numerous bugreports
>>> in bugzilla.
>>> The conclusion is that the above invokes undefined behavior because the
>>> accesses are not done through a union type, so the static memory typing
>>> rules
>>> of C apply.
>>>
>>
>> http://www.open-std.org/JTC1/SC22/WG14/www/docs/dr_236.htm
>>
>>
>
> Interesting. It looks like the committee discussion was going to make the
> union example invalid, but the one using plain pointers (and malloc) was
> still up for discussion. Then the final decision was that both of their
> examples invoked undefined behaviour. Unfortunately, that renders invalid a
> common idiom for free-list memory (de)allocators, by which I mean re-using
> the client storage space for the free-list "next" pointer in the
> deallocator.
>
> I guess the situation is more complicated in C++, which has explicit
> destructors. Consider the following example, which is getting closer to the
> problem that originally got me interested in this subject:
>
> void** global_free_list = 0;
>
> inline void operator delete(void* p2) throw()
> {
>   // Save "next" pointer in re-used client storage. TODO - check for NULL
>   *static_cast<void **>(p2) = global_free_list;
>   global_free_list = static_cast<void **>(p2);
> }
>
> double foo(double* p1)
> {
>   double result = *p1;
>   delete p1;
>   return result;
> }
>
> Now, after inlining, this example looks very similar to my original one,
> except we have pointers of type double* and void** sharing the same storage
> space instead of int* and double*. Note - we can easily ensure that the
> corresponding operator new() always allocates storage suitably sized and
> aligned for a void*.

This is also invalid.  You have to use placement new to change the dynamic
type of memory.

Richard.

Reply via email to