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/48123784/

相关文章:

c++ - 濒临UB - 服务器/客户端内存删除程序

检查一个数组是否在另一个数组内 - C 编程

c - SDL Audio - 只播放静态噪音

c - 为什么 select() 对收到的消息没有反应?

c++ - 临界区段错误 - 避免死锁

c - Vsnprintf 在我的嵌入式目标上因 NULL 而崩溃

c++ - 当不使用指针来跟踪当前节点时,为什么树遍历会导致未定义的行为?

c++ - 为什么 vector::clear 不从 vector 中删除元素?

c++ - union 的析构函数可以是微不足道的吗?

c - 指针的按位算术是否定义了行为?