The following test case, which I'll also attach, segfaults at runtime when compiled by gcc-4.6-20110513 on x86_64-linux or i686-linux. When compiled by gcc-4.5-20110512 it works as expected. > cat comm-bug-test.cc #include <boost/foreach.hpp> #include <vector> #include <stdio.h> std::vector<int> v; std::vector<int> x; const inline std::vector<int *> getv() { const size_t num_accesses(x.size()); std::vector<int *> ret(num_accesses); for (size_t i = 0; i < num_accesses; i++) ret[i] = &v[x[i]]; return ret; } int main(int argc, char **argv) { x.push_back(0); x.push_back(1); x.push_back(2); x.push_back(3); x.push_back(4); x.push_back(5); v.push_back(11); v.push_back(12); v.push_back(13); v.push_back(14); v.push_back(15); v.push_back(16); BOOST_FOREACH(int *w, getv()) printf("%d\n", *w); return 0; } > /mnt/misc/install45/bin/g++ -O2 -Wall comm-bug-test.cc; ./a.out 11 12 13 14 15 16 > /mnt/misc/install46/bin/g++ -O2 -Wall comm-bug-test.cc; ./a.out Segmentation fault > /mnt/misc/install46/bin/g++ -v Using built-in specs. COLLECT_GCC=/mnt/misc/install46/bin/g++ COLLECT_LTO_WRAPPER=/mnt/misc/install46/libexec/gcc/x86_64-unknown-linux-gnu/4.6.1/lto-wrapper Target: x86_64-unknown-linux-gnu Configured with: /mnt/misc/gcc-4.6-20110513/configure --prefix=/mnt/misc/install46 --with-gmp=/home/mikpe/pkgs/linux-x86_64/gmp-4.3.2 --with-mpfr=/home/mikpe/pkgs/linux-x86_64/mpfr-2.4.2 --with-mpc=/home/mikpe/pkgs/linux-x86_64/mpc-0.8.2 --disable-plugin --disable-lto --disable-nls --disable-libmudflap --enable-threads=posix --enable-checking=release --enable-languages=c,c++,objc,obj-c++,fortran,java,ada Thread model: posix gcc version 4.6.1 20110513 (prerelease) (GCC) Initially found by a colleague when testing our code on Fedora 15 with Red Hat's gcc-4.6.0 (20110428) and boost 1.46. I then confirmed the bug on Fedora 13 with a self-compiled gcc-4.6-20110513 and boost-1.41. -m32 or -m64 makes no difference.
Created attachment 24260 [details] test case, preprocessed on x86_64-linux
Created attachment 24261 [details] test case, non-preprocessed
The temporary returned by getv() seems to be destroyed too early, before the printf that uses it
slightly reduced, but boost/foreach.hpp still includes thousands of lines in this version vector<T> zeros its data member on destruction, so using it after destruction is obvious #include <boost/foreach.hpp> template<typename T> struct vector { typedef const T* const_iterator; ~vector() { data = T(); } T data; const_iterator begin() const { return &data; } const_iterator end() const { return &data + 1; } }; vector<int> v = { 1 }; const vector<int *> getv() { vector<int *> ret = { &v.data }; return ret; } int main(int argc, char **argv) { BOOST_FOREACH(int *w, getv()) __builtin_printf("%d\n", *w); return 0; }
slightly more reduced #include <boost/foreach.hpp> struct vector { typedef int* const* const_iterator; ~vector() { data = 0; } int* data; const_iterator begin() const { return &data; } const_iterator end() const { return &data + 1; } }; int v = 1; const vector getv() { vector ret = { &v }; return ret; } int main(int argc, char **argv) { BOOST_FOREACH(int *w, getv()) __builtin_printf("%d\n", *w); return 0; }
The regression started with r170601: Author: jason Date: Tue Mar 1 22:44:35 2011 New Revision: 170601 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=170601 Log: PR c++/47851 * call.c (standard_conversion): Provide requested cv-quals on class rvalue conversion.
well if the fix for PR 47851 made G++ correct then this could be a bug in BOOST_FOREACH, but it's hard to know because trying to reduce any MPL code is pretty tedious! Jason, any ideas? do we need to reduce it with delta?
I'm trying to reduce the preprocessed test case, but since I'm not a C++ person this might take some time.
(In reply to comment #8) > I'm trying to reduce the preprocessed test case, but since I'm not a C++ person > this might take some time. Scratch that, the preprocessed code is way too weird for me.
(In reply to comment #9) > (In reply to comment #8) > > I'm trying to reduce the preprocessed test case, but since I'm not a C++ person > > this might take some time. > > Scratch that, the preprocessed code is way too weird for me. welcome to Boost MPL! ;) there are huge chunks that can be removed (iostreams and locales, reverse_iterators) but reducing it manually is not easy. See http://gcc.gnu.org/wiki/A_guide_to_testcase_reduction for a tool to do it automatically
Created attachment 24299 [details] reduced by delta
This is a bug in BOOST_FOREACH_COMPILE_TIME_CONST_RVALUE_DETECTION. The GCC bugfix meant that where previously true ? boost::foreach_detail_::make_probe(getv()) : (getv()) had the type "vector", now it has type "const vector". 5.16/3 says: Otherwise (i.e., if E1 or E2 has a nonclass type, or if they both have class types but the underlying classes are not either the same or one a base class of the other): E1 can be converted to match E2 if E1 can be implicitly converted to the type that expression E2 would have if E2 were converted to a prvalue (or the type it has, if E2 is a prvalue). "const vector" cannot be converted to make_probe<vector>, but make_probe<vector> has an operator vector&, so it can be converted to const vector, so the type of the conditional expression is const vector. Here's a reduced example: template <class T> void f (T&, int); template <class T> void f (T const&, ...); struct A { }; struct B { operator A& () const; }; const A g(); int main() { f( (true ? B() : g()), 0); }
(In reply to comment #12) > This is a bug in BOOST_FOREACH_COMPILE_TIME_CONST_RVALUE_DETECTION. This was already fixed in boost/trunk, and the fix will be released in Boost.1.47. For details, please see the following ticket: [Foreach] Compile-time const rvalue detection fails with gcc 4.6 https://svn.boost.org/trac/boost/ticket/5279