c - 为什么访问非法指针的程序不会崩溃?

标签 c undefined-behavior

访问非法指针的程序不会因 SIGSEGV 而崩溃。这不是一件好事,但我想知道这是怎么回事,以及这个过程是如何在生产中存活许多天的。这让我感到困惑。

我已经在 Windows、Linux、OpenVMS 和 Mac OS 中试用了这个程序,他们从未提示过。

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

void printx(void *rec) { // I know this should have been a **
    char str[1000];
    memcpy(str, rec, 1000);
    printf("%*.s\n", 1000, str);
    printf("Whoa..!! I have not crashed yet :-P");
}

int main(int argc, char **argv) {
    void *x = 0; // you could also say void *x = (void *)10;
    printx(&x);
}

最佳答案

我对缺少内存故障并不感到惊讶。该程序取消引用未初始化的指针。相反,它复制并打印从指针变量开始的内存内容,以及超出它的 996(或 992)字节。

由于指针是一个堆栈变量,它正在打印靠近堆栈顶部的内存以向下打印。该内存包含 main() 的堆栈帧:可能是一些已保存的寄存器值、程序参数的计数、指向程序参数的指针、指向环境变量列表的指针以及已保存的指令注册 main() 返回,通常在 C 运行时库启动代码中。在我研究过的所有实现中,下面的堆栈帧都有环境变量本身的副本、指向它们的指针数组和指向程序参数的指针数组。在 Unix 环境(您暗示您正在使用)中,程序参数字符串将在该环境下。

所有这些内存都可以“安全”打印,除了会出现一些不可打印的字符,这可能会弄乱显示终端。

主要的潜在问题是是否分配和映射了足够的堆栈内存以防止在访问期间出现 SIGSEGV。如果环境数据太少,可能会发生段错误。或者,如果实现将该数据放在别处,那么这里只有几个字的堆栈。我建议通过清除环境变量并重新运行程序来确认这一点。

如果任何 C 运行时约定不正确,这段代码就不会那么无害:

  • 架构使用堆栈
  • 在栈上分配了一个局部变量(void *x)
  • 堆栈向较低编号的内存方向增长
  • 参数在栈上传递
  • main() 是否带参数调用。 (一些轻型环境,如嵌入式处理器,调用 main() 时不带参数。)

在所有主流的现代实现中,所有这些通常都是正确的。

关于c - 为什么访问非法指针的程序不会崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17852212/

相关文章:

c++ - 为什么取消引用空指针是未定义的行为?

c++ - 我=我++;未定义。 i = foo(i++) 是否也未定义?

c - 从 'char *' 分配到 'int' 的指针转换不兼容的整数

c# - 使用新屏幕的控制台应用程序

在C中计算两个数字的GCD

c - 优化 C 中大文件的 I/O

c++ - Project70.exe : 0xC0000005: Access violation writing location 0xDDDDDDDD 中的 0x0F4D514F (vcruntime140d.dll) 抛出异常

c - 通过套接字发送哈希表的内容

c - 签名右移 = 奇怪的结果?

c++ - 读取与事件成员类型相同的非事件联盟成员是否定义明确?