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.