https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87641

            Bug ID: 87641
           Summary: std::valarray<T>::sum() fails for types where T() is
                    not a neutral element for addition
           Product: gcc
           Version: 7.3.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: frederic.jardon at gmail dot com
  Target Milestone: ---

** Compiler version and command-line used are at the end of this message **


The following code:

    #include <iostream>
    #include <valarray>

    using namespace std;

    int main()
    {
        valarray<int> Y(0xf00d, 1);
        valarray<valarray<int>> X(Y, 1);
        cout << "X[0].size()    = " << X[0].size()            << '\n';
        cout << "X.sum().size() = " << X.sum().size()         << '\n';
    }

Should print (expected):

    X[0].size()    = 1
    X.sum().size() = 1

But it prints (actual):

    X[0].size()    = 1
    X.sum().size() = 0

I tracked the issue to this function:

   //
   // Compute the sum of elements in range [__f, __l)
   // This is a naive algorithm.  It suffers from cancelling.
   // In the future try to specialize
   // for _Tp = float, double, long double using a more accurate
   // algorithm.
   //
   template<typename _Tp>
     inline _Tp
     __valarray_sum(const _Tp* __f, const _Tp* __l)
     {
       _Tp __r = _Tp();
       while (__f != __l)
         __r += *__f++;
       return __r;
     }

The implementation assumes that:

    _Tp __r = _Tp();
    __r += *__f;

has the same value than *__f, but this is not the case if _Tp() is not a
neutral element for addition. For instance a default constructed
std::valarray<T> has a size of 0, and the end result will have a size of 0 even
though the *__f may be a valarray of size 1.

The same problem could occur if _Tp was a custom floating-point-like type whose
default constructed value was NaN.

Reference to the standard: 26.6.2.8

> This function may only be instantiated for a type T to which operator+= can be
> applied. This function returns the sum of all the elements of the array. If
> the array has length 0, the behavior is undefined. If the array has length 1,
> sum() returns the value of element 0. Otherwise, the returned value is
> calculated by applying operator+= to a copy of an element of the array and all
> other elements of the array in an unspecified order.

The standard clearly state that the initial value of __r should be a **copy of
an element of the array**

If you provide me a link on how to submit a pull-request I can work on
providing a patch.

I have reports that other compilers (clang, cl) doesn't exhibit this behavior.

Thanks for your attention and the good compiler :)

Frederic Jardon

======= compiler / compilation information

$ uname -a
CYGWIN_NT-10.0 DD1K7KF2 2.11.1(0.329/5/3) 2018-09-05 10:24 x86_64 Cygwin

$ LANG="" gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/7.3.0/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with:
/cygdrive/i/szsz/tmpp/gcc/gcc-7.3.0-3.x86_64/src/gcc-7.3.0/configure
--srcdir=/cygdrive/i/szsz/tmpp/gcc/gcc-7.3.0-3.x86_64/src/gcc-7.3.0
--prefix=/usr --exec-prefix=/usr --localstatedir=/var --sysconfdir=/etc
--docdir=/usr/share/doc/gcc --htmldir=/usr/share/doc/gcc/html -C
--build=x86_64-pc-cygwin --host=x86_64-pc-cygwin --target=x86_64-pc-cygwin
--without-libiconv-prefix --without-libintl-prefix --libexecdir=/usr/lib
--enable-shared --enable-shared-libgcc --enable-static
--enable-version-specific-runtime-libs --enable-bootstrap --enable-__cxa_atexit
--with-dwarf2 --with-tune=generic
--enable-languages=ada,c,c++,fortran,lto,objc,obj-c++ --enable-graphite
--enable-threads=posix --enable-libatomic --enable-libcilkrts --enable-libgomp
--enable-libitm --enable-libquadmath --enable-libquadmath-support
--disable-libssp --enable-libada --disable-symvers --with-gnu-ld --with-gnu-as
--with-cloog-include=/usr/include/cloog-isl --without-libiconv-prefix
--without-libintl-prefix --with-system-zlib --enable-linker-build-id
--with-default-libstdcxx-abi=gcc4-compatible --enable-libstdcxx-filesystem-ts
Thread model: posix
gcc version 7.3.0 (GCC) 

$ g++ valarray-sum.cpp -save-temps -o valarray-sum

$ ./valarray-sum.exe 
X[0].size()    = 1
X.sum().size() = 0


I also reproduced the same bug on another system:

$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabi/4.9/lto-wrapper
Target: arm-linux-gnueabi
Configured with: ../src/configure -v --with-pkgversion='Debian 4.9.2-10+deb8u1'
--with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs
--enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr
--program-suffix=-4.9 --enable-shared --enable-linker-build-id
--libexecdir=/usr/lib --without-included-gettext --enable-threads=posix
--with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls
--with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug
--enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libitm
--disable-libquadmath --enable-plugin --with-system-zlib
--disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo
--with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-armel/jre --enable-java-home
--with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-armel
--with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-armel
--with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar
--enable-objc-gc --enable-multiarch --disable-sjlj-exceptions
--with-arch=armv4t --with-float=soft --enable-checking=release
--build=arm-linux-gnueabi --host=arm-linux-gnueabi --target=arm-linux-gnueabi
Thread model: posix
gcc version 4.9.2 (Debian 4.9.2-10+deb8u1) 

$ uname -a
Linux DiskStation 2.6.32.12 #23824 Fri Sep 7 12:47:49 CST 2018 armv5tel
GNU/Linux

Reply via email to