Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

inconsistent warning: variable might be clobbered by ‘longjmp’ or ‘vfork’

Tags:

c++

setjmp

g++4.8

I have mostly convinced myself that I have encountered some g++ 4.8.3 bug, but I thought I would ask this list first because I have very little experience with setjmp/longjmp. I have simplified my code in question to the following foo.cxx:

#include <setjmp.h>
#include <string.h>

// Changing MyStruct to be just a single int makes the compiler happy.
struct MyStruct
{
    int a;
    int b;
};

// Setting MyType to int makes the compiler happy.
#ifdef USE_STRUCT
typedef MyStruct MyType;
#elif USE_INT
typedef int MyType;
#endif

void SomeFunc(MyType val)
{
}

static void static_func(MyType val)
{
    SomeFunc(val);
}

int main(int argc, char **argv)
{
    jmp_buf env;
    if (setjmp(env))
    {
        return 1;
    }

    MyType val;
#ifdef USE_STRUCT
    val.a = val.b = 0;
#elif USE_INT
    val = 0;
#endif
    // Enabling the below memset call makes the compiler happy.
    //memset(&val, 0, sizeof(val));

    // Iterating 1 or 2 times makes the compiler happy.
    for (unsigned i = 0; i < 3; i++)
    {
        // calling SomeFunc() directly makes the compiler happy.
        static_func(val);
    }
    return 0;
}

I use g++ 4.8.3 to compile this code. What's interesting to me is that when I define USE_STRUCT, the compilation fails but succeeds with USE_INT. There are comments in the code that further indicate how to make compilation succeed with USE_STRUCT. Compilation only fails also with the -fPIC option to g++, but this is a required argument in my environment.

To see the compilation error:

g++ -DUSE_STRUCT -Wextra -Wno-unused-parameter -O3 -Werror -fPIC foo.cxx
foo.cxx: In function ‘int main(int, char**)’:
foo.cxx:26:5: error: variable ‘val’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Werror=clobbered]

But using a simple int is OK:

g++ -DUSE_INT -Wextra -Wno-unused-parameter -O3 -Werror -fPIC foo.cxx

Can someone please explain to me why val might be clobbered if it is a struct but not if it is an int? Any insights on the other ways to make compilation succeed with the struct, as indicated in the comments in the code? Or is this pointing to a compiler bug?

Any insights and comments are greatly appreciated.

like image 514
boulderpika Avatar asked Jan 06 '15 16:01

boulderpika


1 Answers

setjmp() saves the current stack. Since it's called before the declaration of val, that variable won't be in the saved stack.

After setjmp(), the variable is initialized and if the code later jumps back to the setjmp point, the variable will be initialized again, clobbering the old variable. If there would be a non-trivial destructor that should be called on the old instance, this is undefined behavior (§18.10/4):

A setjmp/longjmp call pair has undefined behavior if replacing the setjmp and longjmp by catch and throw would invoke any non-trivial destructors for any automatic objects.

Likely the destructor of the old instance won't be called. My guess would be that gcc doesn't warn for primitive types, since they don't have destructors, but warns for more complicated types where this might be problematic.

like image 178
sth Avatar answered Nov 13 '22 10:11

sth