【问题标题】:No segmentation fault with forkfork 没有分段错误
【发布时间】:2015-07-24 17:14:14
【问题描述】:

此代码导致分段错误:

int main(int argc, char *argv[]){
    int *n; 
    *n = atoi(argv[1]);
    printf("n: %d \n", *n);
    return 0;
}

虽然这有效:

int main(int argc, char *argv[]){
   int *n; 
   *n = atoi(argv[1]);
   pid_t pid = fork();
   if (pid == 0)
     return 0;
   else
     printf("n: %d \n", *n);
   return 0;
}

为什么用叉子的第二个有效?我知道在int *n 之后,我应该为intmalloc() 分配空间,但使用fork() 似乎会自动执行此操作。

编辑: 现在我了解未定义的行为:) 但现在我要问:这个具体案例的原因是什么?

【问题讨论】:

  • 未定义的行为是未定义的;任何事情都可能发生,结果是合法的。不要调用未定义的行为。
  • “曾经有人告诉我,在篮球运动中你不能拿着球跑。我拿了一个篮球试了一下,效果很好。他显然不懂篮球。”——罗杰米勒关于未定义的行为

标签: c segmentation-fault fork


【解决方案1】:

它不起作用。 (或者更准确地说,你有未定义的行为)

1)fork只是隐藏了segfault,因为你没有检查子进程的退出代码。

2) 内存分配不是自动的——永远不会!

您只是在写入一个随机位置,而您可能只是“幸运”在第二个版本中随机位置位于您的进程空间内。

【讨论】:

  • 或者它确实“工作”(通过不崩溃的方式),但由于它是 UB,它可以做任何事情..
  • @joumvaer92 -- 这只是“随机”的运气 -- 您在进程空间中损坏了某些东西 -- 它没有导致崩溃只是“幸运的”。
  • @joumvaer92:你很不幸(或幸运)它产生了“正确”的输出。但是零保证您会得到正确的答案,因为您的代码正在调用未定义的行为。
  • @joumvaer92:这表明您的系统是自洽的——仅此而已。无法保证您会在另一个系统上获得该行为,或者在系统上使用不同的编译器,或者当前编译器的不同版本,或者使用不同的编译器选项和当前编译器,或者在进程环境中使用不同的值,或者……它连续工作 100 次是 100% 不确定的。这就是未定义行为的(美丽?)可怕的危险;看起来有效是一种好的未定义行为,但不能保证它看起来有效。
  • 为什么分叉隐藏了段错误?
【解决方案2】:

您的代码 sn-ps 都调用 undefined behaviour,礼貌,

  1. 使用未初始化和无效内存*n
  2. (可能)使用未初始化且无效的内存argv[1](如果argc 不是>=2

分段错误是 UB 的众多副作用之一。 UB 案例也包括无缝工作场景。

为什么第二个用叉子有效?

这与fork() UB 的存在(或不存在)无关。 TL;DR.

但使用 fork() 似乎会自动执行此操作。

视觉效果可能具有欺骗性。不要把钱放在 UB 上。

【讨论】:

    【解决方案3】:

    因为n 未初始化并因此指向未知的内存地址,所以您正在调用未定义的行为。它可能会崩溃(如第一个示例),也可能不会崩溃(如第二个示例)。

    在这种情况下,像添加一个未使用的变量这样简单的事情可能会导致程序以前没有崩溃,反之亦然。

    n分配内存,你就不会有这个问题了。

    编辑:

    无论运行多少次,运行./test 100 都能正常运行第二个程序,这是一个运气问题。您添加了对fork(在这种情况下)的调用这一事实恰好重新安排了内存的布局方式,以便它可以工作。稍后您可能决定致电printf 进行额外调试,但突然之间它又开始崩溃了。

    添加fork 调用不会自动分配任何空间。

    防止崩溃的唯一方法是为n 分配内存,并确保argc 至少为2,以便argv[1] 指向有意义的地方。

    【讨论】:

      【解决方案4】:

      碰巧你在运行 fork 并返回 0 时看不到段错误,你的代码永远不会运行 printf ("% d", *n)

      当你试图访问一个不允许的内存位置时会出现分段错误,所以解决方法是通过malloc或calloc函数分配ana内存,否则仍然有问题。 试试这个:

       n=malloc(sizeof(int));
       *n=atoi(argv[1]);
      

      问候

      【讨论】:

      • 不应该是*n=atoi(argv[1]);吗?
      • 这意味着您要将atoi 的返回值分配给n 指向的内容,即*n。否则,您将覆盖 malloc 的返回值。
      • @dbush 没看懂你的意思,谢谢指正
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-20
      • 2012-01-27
      • 2022-07-01
      • 1970-01-01
      • 2018-12-08
      • 1970-01-01
      相关资源
      最近更新 更多