我怎么知道程序导致核心转储段错误的原因?

问题描述 投票:-1回答:1

我有这些功能,我想知道是否有人可以帮助我。我必须调查它们导致“段错误”的原因,以及为什么它根据其条件更快或更慢地发生。我认为在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
1个回答
2
投票

您拥有的代码很可能会触发我的体验错误。没有任何编译器或程序反馈,有点难以辨别出错误的原因,但我相信您可能正在寻找(通常)有关堆栈,堆和递归的信息。

首先,请注意

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个整数,这是堆栈PER递归的400个字节。毫不奇怪,它会在10,000到20,000次递归之间崩溃。没有足够的空间将数据存储在堆栈中。注意:对于您在问题中提到的内容,此tmp数组不会尝试分配相同的内存区域。由于这是递归构建的,因此它在该堆栈上为该函数实例创建了一个新空间。

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

我希望这一澄清有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.