【问题标题】:pointer segfault vs undefined behavior指针段错误与未定义的行为
【发布时间】:2016-11-13 04:19:47
【问题描述】:

如果我添加命令行参数或注释掉调用cpy 函数,为什么此代码在定期运行时会产生段错误,但未定义行为而不是段错误?

#include <cstdlib>
#include <iostream>
#include <cstring>
using namespace std;

int *p;

void fn() {
    int n[1];
    n[0]=99;
    p = n;

}

void cpy(char *v) {
    char x[8];
    strncpy(x,v,8);
}

int main(int argc, char** argv) {
    fn();
    cpy(argv[1]);
    cout << "p[0]:" << p[0];
}

我知道n 是函数fn 的本地变量,但是有没有办法让缓冲区溢出或输入argv[1] 的内容以使其打印n 从任何地方保存的值它在/曾经在内存中吗?

【问题讨论】:

  • 未定义的行为?如果添加命令行参数,它会存储在 argv[1] 中。如果你注释掉 cpy() 行,你就没有在任何地方使用 argv[1],这就是导致段错误的原因。
  • 但是为什么不使用argv[1] 会导致段错误?我的意思是未定义的行为打印p 的索引,它指向一个超出范围的变量。
  • 等等,就像不提供命令行参数,或者不使用变量 argv[1]?
  • 嗯,是的,为什么添加命令行 arg 使得尝试打印空指针不再导致段错误?我不知道argv 对打印指针有何影响。
  • 它没有。尝试访问 argv[1] 时,在尝试打印指针之前发生段错误。

标签: c++ segmentation-fault undefined-behavior buffer-overflow


【解决方案1】:

如果你不传递参数,那么argv[1]==nullptr。然后cpy(argv[1])cpy(nullptr) 并且cpy 调用strncpy(x,nullptr,8) 和segfaults。

如果你注释掉cpy,那么没有段错误。

如果你传递一个参数,那么 cpy 就不会出现段错误。但是你会遇到一个不同的问题:fn 做了p=n,但是 n 被声明在堆栈上,所以回到 cout&lt;&lt;p[0] 的 main 中,p 指向不再存在的对象 n,所以行为是未定义的。

【讨论】:

  • 感谢这解释了我 95% 的困惑。碰巧知道一种方法来操纵输入以使其打印出num 所在位置的数据(如果它没有被覆盖)?
  • 当你说num是指在fn中声明的n[]?您需要在 fn 返回之前打印它,或者在 fn 返回之前将其保存在其他地方。
  • 是的,对不起n[] 我基本上是想在不更改代码的情况下让 main 打印出99
  • 您需要在调用 cpy() 之前执行此操作(假设您仍然如此),因为它将在该函数中被覆盖。通过注释掉对 cpy 的调用,或将其移动到您的 cout 语句下方,将打印出 99。
  • 那行不通。但这似乎是:g++ -O3 foo.cpp &amp;&amp; ./a.out c(字母 c 的 ascii 值为 99)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-26
  • 1970-01-01
  • 1970-01-01
  • 2018-07-03
  • 1970-01-01
  • 1970-01-01
  • 2013-07-09
相关资源
最近更新 更多