关于memcopy的Segfault,也可以解释这段代码中的C语法吗?

时间:2014-06-25 00:02:21

标签: c segmentation-fault memcpy void-pointers

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

另外,如果有人能帮我翻译memcpy之前发生的代码,我会非常感激。

首先,我们有一个函数,其中传递一个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中的char数组被转换为void指针,然后设置为src的值时,会发生什么?我无法追随该步骤应该发生的事情。

在此之后,memcpy发生了:

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

这就是经常发生段错误的地方。我已经检查了dest / src为null,都不是null。

此外,在调用ExampleFunction的函数中,如果重要,则声明dest的数组的大小为5000。但是,当我在上面的代码中打印buf-> bufSize * numStuff中的值时,该值通常高于5000 - 它可以高达80,000 - 尽管没有segfaulting。也就是说,它运行良好,长度变量(buf->; bufSize * numStuff)远远高于dest变量初始化的假设长度。但是,也许这无关紧要,因为它被转换为无效指针?

由于各种原因,我无法使用dbg或安装IDE。我只是使用基本的printf调试。有没有人有我可以探索的想法?提前谢谢。

2 个答案:

答案 0 :(得分:0)

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

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

如果dest只有5000个字节的足够存储空间,并且您尝试写入超过该长度的存储空间,那么您会损坏您的程序堆栈,这会导致在副本上或有时稍晚的段错误。无论你是否转换为无效指针都没有任何区别。

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

我认为你需要确切地知道buf->bufSize*numStuff应该计算什么,如果它不正确(不打算),要么修复它,要么将副本截断到目标的大小,要么增加目标数组。

答案 1 :(得分:0)

空指针解除引用不是导致段错误的唯一因素。当程序分配内存时,当您尝试访问 已分配的内存区域后,也可能触发段错误。

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

因为内存分配器以大块分配内存,然后将其分解为对malloc的各种调用,所以每次运行malloc的缓冲区结束时,代码都不会一直失败。您将完全了解您描述的零星故障行为。

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

我建议采用几种方法:

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

  2. 如果做不到这一点,有很多工具可以帮助您从程序中获得更好的诊断信息。最简单的用法是efence(“电围栏”),它有助于识别代码中超出任何缓冲区的位置。 (http://linux.die.net/man/3/efence)。使用valgrind(http://valgrind.org/)可以进行更彻底的分析 - 但是Valgrind使用起来要多得多。

  3. 祝你好运!

    PS。将一个char *指针转换为void *指针没什么特别的 - 它仍然只是一个已分配的内存块的地址。