c++/2701: boost: constructor called twice (gcc-2.95 regression)

Peter Schmid schmid@snake.iap.physik.tu-darmstadt.de
Mon Apr 30 14:56:00 GMT 2001


>Number:         2701
>Category:       c++
>Synopsis:       boost: constructor called twice (gcc-2.95 regression)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Apr 30 14:56:00 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     Peter Schmid
>Release:        3.1 20010428 (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.4 (with BFD 2.11.90.0.4)
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-long-long --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.21.2 repository 
causes a segmentation fault when run if compiled by gcc 3.1. If the
code is compiled by gcc 2.95.2 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). I believe that is a regression from gcc
2.95.2. 

>How-To-Repeat:
Source code t.C

#include <assert.h>
extern "C" int printf (const char *, ...);
namespace std {

    template<typename _Tp> struct numeric_limits {
        static const bool is_specialized = false;
        static _Tp max() throw() { return static_cast<_Tp>(0); }
    };

    template<> struct numeric_limits<int> {
        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 IntType, IntType a, IntType c, IntType m, IntType val>
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<int32_t, 16807, 0, 2147483647, 
  1043618065> minstd_rand0;

// must be in boost namespace, otherwise the inline friend trick fails
template<class Generator, class ResultType>
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<Generator&>(*this); }
  value_type v;
};

// uniform integer distribution on a small range [min, max]
template<class UniformRandomNumberGenerator, class IntType = int>
class uniform_smallint
  : public generator_iterator_mixin_adapter<
        uniform_smallint<UniformRandomNumberGenerator, IntType>, 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<class UniformRandomNumberGenerator, class IntType>
uniform_smallint<UniformRandomNumberGenerator, IntType>::
uniform_smallint(base_type & rng, IntType min, IntType max) 
  : _rng(rng), _min(min), _max(max),
    _range(static_cast<base_result>(_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<base_result>::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 UniformRandomNumberGenerator, class IntType = int>
class uniform_int
  : public generator_iterator_mixin_adapter<
        uniform_int<UniformRandomNumberGenerator, IntType>, 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<class UniformRandomNumberGenerator, class IntType>
inline IntType uniform_int<UniformRandomNumberGenerator, IntType>::operator()()
{
}

} // namespace boost


template<class URNG, class ResultType>
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<URNG> 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-long-long --enable-languages=c,c++,f77,objc
Thread model: posix
gcc version 3.1 20010428 (experimental)
 /usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.1/cpp0 -lang-c++ -D_GNU_SOURCE -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__STDC_HOSTED__=1 -W -Wall -Acpu=i386 -Amachine=i386 -Di386 -D__i386 -D__i386__ -D__tune_i686__ -D__tune_pentiumpro__ t.C t.ii
GNU CPP version 3.1 20010428 (experimental) (cpplib) (i386 Linux/ELF)
#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/local/i686-pc-linux-gnu/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 20010428 (experimental) (cpplib) (i386 Linux/ELF)
GNU C++ version 3.1 20010428 (experimental) (i686-pc-linux-gnu)
	compiled by GNU C version 3.1 20010428 (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<boost::minstd_rand0, 
   int> 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.4 (i686-pc-linux-gnu) using BFD version 2.11.90.0.4
 /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 -lc -lgcc_s /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)

./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<typename _Tp> struct numeric_limits {
        static const bool is_specialized = false;
        static _Tp max() throw() { return static_cast<_Tp>(0); }
    };

    template<> struct numeric_limits<int> {
        static const bool is_specialized = true;
        static int max() throw()
        { return 2147483647; }
    };

}



namespace boost
{
    typedef int int32_t;

namespace random {


template<class IntType, IntType a, IntType c, IntType m, IntType val>
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<int32_t, 16807, 0, 2147483647,
  1043618065> minstd_rand0;


template<class Generator, class ResultType>
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<Generator&>(*this); }
  value_type v;
};


template<class UniformRandomNumberGenerator, class IntType = int>
class uniform_smallint
  : public generator_iterator_mixin_adapter<
        uniform_smallint<UniformRandomNumberGenerator, IntType>, 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<class UniformRandomNumberGenerator, class IntType>
uniform_smallint<UniformRandomNumberGenerator, IntType>::
uniform_smallint(base_type & rng, IntType min, IntType max)
  : _rng(rng), _min(min), _max(max),
    _range(static_cast<base_result>(_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<base_result>::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 UniformRandomNumberGenerator, class IntType = int>
class uniform_int
  : public generator_iterator_mixin_adapter<
        uniform_int<UniformRandomNumberGenerator, IntType>, 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<class UniformRandomNumberGenerator, class IntType>
inline IntType uniform_int<UniformRandomNumberGenerator, IntType>::operator()()
{
}

}


template<class URNG, class ResultType>
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<URNG> 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:



More information about the Gcc-bugs mailing list