gcc-4.4.0 and boost::optional is giving (spurious?) strict-aliasing warnings

Before I get to the details, let me start by saying that I suspect that these warnings are probably spurious. But, before I go and start asking the compiler folks if they are bugs, I'd like to check here first. If you take unmodified boost-1.38.0 and try to use boost::optional with gcc-4.4.0 -Wall -O3, you seem to get warnings about strict-aliasing rules being broken. If boost::optional (and boost::function) are really broken, then we're probably in trouble :) test.cc: #include <boost/optional.hpp> boost::optional<int> x; int func() { return *x; } On x86_64-unknown-linux-gnu: $ /opt/gcc-4.4.0/bin/g++ -Wall -O3 -I. -c -o test.o test.cc test.cc: In function ‘int func()’: test.cc:5: warning: dereferencing pointer ‘<anonymous>’ does break strict-aliasing rules ./boost/optional/optional.hpp:594: note: initialized from here I have seen some similar issues with boost::bind and boost::function, but I haven't isolated them down to something this simple yet. I figured I'd start by asking about this. So, is it safe to presume that boost::optional is not really breaking the strict aliasing rules? (It's not immediately obvious.) If so, then I can ask the gcc folks about this. Thanks! -- ---------------------------------------------------------- Brad Spencer - spencer@starscale.com - www.starscale.com

Brad Spencer wrote:
Before I get to the details, let me start by saying that I suspect that these warnings are probably spurious. But, before I go and start asking the compiler folks if they are bugs, I'd like to check here first.
If you take unmodified boost-1.38.0 and try to use boost::optional with gcc-4.4.0 -Wall -O3, you seem to get warnings about strict-aliasing rules being broken. If boost::optional (and boost::function) are really broken, then we're probably in trouble :)
Does it affect boost::variant too?

On Wed, May 6, 2009 at 11:08 AM, Mathias Gaunard <mathias.gaunard@ens-lyon.org> wrote:
Does it affect boost::variant too?
Yes, it does for me: /home/mlcreech/svn/PCM-tk/trunk/vendor_export/include/boost/variant/detail/backup_holder.hpp: In member function 'virtual int CTrendThread::wait_for_events()': /home/mlcreech/svn/PCM-tk/trunk/vendor_export/include/boost/variant/detail/backup_holder.hpp:67: warning: dereferencing pointer '<anonymous>' does break strict-aliasing rules /home/mlcreech/svn/PCM-tk/trunk/vendor_export/include/boost/variant/detail/cast_storage.hpp:33: note: initialized from here this is triggered by a call to boost::apply_visitor. I tried a couple of simpler test cases with no problems, though. GCC 4.4.0, compiling w/ "-Os -Wall -std=c++0x" Boost 1.39 -- Matthew L. Creech

At 7:17 PM -0300 5/5/09, Brad Spencer wrote:
Before I get to the details, let me start by saying that I suspect that these warnings are probably spurious. But, before I go and start asking the compiler folks if they are bugs, I'd like to check here first.
If you take unmodified boost-1.38.0 and try to use boost::optional with gcc-4.4.0 -Wall -O3, you seem to get warnings about strict-aliasing rules being broken. If boost::optional (and boost::function) are really broken, then we're probably in trouble :)
test.cc:
#include <boost/optional.hpp> boost::optional<int> x; int func() { return *x; }
On x86_64-unknown-linux-gnu:
$ /opt/gcc-4.4.0/bin/g++ -Wall -O3 -I. -c -o test.o test.cc test.cc: In function 'int func()': test.cc:5: warning: dereferencing pointer '<anonymous>' does break strict-aliasing rules ./boost/optional/optional.hpp:594: note: initialized from here
I have seen some similar issues with boost::bind and boost::function, but I haven't isolated them down to something this simple yet. I figured I'd start by asking about this.
So, is it safe to presume that boost::optional is not really breaking the strict aliasing rules? (It's not immediately obvious.) If so, then I can ask the gcc folks about this.
If I've traced through the code properly and still remember the strict aliasing rules at all, then I think boost::optional is in fact in violation of those rules. [Note that the relevant parts of the C99 standard for this discussion are 6.5#6-7 and 6.5.2.3#5.] In boost/aligned_storage.hpp, the class template boost::aligned_storage defines its address member function thusly: void* address() { return this; } const void* address() const { return this; } There is code in boost/optional/optional.hpp (and probably the other libs you mention) which looks like: internal_type* get_object() { return static_cast<internal_type*>(m_storage.address()); } What this leads, after some expansion, to something roughly equivalent to static_cast<internal_type*>( static_cast<void*>( <a pointer to an instance of aligned_storage> )) which I believe is not strict aliasing safe. It is effectively a cast from aligned_storage* to internal_type*, with a trip through void* along the way. That trip through void* does not make the conversion satisfy the strict aliasing rules. [Note that it is not the cast itself that violates the strict aliasing rules, it is the later dereference of the pointer resulting from the cast.] [Note that I'm pretty sure that switching from static_cast to reinterpret_cast doesn't help.] One of the escape hatches provided by the strict aliasing rules involves ensuring that there is a union type in scope at the point of the conversion which contains both of the involved types. [The "visible union" rule of 6.5.2.3#5.] However, that isn't generally applicable to something like optional, because unions are restricted to POD types. Another escape hatch offered by the strict aliasing rules involves memcpy and memmove. [6.5#6] I think that the following implementation of aligned_storage::address will satisfy the strict aliasing rules: void* address() { void* data = data_.data_.buf; return memmove(data, data, sizeof(*data)); } And I think gcc will optimize away the memmove, at least at sufficient optimization levels. But note that I have not tested this at all. [Hm, using a size of 0 or 1 or some similar small value might be sufficient to quiet the compiler; I'm not certain whether it is sufficient to satisfy the letter of the C standard.] [Or perhaps the "correct" definition from a C perspective is void* address() { return memmove(this, data_.data_.buf, sizeof(*this)); } except that applying memmove to a non-POD is undefined. I keep getting confused every time I try to get my head wrapped around the strict aliasing rules and their implications.] The idea is that memmove (and memcpy, but that requres non-overlapping source and destination, which we don't have here) is defined by the aliasing rules to strip away the type of the destination, in a way that a simple cast does not. [And yes, I agree that this is rather grotesque.] [Assuming this change is correct, it might also address the warnings from other libs like function, which I think are also making use of aligned_storage.] Unfortunately, while the aliasing rules permit one to cast a pointer to any type to a char* and then go poking around looking at the raw binary data, the reverse is generally not permitted. Thus, the following implementation of aligned_storage::address is not correct: void* address() { return data_.data_.buf; } Of course, one could just turn off strict aliasing for gcc, using the -fno-strict-aliasing option. Doing so would put you in good company; many large projects (including the Linux kernel, BSD, rtems, Python, bjam(!), others that I don't recall off the top of my head) turn off strict aliasing, with such reasons as the following cited - the strict aliasing rules and their implications are arcane, - the strict aliasing rules forbid idioms common in low-level system programming type code, - the methods for dealing with strict aliasing in such low-level system code make the code harder to understand, - the benefits derived from enabling strict aliasing are not worth the headaches - tools (including compilers that support strict aliasing) don't (and perhaps can't) provide good diagnostics about violations. gcc, for example, specifically documents that all levels for enabled strict aliasing warnings can produce both false positives and false negatives. I'm not in a position to try anything with gcc4.4 right now. If anyone tries any of my suggestions above, I'd be interested in the results. Note that to be really thorough, one should carefully inspect the generated code if the warnings go away.
participants (4)
-
Brad Spencer
-
Kim Barrett
-
Mathias Gaunard
-
Matthew L. Creech