无效的读/写有时会产生分段错误,有时则不会

Jee*_*tel 2 c linux segmentation-fault

示例代码:

int main ()
{
  char b[] = {"abcd"};
  char *c = NULL;
  printf("\nsize: %d\n",sizeof(b));
  c = (char *)malloc(sizeof(char) * 3);
  memcpy(c,b,10);   // here invalid read and invalid write
  printf("\nb: %s\n",b);
  printf("\nc: %s\n",c);

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

在代码中看到我做了一些无效读取和无效写入,但这个小程序工作正常,并没有创建core dump.

但是一旦进入我的大型库,每当我进行1个字节的无效读取或无效写入时,它总是创建核心转储.

题:

为什么我有时会从无效的读/写中获取核心转储,有时无法获得核心转储?

Dan*_*ego 6

当您执行无效的读/写操作时,它完全取决于您覆盖或取消引用的内容.具体来说,如果你要覆盖一些被解除引用的指针,比如说,一个指针中最重要的一个字节,你可能最终得到的东西被解除引用到一个完全不同(并且完全无效)的内存区域.

因此,例如,如果堆栈的排列使得memcpy超过结尾c将覆盖部分b,当您尝试作为参数调用printf()b,它会尝试获取该指针并取消引用它以打印字符串.由于它不再是有效指针,因此会导致段错误.但是,由于堆栈排列之类的东西是平台(也许是编译器?)依赖,所以在不同的程序中,您可能看不到与相似示例相同的行为.


ano*_*ard 5

您要做的是基本上缓冲区溢出和代码示例中更具体的堆溢出.您有时只看到崩溃的原因取决于您访问的内存区域以及您是否有权访问/写入(Dan Fego已经很好地解释了这一点).我认为Dan Fego提供的例子更多的是关于堆栈溢出(更正欢迎!).gcc具有与堆栈缓冲区溢出相关的保护(堆栈粉碎).您可以在以下示例中看到此(基于堆栈的溢出):

#include <stdio.h>
#include <string.h>

int main (void)
{
    char b[] = { "abcdefghijk"};
    char c [8];
    memcpy (c, b, sizeof c + 1);      // here invalid read and invalid write
    printf ("\nsize: %d\n", sizeof b); 
    printf ("\nc: %s\n", c); 
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

样本输出:

$ ./a.out 

size: 12

c: abcdefghi???
*** stack smashing detected ***: ./a.out terminated
Run Code Online (Sandbox Code Playgroud)

可以使用-fno-stack-protectorgcc中的选项禁用此保护.
缓冲区溢出是安全漏洞的主要原因之一.不幸的是,功能就像memcpy不检查这些问题,但有办法防止这些问题.
希望这可以帮助!