首页 > 解决方案 > 我怎么知道程序为什么会导致 coredump sigfault?

问题描述

我有这些功能,我想知道是否有人可以帮助我。我必须调查它们为什么会导致“段错误”,以及为什么它会根据其条件发生得更快或更慢。我认为在 Rec1 中,它是由一个无限循环导致内存堆栈的内存崩溃的。在 rec2 中,我认为它的速度更快,因为与 Rec1 中的条件相同,但添加它每次都为指针分配内存。在 Rec3 () 中,它会立即崩溃,因为它在第二次迭代中分配了相同的内存点,并且由于程序试图访问相同的分配内存而导致问题。在 Rec4() 我认为这是因为它创建了一个具有无限位置的数组,问的是数组最大空间的限制。你能给我一些关于这些假设的建议吗?

#include <stdio.h>
#include <stdlib.h>

#define MOD 10000

int k = 0;

char global[100];

void
panic (char *m)
{
  fprintf (stderr, "%s\n", m);
  exit (0);
}

void
rec1 ()
{
  k++;
  if (k % MOD == 0)
    fprintf (stderr, "%d ", k / MOD);
  rec1 ();
}

void
rec2 ()
{
  int *tmp;

  tmp = malloc (100 * sizeof (int));
  if (tmp == NULL)
    exit (0);

  k++;
  if (k % MOD == 0)
    fprintf (stderr, "%d ", k / MOD);
  rec2 ();
}

void
rec3 ()
{
  int tmp[100];

  k++;
  if (k % MOD == 0)
    fprintf (stderr, "%d ", k / MOD);
  rec3 ();
}

void
rec4 ()
{
  global[k] = k;
  if (k % 200 == 0)
    fprintf (stderr, "%d ", k);
  k++;
  rec4 ();
}

int
main (int argc, char *argv[])
{
  int mode = 1;
  if (argc > 1)
    mode = atoi (argv[1]);

  printf ("Testing rec%d...\n", mode);
  switch (mode)
    {
    case 1:
      rec1 ();
      break;
    case 2:
      rec2 ();
      break;
    case 3:
      rec3 ();
      break;
    case 4:
      rec4 ();
      break;
    default:
      panic ("Wrong mode");
    }

  return 0;
}

这是我在终端中运行编译后的 C 程序时的输出。

Testing rec1...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554904 in rec1 () at stack.c:24
24    rec1 ();

Testing rec2...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a7b96a in __GI___libc_free (mem=0x555555757670) at malloc.c:3086
3086    malloc.c: No existe el archivo o el directorio.

Testing rec3...
1 
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554a43 in rec3 () at stack.c:53
53    rec3 ();

Testing rec4...
0 200 400 600 800 1000 1200 1400 1600 1800 2000 2200 2400 2600 2800 3000 3200 3400 3600 3800 4000 Violación de segmento (`core' generado)
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554a1f in rec4 ()

标签: c

解决方案


根据我的经验,您拥有的代码很可能会引发错误。在没有任何编译器或程序反馈的情况下,很难准确判断出了什么问题,但我相信您可能正在(通常)寻找有关堆栈、堆和递归的信息。

首先,请注意

void rec1 ()  {
     k++;
     if (k % MOD == 0)
        fprintf (stderr, "%d ", k / MOD);

     rec1 ();
}

不是“迭代”。迭代是指重复代码的顺序部分(通常是一个forwhile循环)。您在这里拥有的是递归递归创建要操作的方法的新实例,以及用于导航到最后一个执行点的堆栈指针(以及存储任何直接相关的变量)。每次rec1 ()从函数调用函数时都会发生这种情况rec1 ()最终,您将用完堆栈上的空间来存储这些指针。在现代计算机上,您可以在堆栈中存储的指针数量通常非常多,但考虑到您没有return声明,你最终会遇到最大容量。

编辑

这篇文章已经过编辑,以反映问题提出的新材料。

好的...从您提供的材料看来,您实际上是被问到每个rec存储和处理信息的位置...

在 的情况下Rec1,它确实似乎是一个简单的堆栈溢出情况。指向前一个 Rec1 的最后一个执行点的指针存储在堆栈上,最终导致程序在大约 520,000 个实例后崩溃。鉴于每个指针是 4 个字节,在堆栈溢出之前,它仅存储在堆栈中大约 2 MB 的递归指针信息,并触发 Seg Fault。

第二种情况有点棘手。请注意,您的程序表明它在触发 Seg Fault 之前会进行大约 260,000 次递归。这正好是 Rec1 的一半。但是,这本身不一定是堆栈溢出。Rec2 每次递归在堆上分配 400 字节的数据。指向堆的指针存储在堆栈中,这意味着每次递归将 8 个字节存储在堆栈中(这可能与为什么它恰好是一半有关,但也可以通过堆栈/堆大小的比率来解释)。现在,Rec2 的错误表明malloc找不到文件或目录,这在我看来好像 malloc 无法正确完成。这实际上可能表明已达到最大堆大小。

Rec3很简单。每次递归时,整个整数数组 tmp 都存储在堆栈中。这是每个整数 4 个字节乘以 100 个整数,即每次递归堆栈上的 400 个字节。它在 10,000 到 20,000 次递归之间崩溃也就不足为奇了。只是没有足够的空间将数据存储在堆栈上。注意:关于您在问题中提到的内容,此 tmp 数组不会尝试分配相同的内存区域。由于这是递归构建的,因此它会在堆栈上为该函数实例创建一个新空间。

Rec4是缓冲区溢出的简单情况。在覆盖分配的前 100 字节内存之后,它会导致指向仅限于进程的地址空间global[100],只是时间问题。这在大约 4000 次递归后触发了 seg 错误(k 不是 mod 10,000 in )。k++global[k]rec4

我希望这个澄清会有所帮助。


推荐阅读