From mboxrd@z Thu Jan 1 00:00:00 1970 From: Peter Schmid To: gcc-gnats@gcc.gnu.org Subject: c++/3565: boost: constructor called twice (gcc-3.0 regression) Date: Wed, 04 Jul 2001 11:16:00 -0000 Message-id: <200107041911.VAA30417@snake.iap.physik.tu-darmstadt.de> X-SW-Source: 2001-07/msg00106.html List-Id: >Number: 3565 >Category: c++ >Synopsis: boost: constructor called twice (gcc-3.0 regression) >Confidential: no >Severity: serious >Priority: medium >Responsible: unassigned >State: open >Class: sw-bug >Submitter-Id: net >Arrival-Date: Wed Jul 04 11:16:01 PDT 2001 >Closed-Date: >Last-Modified: >Originator: Peter Schmid >Release: 3.1 20010703 (experimental) >Organization: TU Darmstadt >Environment: System: Linux kiste 2.4.3 #35 Sat Mar 31 22:08:25 CEST 2001 i686 unknown Architecture: i686 SuSE 7.1 Glibc 2.2 GNU ld version 2.11.90.0.15 (with BFD 2.11.90.0.15) host: i686-pc-linux-gnu build: i686-pc-linux-gnu target: i686-pc-linux-gnu configured with: ../gcc/configure --enable-shared --disable-nls --enable-threads=posix --enable-clocale=gnu --enable-languages=c,c++,f77,objc >Description: The following source code t.C extracted from the file libs/random/random_test.cpp from the boost 1.22.0 repository causes a segmentation fault when run, if compiled by gcc 3.1. If the code is compiled by gcc 2.95.2 or gcc 3.0 the program runs as expected. Further analysis shows that the code compiled by gcc 3.1 calls the uniform_smallint constructor twice, the _factor variable wraps around; it is set to zero causing a division by zero floating point exception in line 87 (result_type operator()()) of the class class uniform_smallint). That is a regression from gcc 2.95.2 and from gcc 3.0; and a long standing g++ 3.1 bug. >How-To-Repeat: Source code t.C #include extern "C" int printf (const char *, ...); namespace std { template struct numeric_limits { static const bool is_specialized = false; static _Tp max() throw() { return static_cast<_Tp>(0); } }; template<> struct numeric_limits { static const bool is_specialized = true; static int max() throw() { return 2147483647; } }; } // namespace std # define BOOST_STATIC_CONSTANT(type, assignment) static const type assignment namespace boost { typedef int int32_t; namespace random { // compile-time configurable linear congruential generator template class linear_congruential { public: typedef IntType result_type; static const bool has_fixed_range = true; result_type min() const { return c == 0 ? 1 : 0; } result_type max() const { return m-1; } explicit linear_congruential(IntType x0 = 1) : _x(x0) { } IntType operator()() { return _x; } private: IntType _x; }; } // namespace random // validation values from the publications typedef random::linear_congruential minstd_rand0; // must be in boost namespace, otherwise the inline friend trick fails template class generator_iterator_mixin_adapter { public: typedef ResultType value_type; Generator& operator++() { v = cast()(); return cast(); } const value_type& operator*() const { return v; } protected: // instantiate from derived classes only generator_iterator_mixin_adapter() { } void iterator_init() { operator++(); } private: Generator & cast() { return static_cast(*this); } value_type v; }; // uniform integer distribution on a small range [min, max] template class uniform_smallint : public generator_iterator_mixin_adapter< uniform_smallint, IntType > { public: typedef UniformRandomNumberGenerator base_type; typedef IntType result_type; BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); uniform_smallint(base_type & rng, IntType min, IntType max); result_type operator()() { // we must not use the low bits here, because LCGs get very bad then return ((_rng() - _rng.min()) / _factor) % _range + _min; } result_type min() const { return _min; } result_type max() const { return _max; } friend bool operator==(const uniform_smallint& x, const uniform_smallint& y) { return x._min == y._min && x._max == y._max && x._rng == y._rng; } private: typedef typename base_type::result_type base_result; base_type & _rng; IntType _min, _max; base_result _range; int _factor; }; template uniform_smallint:: uniform_smallint(base_type & rng, IntType min, IntType max) : _rng(rng), _min(min), _max(max), _range(static_cast(_max-_min)+1), _factor(1) { printf("Constructor called\n"); assert(min < max); // check how many low bits we can ignore before we get too much // quantization error base_result r_base = _rng.max() - _rng.min(); if(r_base == std::numeric_limits::max()) { _factor = 2; r_base /= 2; } r_base += 1; if(r_base % _range == 0) { // no quantization effects, good _factor = r_base / _range; } else { const base_result r = 32*_range*_range; for(; r_base >= r; _factor *= 2) r_base /= 2; } this->iterator_init(); // initialize iterator interface } // uniform integer distribution on [min, max] template class uniform_int : public generator_iterator_mixin_adapter< uniform_int, IntType > { public: typedef UniformRandomNumberGenerator base_type; typedef IntType result_type; BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); uniform_int(base_type & rng, IntType min, IntType max) : _rng(rng), _min(min), _max(max), _range(_max - _min), _bmin(_rng.min()), _brange(_rng.max() - _bmin) { assert(min < max); this->iterator_init(); } result_type operator()(); result_type min() const { return _min; } result_type max() const { return _max; } friend bool operator==(const uniform_int& x, const uniform_int& y) { return x._min == y._min && x._max == y._max && x._rng == y._rng; } private: typedef typename base_type::result_type base_result; base_type & _rng; result_type _min, _max, _range; base_result _bmin, _brange; }; template inline IntType uniform_int::operator()() { } } // namespace boost template void instantiate_urng(const URNG &, const ResultType &) { URNG urng; int a[URNG::has_fixed_range ? 5 : 10]; // compile-time constant (void) a; // avoid "unused" warning typename URNG::result_type x1 = urng(); boost::uniform_smallint unismall(urng, 0, 11); } void instantiate_all() { using namespace boost; instantiate_urng(minstd_rand0(), 0); } int main() { instantiate_all(); } Compiling the program t g++ -v -o t t.C -W -Wall -save-temps Reading specs from /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1/specs Configured with: ../gcc/configure --enable-shared --disable-nls --enable-threads=posix --enable-clocale=gnu --enable-languages=c,c++,f77,objc Thread model: posix gcc version 3.1 20010703 (experimental) /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1/cpp0 -lang-c++ -D__GNUG__=3 -D__DEPRECATED -D__EXCEPTIONS -D__GXX_ABI_VERSION=100 -v -D__GNUC__=3 -D__GNUC_MINOR__=1 -D__GNUC_PATCHLEVEL__=0 -D__ELF__ -Dunix -Dlinux -D__ELF__ -D__unix__ -D__linux__ -D__unix -D__linux -Asystem=posix -D__NO_INLINE__ -D__STDC_HOSTED__=1 -W -Wall -D_GNU_SOURCE -Acpu=i386 -Amachine=i386 -Di386 -D__i386 -D__i386__ -D__tune_i686__ -D__tune_pentiumpro__ t.C t.ii GNU CPP version 3.1 20010703 (experimental) (cpplib) (i386 Linux/ELF) ignoring nonexistent directory "/usr/local/i686-pc-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /usr/local/include/g++-v3 /usr/local/include/g++-v3/i686-pc-linux-gnu /usr/local/include/g++-v3/backward /usr/local/include /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1/include /usr/include End of search list. /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1/cc1plus -fpreprocessed t.ii -quiet -dumpbase t.C -W -Wall -version -o t.s GNU CPP version 3.1 20010703 (experimental) (cpplib) (i386 Linux/ELF) GNU C++ version 3.1 20010703 (experimental) (i686-pc-linux-gnu) compiled by GNU C version 3.1 20010703 (experimental). t.C: In function `void instantiate_urng(const URNG&, const ResultType&) [with URNG = boost::minstd_rand0, ResultType = int]': t.C:184: instantiated from here t.C:176: warning: unused variable `int32_t x1' t.C:178: warning: unused variable `boost::uniform_smallint unismall' /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1/../../../../i686-pc-linux-gnu/bin/as -V -Qy -o t.o t.s GNU assembler version 2.11.90.0.15 (i686-pc-linux-gnu) using BFD version 2.11.90.0.15 /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1/collect2 -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o t /usr/lib/crt1.o /usr/lib/crti.o /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1/crtbegin.o -L/usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1 -L/usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1/../../../../i686-pc-linux-gnu/lib -L/usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1/../../.. t.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1/crtend.o /usr/lib/crtn.o Running the program t (compiled by g++ 3.1) ./t Constructor called Constructor called Floating point exception (core dumped) Running the program t (compiled by g++ 2.95.2 or g++ 3.0) ./t Constructor called Preprocessed source file t.ii # 1 "t.C" # 1 "/usr/include/assert.h" 1 3 # 35 "/usr/include/assert.h" 3 # 1 "/usr/include/features.h" 1 3 # 283 "/usr/include/features.h" 3 # 1 "/usr/include/sys/cdefs.h" 1 3 # 284 "/usr/include/features.h" 2 3 # 311 "/usr/include/features.h" 3 # 1 "/usr/include/gnu/stubs.h" 1 3 # 312 "/usr/include/features.h" 2 3 # 36 "/usr/include/assert.h" 2 3 # 58 "/usr/include/assert.h" 3 extern "C" { extern void __assert_fail (__const char *__assertion, __const char *__file, unsigned int __line, __const char *__function) throw () __attribute__ ((__noreturn__)); extern void __assert_perror_fail (int __errnum, __const char *__file, unsigned int __line, __const char *__function) throw () __attribute__ ((__noreturn__)); extern void __assert (const char *__assertion, const char *__file, int __line) throw () __attribute__ ((__noreturn__)); } # 2 "t.C" 2 extern "C" int printf (const char *, ...); namespace std { template struct numeric_limits { static const bool is_specialized = false; static _Tp max() throw() { return static_cast<_Tp>(0); } }; template<> struct numeric_limits { static const bool is_specialized = true; static int max() throw() { return 2147483647; } }; } namespace boost { typedef int int32_t; namespace random { template class linear_congruential { public: typedef IntType result_type; static const bool has_fixed_range = true; result_type min() const { return c == 0 ? 1 : 0; } result_type max() const { return m-1; } explicit linear_congruential(IntType x0 = 1) : _x(x0) { } IntType operator()() { return _x; } private: IntType _x; }; } typedef random::linear_congruential minstd_rand0; template class generator_iterator_mixin_adapter { public: typedef ResultType value_type; Generator& operator++() { v = cast()(); return cast(); } const value_type& operator*() const { return v; } protected: generator_iterator_mixin_adapter() { } void iterator_init() { operator++(); } private: Generator & cast() { return static_cast(*this); } value_type v; }; template class uniform_smallint : public generator_iterator_mixin_adapter< uniform_smallint, IntType > { public: typedef UniformRandomNumberGenerator base_type; typedef IntType result_type; static const bool has_fixed_range = false; uniform_smallint(base_type & rng, IntType min, IntType max); result_type operator()() { return ((_rng() - _rng.min()) / _factor) % _range + _min; } result_type min() const { return _min; } result_type max() const { return _max; } friend bool operator==(const uniform_smallint& x, const uniform_smallint& y) { return x._min == y._min && x._max == y._max && x._rng == y._rng; } private: typedef typename base_type::result_type base_result; base_type & _rng; IntType _min, _max; base_result _range; int _factor; }; template uniform_smallint:: uniform_smallint(base_type & rng, IntType min, IntType max) : _rng(rng), _min(min), _max(max), _range(static_cast(_max-_min)+1), _factor(1) { printf("Constructor called\n"); ((void) ((min < max) ? 0 : (__assert_fail ("min < max", "t.C", 109, __PRETTY_FUNCTION__), 0))); base_result r_base = _rng.max() - _rng.min(); if(r_base == std::numeric_limits::max()) { _factor = 2; r_base /= 2; } r_base += 1; if(r_base % _range == 0) { _factor = r_base / _range; } else { const base_result r = 32*_range*_range; for(; r_base >= r; _factor *= 2) r_base /= 2; } this->iterator_init(); } template class uniform_int : public generator_iterator_mixin_adapter< uniform_int, IntType > { public: typedef UniformRandomNumberGenerator base_type; typedef IntType result_type; static const bool has_fixed_range = false; uniform_int(base_type & rng, IntType min, IntType max) : _rng(rng), _min(min), _max(max), _range(_max - _min), _bmin(_rng.min()), _brange(_rng.max() - _bmin) { ((void) ((min < max) ? 0 : (__assert_fail ("min < max", "t.C", 145, __PRETTY_FUNCTION__), 0))); this->iterator_init(); } result_type operator()(); result_type min() const { return _min; } result_type max() const { return _max; } friend bool operator==(const uniform_int& x, const uniform_int& y) { return x._min == y._min && x._max == y._max && x._rng == y._rng; } private: typedef typename base_type::result_type base_result; base_type & _rng; result_type _min, _max, _range; base_result _bmin, _brange; }; template inline IntType uniform_int::operator()() { } } template void instantiate_urng(const URNG &, const ResultType &) { URNG urng; int a[URNG::has_fixed_range ? 5 : 10]; (void) a; typename URNG::result_type x1 = urng(); boost::uniform_smallint unismall(urng, 0, 11); } void instantiate_all() { using namespace boost; instantiate_urng(minstd_rand0(), 0); } int main() { instantiate_all(); } >Fix: >Release-Note: >Audit-Trail: >Unformatted: