Home > Software engineering >  bad_function_call thrown and segmentation fault caused when passing avx variables to std::function
bad_function_call thrown and segmentation fault caused when passing avx variables to std::function

Time:09-27

This problem is found when writing some code related to computer graphics, a simplified version of the code is shown below:

#include <bits/stdc  .h>

#define __AVX__ 1
#define __AVX2__ 1
#pragma GCC target("avx,avx2,popcnt,tune=native")
#include <immintrin.h>

namespace with_avx {
class vec {
   public:
    vec(double x = 0, double y = 0, double z = 0, double t = 0) {
        vec_data = _mm256_set_pd(t, z, y, x);
    }
    __m256d vec_data;
};
}  // namespace with_avx

namespace without_avx {
class vec {
   public:
    vec(double x = 0, double y = 0, double z = 0, double t = 0) {
        vec_data[0] = x, vec_data[1] = y, vec_data[2] = z, vec_data[3] = t;
    }
    double vec_data[4];
};
}  // namespace without_avx

#ifdef USE_AVX
using namespace with_avx;
#else
using namespace without_avx;
#endif

vec same(vec x) { return x; }
std::function<vec(vec)> stdfunc = same;

int main() { 
    vec rand_vec(rand(), rand(), rand());
    vec ret = stdfunc(rand_vec);
    std::cout<<(double)ret.vec_data[0];
}

If I compile the code with the flag USE_AVX like the following:

 g  -12 stdfunction_test.cpp -o ../build/unit_test -D USE_AVX -g

g will output some warnings:

In file included from /usr/include/c  /12/functional:59,
                 from /usr/include/x86_64-linux-gnu/c  /12/bits/stdc  .h:71,
                 from stdfunction_test.cpp:2:
/usr/include/c  /12/bits/std_function.h: In member function ‘_Res std::function<_Res(_ArgTypes ...)>::operator()(_ArgTypes ...) const [with _Res = with_avx::vec; _ArgTypes = {with_avx::vec}]’:
/usr/include/c  /12/bits/std_function.h:587:7: note: the ABI for passing parameters with 32-byte alignment has changed in GCC 4.6
  587 |       operator()(_ArgTypes... __args) const
      |       ^~~~~~~~

Then if I run the code, sometimes segmentation fault is caused with the following output:

[1]    12710 segmentation fault  ../build/unit_test

Sometimes, bad_function_call is thrown with the following output:

terminate called after throwing an instance of 'std::bad_function_call'
  what():  bad_function_call
[1]    12678 IOT instruction  ../build/unit_test

Both of these two errors are made when this line is executed:

vec ret = stdfunc(rand_vec);

I then used gdb for backtrace:

(gdb) bt
#0  0x00007ffff7e35521 in __cxa_throw () from /lib/x86_64-linux-gnu/libstdc  .so.6
#1  0x00007ffff7e2c6f4 in std::__throw_bad_function_call() () from /lib/x86_64-linux-gnu/libstdc  .so.6
#2  0x000055555555558b in std::function<with_avx::vec (with_avx::vec)>::operator()(with_avx::vec) const (this=0x7fffffffda74,
    __args#0=...) at /usr/include/c  /12/bits/std_function.h:590
#3  0x000055555555528d in main () at stdfunction_test.cpp:39

However if I don't add the flag, the code would run normally.

I think this is possibly caused by some kind of alignment problems like the warning sait I just don't know how to solve this.

My environment is listed on the following, hope they will be useful:

  • g version: g -12 (Ubuntu 12-20220319-1ubuntu1) 12.0.1 20220319 (experimental) [master r12-7719-g8ca61ad148f]
  • OS: Ubuntu-22.04 running on WSL2

CodePudding user response:

Changing the target architecture half way through the file is causing your issue. Presumably parts of std::function's implementation changes with the target architecture. Moving your pragma to the start of the file fixes the problem: https://godbolt.org/z/WP5ah38WP

It'll be safer in general if you set your architecture target via the compiler command line (e.g. -mavx2) which will ensure all your code is compiled with the same architectures: https://godbolt.org/z/z5j79c5eh

  • Related