Boost logo

Boost :

Subject: Re: [boost] [gil] gcc fail with simple code
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2018-03-28 18:01:57


On 03/28/18 20:52, Andrey Semashev wrote:
> On 03/28/18 20:30, Christian Henning via Boost wrote:
>> Hi all,
>>
>> we are, at the boost::gil corner, investigating a runtime failure when
>> compiling with gcc 5.4. When running in release configuration the
>> following
>> code fails:
>>
>> #include <iostream>
>> #include <boost/gil/gil_all.hpp>
>>
>> using namespace boost::gil;
>> using namespace std;
>>
>> void error_if(bool condition) {
>>      if (condition)
>>          throw std::exception();
>> }
>>
>> bits32s c32s_min = channel_traits<bits32s>::min_value();
>> bits32s c32s_max = channel_traits<bits32s>::max_value();
>>
>> // For channel values simply initialize the value directly
>> template <typename ChannelValue>
>> struct value_core {
>>      typedef ChannelValue channel_t;
>>      channel_t _min_v, _max_v;
>>
>>      value_core() : _min_v(channel_traits<ChannelValue>::min_value()),
>> _max_v(channel_traits<ChannelValue>::max_value())
>>      {}
>> };
>>
>> int main(int argc, char *argv[])
>> {
>>      value_core<bits32s> a;
>>
>>      bits32s v_min, v_max;
>>
>>      v_min = channel_convert<bits32s>(c32s_min);
>>      v_max = channel_convert<bits32s>(c32s_max);
>>
>>      //std::cout << v_min << std::endl;
>>      // std::cout << this->_min_v << std::endl;
>>      //std::cout << v_max << std::endl;
>>      // std::cout << this->_max_v << std::endl;
>>
>>      error_if(v_min != a._min_v || v_max != a._max_v);
>> }
>>
>> The interesting thing is that everything works with the cout's enabled.
>>
>> Has anyone ever dealt with a similar issue?
>
> Most likely, you have a signed integer overflow somewhere. The code
> crashes on gcc 7.2 with -O3 but doesn't crash with -O0 or with -O3 -fwrapv.

With -ftrapv the code crashes at this point:

#0 __GI_raise (sig=sig_at_entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff7490f5d in __GI_abort () at abort.c:90
#2 0x00007ffff783b2d8 in __addvsi3 () from
/lib/x86_64-linux-gnu/libgcc_s.so.1
#3 0x00005555555548a9 in
boost::gil::detail::channel_convert_to_unsigned<int>::operator()
(this=<optimized out>, x=<optimized out>) at
./boost/gil/channel_algorithm.hpp:332
#4 boost::gil::channel_converter<int, int>::operator() (this=<optimized
out>, src=@0x555555755014: 2147483647) at
./boost/gil/channel_algorithm.hpp:368
#5 boost::gil::channel_convert<int, int> (src=@0x555555755014:
2147483647) at ./boost/gil/channel_algorithm.hpp:377
#6 main (argc=<optimized out>, argv=<optimized out>) at test_gil.cpp:32

channel_algorithm.hpp:332 is this line:

     type operator()(bits32s x) const { return
static_cast<bits32>(x+(1<<31)); }

This shift is UB because it overflows (until C++17, I think?). The
addition will also overflow unless x is 0.

I would suggest casting to unsigned first and then performing the math.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk