Как я могу знать, почему программа вызывает sigfault coredump? - PullRequest
0 голосов
/ 28 марта 2019

У меня есть эти функции, и я хотел бы знать, может ли кто-нибудь мне помочь.Я должен выяснить, почему они вызывают "сегфо", и почему это происходит быстрее или медленнее в зависимости от его условий.Я предположил, что в Rec1 это вызвано бесконечным циклом, который разрушает память стека памяти.Я полагаю, что в rec2 он вызывается быстрее из-за того же условия, что и в Rec1, но добавляет, что он также выделяет память каждый раз для указателя.В Rec3 () происходит сбой мгновенно, потому что он выделяет ту же область памяти во второй итерации, и вызывает проблему, потому что программа пытается получить доступ к той же выделенной памяти.В Rec4 () я думаю, что это вызвано тем, что он создает массив с бесконечными позициями, ask - ограничение максимального пространства массива.Можете ли вы дать мне несколько советов по этим предположениям?

#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 ()

1 Ответ

2 голосов
/ 28 марта 2019

Код, который у вас есть, может привести к ошибке в моем опыте.Без обратной связи от компилятора или программы немного трудно определить, что именно пошло не так, но я полагаю, что вы, возможно, ищете (как правило) информацию о стеках, кучах и рекурсии.

Во-первых, обратите внимание, что

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

     rec1 ();
}

- это НЕ"Итерация". Итерация относится к повторению последовательной части кода (обычно цикл for или while).Здесь у вас есть рекурсия . Рекурсия создает новый экземпляр метода для работы вместе с указателем стека для перехода к последней точке выполнения (а также для хранения любых непосредственно релевантных переменных).Это происходит каждый раз, когда вы вызываете функцию rec1 () из функции rec1 () В конце концов, вам не хватит места в стеке для хранения этих указателей.Количество указателей, которые вы можете хранить в стеке, обычно достаточно велико на современных компьютерах, но, учитывая, что у вас нет оператора return, вы в конечном итоге получите максимальную емкость.

РЕДАКТИРОВАТЬ

Это сообщение было отредактировано, чтобы отразить новый материал, представленный вопросом.

Хорошо ... Из материала, который вы представили,похоже, что вас по существу спрашивают, ГДЕ каждый rec хранит и обрабатывает информацию ...

В случае Rec1 это действительно простой случай переполнения стека.Указатель на последнюю точку выполнения предыдущего Rec1 сохраняется в стеке, что в конечном итоге приводит к падению программы после примерно 520 000 экземпляров.Учитывая, что каждый указатель составляет 4 байта, это примерно 2 МБ только одной информации рекурсивного указателя, хранящейся в вашем стеке до того, как он разрушится и вызовет сбой сегмента из-за переполнения стека.

Второй случай немного сложнее.Обратите внимание, что ваша программа указывает, что она делает примерно 260 000 рекурсий, прежде чем вызовет сбой сегмента.Это ровно половина Rec1. ОДНАКО , это не обязательно переполнение стека как таковое.Rec2 выделяет 400 байтов данных в куче за рекурсию.Указатель на кучу хранится в стеке, это означает, что в рекурсии в стеке хранится 8 байтов (что может быть связано с тем, почему именно его половина, но также может быть объяснено отношением вашего стекаразмер кучи).Теперь ошибка для Rec2 гласит, что malloc не может найти файл или каталог, что мне кажется, что malloc не может завершиться правильно.Это может фактически указывать на то, что максимальный размер кучи был достигнут.

Rec3 довольно просто.Весь целочисленный массив tmp хранится в стеке для каждой рекурсии.это 4 байта на целое число, умноженное на 100, что составляет 400 байтов в рекурсии стека.Неудивительно, что происходит сбой от 10 000 до 20 000 рекурсий.Просто не хватило места для хранения данных в стеке. ПРИМЕЧАНИЕ : В связи с тем, что вы упомянули в своем вопросе, этот массив tmp не пытается выделить ту же область памяти.Из-за того, что это рекурсивно, это создает новое пространство в стеке для этого экземпляра функции.

Rec4 - простой случай переполнения буфера.После перезаписи первых 100 байтов памяти, выделенной в global[100],, было только вопросом времени, когда k++ заставит global[k] указать на адресное пространство, ограниченное процессом.Это вызвало ошибку сегмента после примерно 4000 рекурсий (k не было модом 10 000 в rec4).

Надеюсь, это разъяснение поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...