memcpy局部静态变量时出现分段错误

Segmentation fault when memcpy local static variable

本文关键字:分段 错误 局部 静态 变量 memcpy      更新时间:2023-10-16

我遇到了一个分段错误,但我不清楚原因。我遗漏了一堆东西(希望没什么重要的)。有趣的是,它运行良好,在valgrind中进行了全面的泄漏检查,没有错误。以下是所有信息(我正在使用我在网上找到的代码开发随机数生成器):

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

使用以下命令将其编译为静态库:

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;
}

使用以下命令(省略了一些内容)将文件2编译到一个静态库中(来自cmake,运行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

然后我在这个小测试程序test.cpp:中测试所有内容

#include "file2.h"
#include <cstring>
int main(void) 
{
state_t * state = rstate();
state_t save;
memcpy(&save, state, sizeof(save)); //segmentation fault
}

我用以下命令构建(省略了内容):

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

如果我把test.cpp改为这个,它会很好地工作:

#include "file2.h"
#include <cstring>
int main(void) 
{
state_t * state = new state_t();
state = rstate();
state_t save;
memcpy(&save, state, sizeof(save));
}

或者,如果我不使用test.cpp,而是将file2.h更改为:

#include "../rand/include/file1.h"
#ifdef __cplusplus
extern "C" {
#endif
state_t * rstate(void);
state_t rngState;
#ifdef __cplusplus
};
#endif

并将file2.cpp更改为:

#include "file2.h"
state_t * rstate(void) {
return &rngState;
}

程序也能正常运行。最后,如果我将file2.h更改为:

#include "../rand/include/file1.h"
#ifdef __cplusplus
extern "C" {
#endif
state_t * rstate(void);
extern state_t rngState;
#ifdef __cplusplus
};
#endif

和file2.cpp到此:

#include "file2.h"
state_t rngState;
state_t * rstate(void) {
return &rngState;
}

它在测试程序中也存在seg故障。

此外,seg故障发生在位置state->state[34]。例如,当我尝试打印state->state[34].u[0]时。

你知道这里发生了什么吗?

TL;博士

想想这个网站叫什么。。。这是堆栈溢出!


我花了将近一天的时间来解决这个问题。我的代码具有与OP相同的模式,需要将静态变量复制到局部变量中。

问题变量的类型是使用C定义的,但在C++例程中使用。因此,可能是C和C++之间的一些不兼容导致了这样的问题,这也是我做的第一次检查。然而,我放弃了,因为C结构应该保证是memcpy()可以操作的琐碎和标准布局。

下一个动作是一种愚蠢的方式,我检查了结构的每一个成员,找出哪个是恶棍。使用二进制搜索的思想,我很快将范围缩小到其中的几个,其中大多数是具有大量数字的数组。这让我想起了堆栈溢出。

比较ulimit -ssizeof()之间的值。同样,如果你安装了valgrind,试试看。valgrind的输出可能包含以下

  • 客户端交换堆栈SP xxx->xxx
  • 访问不在地址xxx的映射区域内

您甚至可以调用dmesg并看到类似segfault at xxx ip xxx sp xxx error 6的内容。error 6在https://utcc.utoronto.ca/~cks/space/blog/linux/KernelSefaultErrorCodes。

回到valgrind,实际上它提供了一个使用--main-stacksize=来临时增加程序上限的提示,该上限可以设置为足够大的值来抑制堆栈问题。对我来说,一切都很顺利。