Home > Enterprise >  this = nullptr in lambda functions gcc 11.1
this = nullptr in lambda functions gcc 11.1

Time:08-27

I've got the following code:

#include <iostream>

template<typename T>
struct A
{
    T a;
    T b;
    static bool(*foo)(T, T);
};

template<>
bool(*A<int>::foo)(int, int) = [](int a, int b)->bool{ return a == b; };

struct B
{
    int b;
};

template<typename T, typename U>
T bar(U(*func)(const int&)) { return func(23).b; }

int main()
{
    A<int> a = {.a=1, .b=1};
    std::cout << std::boolalpha << A<int>::foo(a.a, a.b) << std::endl;
    std::cout << bar<int, B>([](const int& val) -> B { return {.b = val}; });
    return 0;
}

Being compiled with -Werror=nonnull -Og -fsanitize=undefined -std=c 20 flags under gcc 11.1 it produces a error per lambda like:

<source>:12:71: error: 'this' pointer is null [-Werror=nonnull]

(for more details see https://godbolt.org/z/a4GsPW71E)

As I know, this = nullptr is a vivid marker of UB in the code, however my code looks pretty inconspicuous. To avoid the error you should either change version of compiler or make a slight change in the code (e.g. remove lambda's parameter, or template, or something else).

Does anyone know the reason of this errors, does gcc try to help me or it is just a bug in the compiler?

CodePudding user response:

Here is the most I can simplify your example to:

// g  -11 -Werror=nonnull -Og -fsanitize=undefined
// (Or any level of optimization other than -O0)

bool(*bar)(int) = [](int) { return true; };

https://godbolt.org/z/rbrczEbPx

<source>: In static member function 'static constexpr bool<lambda(int)>::_FUN(int)':
<source>:1:42: error: 'this' pointer is null [-Werror=nonnull]
    1 | bool(*bar)(int) = [](int) { return true; };
      |                                          ^
<source>:1:19: note: in a call to non-static member function '<lambda(int)>'
    1 | bool(*bar)(int) = [](int) { return true; };
      |                   ^
cc1plus: some warnings being treated as errors

My guess is that -fsanitize=undefined adds some code to the lambda checking something with the this in the lambda type's operator(), and some optimization removes the lambda object entirely with something that sets the this pointer in the lambda to nullptr since it is unused, which is caught by -Werror=nonnull.

But yes, this is a GCC bug. It does not appear in gcc-11.2 nor in gcc-10. As a workaround, you can replace your code like so:

template<>
bool(*A<int>::foo)(int, int) = [](int a, int b)->bool{ return a == b; };

// becomes

inline auto A_foo_int_fn(int a, int b)->bool{ return a == b; }
template<>
bool(*A<int>::foo)(int, int) = A_foo_int_fn;

Or just disable -Wnonnull around that region of code:

#if __GNUC__ == 11 && __GNUC_MINOR__ == 1
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
#endif

template<>
bool(*A<int>::foo)(int, int) = [](int a, int b)->bool{ return a == b; };

#if __GNUC__ == 11 && __GNUC_MINOR__ == 1
#pragma GCC diagnostic pop
#endif

This may be related to this bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96003

CodePudding user response:

I'm going to call this a compiler bug. The error message is obvious nonsense:

: In static member function 'static constexpr bool A::::_FUN(int, int)': :12:71: error: 'this' pointer is null [-Werror=nonnull]

"static member function" ... "'this' pointer is null".

I can sort of understand what happens here. A non-capturing lambda can be converted to a function pointer. The lambda is an object, so GCC reasonably has a this pointer internally, but that pointer stops making sense when the operator(int,int) aka _FUN is converted to a free function.

  • Related