在memcopy上的段错误,也可以在这个代码中解释C语法



我正在尝试调试一段由其他人编写的代码,该代码有时会导致段错误,但不是所有时间,在内存操作期间。

另外,如果有人能帮助我翻译内存内存之前的一段代码,我将非常感激。

首先,我们有一个函数,其中传递了一个void指针和一个指向结构体的指针,如下所示:

  void ExampleFunction(void *dest, StuffStruct *buf)

结构体看起来像这样:

typedef struct {
   char *stuff;
   unsigned int totalStuff;
   unsigned int stuffSize;
   unsigned int validStuff;
} StuffStruct;

返回到ExampleFunction。在ExampleFunction内部,这是发生的:

void *src;
int numStuff;
numStuff = buf->validStuff;
src = (void *)(buf->stuff);

我被上面的行弄糊涂了。当buf->stuff中的字符数组被转换为空指针,然后设置为src的值时,究竟会发生什么?我不知道这一步应该怎么走。

在此之后,内存发生:

memcpy(dest, src, buf->bufSize*numStuff)

这就是段故障经常发生的地方。我已经检查了dest/src为空,也不是空的。

另外,在调用ExampleFunction的函数中,dest的数组被声明为5000的大小,如果有必要的话。然而,当我在上面的代码中打印buf->bufSize*numStuff中的值时,这个值通常高于5000——它可以高达80000——但是没有出现分段错误。也就是说,当长度变量(但是->bufSize*numStuff)远高于dest变量初始化时的假定长度时,它可以正常运行。然而,也许这并不重要,因为它被转换为一个空指针?

由于各种原因,我无法使用dbg或安装IDE。我只是在使用基本的打印调试。有人能给我提点建议吗?

首先,强制转换和赋值操作只是将buf->stuff的地址复制到指针src中。这里没有魔法。

numStuff = buf->validStuff;
src = (void *)(buf->stuff);

如果dest只有足够的5000字节的存储空间,并且您试图写入超出该长度的内容,那么您正在损坏程序堆栈,这可能导致在副本上或有时稍后出现段故障。是否强制转换为void指针没有任何区别。

memcpy(dest, src, buf->bufSize*numStuff)

我认为你需要弄清楚到底什么buf->bufSize*numStuff应该是计算,要么修复它,如果它是不正确的(不打算),截断复制到目标的大小,或增加目标数组的大小。

空指针解引用并不是导致段错误的唯一原因。当你的程序分配内存时,当你试图访问在你分配的内存区域之后的内存时,也有可能触发段错误。

您的代码看起来像是打算将buf->stuff指向的缓冲区的内容复制到目标缓冲区。如果这些缓冲区中的任何一个小于memcpy操作的大小,则memcpy可能会超出已分配内存的界限并触发段错误。

因为内存分配器在大块中分配内存,然后将其分配给对malloc的各种调用,所以您的代码不会在每次运行超过malloc缓冲区的末尾时始终失败。您将得到您所描述的零星故障行为。

这段代码中的假设是,buf->stuff指向的缓冲区和dest指针指向的缓冲区的长度至少为"buf->bufSize * numStuff"字节。这两个假设有一个是错误的。

我建议以下几种方法:

  1. 检查分配由dest指向的缓冲区和由buf->stuff指向的缓冲区的代码,并确保它们总是等于或大于buf->bufSize * numStuff。

  2. 如果做不到这一点,有很多工具可以帮助您从程序中获得更好的诊断信息。使用最简单的是篱笆("Electric Fence"),它将帮助识别代码中超出缓冲区的地方。(http://linux.die.net/man/3/efence)。可以使用valgrind (http://valgrind.org/)进行更彻底的分析,但是valgrind使用起来有点复杂。

祝你好运!

p。将char*指针转换为void*指针没有什么特别之处——它仍然只是一个分配的内存块的地址。

最新更新