简体   繁体   中英

Segmentation fault when memcpy local static variable

I'm getting a segmentation fault but it's not clear to me why. I left a bunch of stuff out (hopefully nothing important). The funny thing is that it runs fine with 0 errors with a full leak check in valgrind. Here's all the info (I was working on a random number generator using code I found online):

file1.h

#ifdef __cplusplus
extern "C" {
#endif

#define STATE_N (19937 / 128 + 1)

union W128_T {
   uint32_t u[4];
   uint64_t u64[2];
};

typedef union W128_T w128_t;

struct STATE_T {
    w128_t state[STATE_N];
    int index;
};

typedef struct STATE_T state_t;

#ifdef __cplusplus
}
#endif

This is compiled into a static lib using the following command:

gcc -c -O3 -finline-functions -fomit-frame-pointer -DNDEBUG -fno-strict-aliasing --param max-inline-insns-single=1800 -fPIC -Wmissing-prototypes -Wall -std=c99 src/file1.c -o obj/file1.o
ar rc lib/librand.a obj/file1.o

file2.h

#include "../rand/include/file1.h"

#ifdef __cplusplus
extern "C" {
#endif

state_t * rstate(void);

#ifdef __cplusplus
};
#endif

file2.cpp

#include "file2.h"

static state_t rngState;

state_t * rstate(void) {
   return &rngState;
}

File 2 is compiled into a static library with the following command (some stuff omitted) (from cmake, running make VERBOSE=1:

/usr/bin/c++ -I/home/random/File1include -I/home/file2include -o CMakeFiles/file2Lib.dir/src/file2.o -c /home/src/file2.cpp

Then I test it all in this small test program test.cpp:

#include "file2.h"
#include <cstring>

int main(void) 
{
   state_t * state = rstate();
   state_t save;

   memcpy(&save, state, sizeof(save)); //segmentation fault
}

Which I build with the following command (stuff omitted):

g++ -I/home/random/File1include -I/home/file2include -L/home/file2Lib.dir -Wall -g test.o test.cpp
g++ -I/home/random/File1include -I/home/file2include -L/home/file2Lib.dir -Wall -g test.o -lfile2Lib -o randomTest

If I change test.cpp to this it works fine:

#include "file2.h"
#include <cstring>

int main(void) 
{
   state_t * state = new state_t();
   state = rstate();
   state_t save;

   memcpy(&save, state, sizeof(save));
}

OR if I leave test.cpp alone and change file2.h to this:

#include "../rand/include/file1.h"

#ifdef __cplusplus
extern "C" {
#endif

state_t * rstate(void);
state_t rngState;

#ifdef __cplusplus
};
#endif

And change file2.cpp to this:

#include "file2.h"

state_t * rstate(void) {
   return &rngState;
}

The program also runs correctly. Finally, if I change file2.h to this:

#include "../rand/include/file1.h"

#ifdef __cplusplus
extern "C" {
#endif

state_t * rstate(void);
extern state_t rngState;

#ifdef __cplusplus
};
#endif

and file2.cpp to this:

#include "file2.h"

state_t rngState;

state_t * rstate(void) {
   return &rngState;
}

it also has a seg fault in the test program.

Also,the seg fault occurs at location state->state[34] . When I try printing out state->state[34].u[0] for example.

Any ideas what is happening here?

TL;DR

Think about what this website is called...It's stack overflow!


I have spent almost one day to work out this problem. My codes have identical pattern like the OP's, requiring a static variable copied into a local variable.

The type of the problematic variable is defined using C but is used in a C++ routine. Therefore, it's possible that some incompatibilities between C and C++ cause such problem, which was also the first examination I did. However, I gave up because the C structure should be guaranteed to be trivial and standard layout that a memcpy() can operate.

Next movement was a stupid way that I checked every member of the structure to find out which was the villain. Using the idea of binary search, I quickly narrowed down to few of them, most of which were arrays with a large amount of number. This reminded me of stack overflow.

Compare the values between ulimit -s and sizeof() . Also if you have valgrind installed, try it. The output of valgrind may contain something like below

  • client switching stack SP xxx -> xxx
  • Access not within mapped region at address xxx

And you may even invoke dmesg and see something like segfault at xxx ip xxx sp xxx error 6 . The error 6 is explained in https://utcc.utoronto.ca/~cks/space/blog/linux/KernelSegfaultErrorCodes .

Back to valgrind, actually it gives a tip to use --main-stacksize= to temporarily increase your program's upper bound, which can be set to a large enough value to suppress stack problem. For me, then everything goes well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM