Что вызывает ошибку сегментации (дамп ядра) в C? - PullRequest
2 голосов
/ 10 апреля 2019

Я пытаюсь написать программу с кодом Хемминга на C. Однако я продолжаю получать ошибку Segmentation Fault (Core Dumped) при попытке запустить ./a.out после компиляции.Он компилируется без ошибок, и я понимаю, что эта ошибка может возникать при попытке обратиться к свободному пространству или при изменении строкового литерала.Я не верю, что я делаю что-то из этого, у меня есть простая матрица, которую я заполняю и проверяю.Буду признателен за любую информацию по этому вопросу, я оставил ниже тот код, который у меня есть:

Это связано с домашней задачей, связанной с созданием программы с кодом Хемминга для обработки ввода и вывода data.dat в файл.отсортированный список из 1 и 0

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

FILE *fp;
FILE *fpOut;

int main(int argc, char *argv[])
{
        fp = fopen(argv[1], "r");
        fpOut = fopen("sortedCodeWords.dat", "w");

        int temp;
        int numI = 0;
        int count = 0;

        char matrix1[7];

        if(fp == NULL)
                printf("File can not be opened");
        else
        {
                char ch = getc(fp);

                while(ch != EOF)
                {

                        matrix1[2] = ch;
                        ch = getc(fp);

                        matrix1[4] = ch;
                        ch = getc(fp);

                        matrix1[5] = ch;
                        ch = getc(fp);

                        matrix1[6] = ch;
                        ch = getc(fp);

                        ch = getc(fp);

                        if(ch == '\n')
                        {
                                for(int i = 2; i < 7; i++)
                                {
                                        if(matrix1[i] == '1')
                                            numI++;

                                        i++;
                                }

                                if(numI % 2 == 0)
                                        matrix1[0] = 0;
                                else
                                        matrix1[0] = 1;

                                numI = 0;

                                for(int i = 1; i < 7; i++)
                                {
                                        if(matrix1[i] == '1')
                                                numI++;
                                        if(matrix1[i+1] == '1')
                                                numI++;

                                        i++;
                                        i++;
                                }

                                if(numI % 2 == 0)
                                        matrix1[1] = 0;
                                else
                                        matrix1[1] = 1;

                                numI = 0;

                                for(int i = 4; i < 7; i++)
                                {
                                        if(matrix1[i] == '1')
                                                numI++;
                                }

                                if(numI % 2 == 0)
                                        matrix1[3] = 0;
                                else
                                        matrix1[3] = 1;
                                numI = 0;

                                for (int i = 0; i < 7; i++)
                                {
                                        fprintf(fpOut, "%s", matrix1[i]);
                                }

                                fprintf(fpOut, "\n");

                                ch = getc(fp);
                        }

                        count++;
                }
        }
}

Я ожидаю вывод в файл.Я не всегда получал эту ошибку, но когда я перешел с 2D-массива на 1D-массив, я теперь получаю эту ошибку (я изменил, потому что понял, что в этом нет необходимости)

Ответы [ 4 ]

3 голосов
/ 10 апреля 2019

Я не скомпилировал его, но я заметил, что он выглядит так, как будто вы потенциально выходите из конца массива, где вы зацикливаетесь на i<7, но используете индекс i+1в одном случае.

Может быть, сборка с включенным AddressSanitizer и посмотреть, какие предупреждения во время выполнения вы получите после проверки потенциальной проблемы выше.(Это просто вопрос добавления следующих флагов к вашей команде gcc ... -g -fsanitize = address -fno-omit-frame-pointer

1 голос
/ 10 апреля 2019

Вы должны научиться пользоваться отладчиком.

Я рискну предположить, что вы здесь работаете над linux и пройдете процесс отладки своего кода.

Сначала мы компилируем с включенной отладочной информацией.

james@debian:~/code$ gcc foo.c -g

Теперь давайте рассмотрим два инструмента: valgrind и gdb


valgrind , в частности, является довольно хорошим инструментом, он ловит всякий раз, когда вы используете испорченную память. Это практически обязательно для отслеживания утечек памяти, но может быть использовано для многих ошибок Seg. Более того, он прост в использовании и не требует взаимодействия.

james@debian:~/code$ valgrind ./a.out foo.dat
==1857== Memcheck, a memory error detector
==1857== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1857== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==1857== Command: ./a.out foo.dat
==1857==
==1857== Conditional jump or move depends on uninitialised value(s)
==1857==    at 0x109381: main (foo.c:61)
==1857==
==1857== Invalid read of size 1
==1857==    at 0x4837C38: __GI_strlen (in /usr/lib/i386-linux-gnu/valgrind/vgpreload_memcheck-x86-linux.so)
==1857==    by 0x48A4786: vfprintf (vfprintf.c:1638)
==1857==    by 0x48AAC57: fprintf (fprintf.c:32)
==1857==    by 0x109437: main (foo.c:91)
==1857==  Address 0x1 is not stack'd, malloc'd or (recently) free'd
==1857==
==1857==
==1857== Process terminating with default action of signal 11 (SIGSEGV)
==1857==  Access not within mapped region at address 0x1
==1857==    at 0x4837C38: __GI_strlen (in /usr/lib/i386-linux-gnu/valgrind/vgpreload_memcheck-x86-linux.so)
==1857==    by 0x48A4786: vfprintf (vfprintf.c:1638)
==1857==    by 0x48AAC57: fprintf (fprintf.c:32)
==1857==    by 0x109437: main (foo.c:91)
==1857==  If you believe this happened as a result of a stack
==1857==  overflow in your program's main thread (unlikely but
==1857==  possible), you can try to increase the size of the
==1857==  main thread stack using the --main-stacksize= flag.
==1857==  The main thread stack size used in this run was 8388608.
==1857==
==1857== HEAP SUMMARY:
==1857==     in use at exit: 688 bytes in 2 blocks
==1857==   total heap usage: 3 allocs, 1 frees, 4,784 bytes allocated
==1857==
==1857== LEAK SUMMARY:
==1857==    definitely lost: 0 bytes in 0 blocks
==1857==    indirectly lost: 0 bytes in 0 blocks
==1857==      possibly lost: 0 bytes in 0 blocks
==1857==    still reachable: 688 bytes in 2 blocks
==1857==         suppressed: 0 bytes in 0 blocks
==1857== Rerun with --leak-check=full to see details of leaked memory
==1857==
==1857== For counts of detected and suppressed errors, rerun with: -v
==1857== Use --track-origins=yes to see where uninitialised values come from
==1857== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault

Просто читая первую ошибку, она отмечает проблему в строке 61, говоря, что if(matrix1[i] == '1') использует неинициализированную память.

Читая ваш код, помните, что matrix1[1] никогда не инициализируется, поэтому есть ошибка. Это не ошибка сегмента.

Еще одна ошибка отмечена в строке 91, которая выглядит как ошибка, но ее трудно понять. Итак, давайте уничтожим GDB.


james@debian:~/code$ gdb a.out
GNU gdb (Debian 8.2.1-2) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...done.
(gdb) run foo.dat
Starting program: /home/james/code/a.out foo.dat

Program received signal SIGSEGV, Segmentation fault.
__strlen_ia32 () at ../sysdeps/i386/i586/strlen.S:51
51      ../sysdeps/i386/i586/strlen.S: No such file or directory.

run foo.dat запускает программу. Мы быстро получим вашу ошибку сегментации с некоторой информацией.

(gdb) info stack
#0  __strlen_ia32 () at ../sysdeps/i386/i586/strlen.S:51
#1  0xb7e28787 in _IO_vfprintf_internal (s=0x4052c0, format=0x402037 "%s",
    ap=0xbffff52c "\360\021@") at vfprintf.c:1638
#2  0xb7e2ec58 in __fprintf (stream=0x4052c0, format=0x402037 "%s")
    at fprintf.c:32
#3  0x00401438 in main (argc=2, argv=0xbffff614) at foo.c:91
(gdb) frame 3
#3  0x00401438 in main (argc=2, argv=0xbffff614) at foo.c:91
91                          fprintf(fpOut, "%s", matrix1[i]);
(gdb)

info stack печатает стек выполнения. Мы не заботимся об ошибке на уровне системных файлов, мы заботимся об ошибке в main. frame 3 переключается на кадр № 3, где находится основная функция. На данный момент вы, возможно, уже видели ошибку, но мы можем копать глубже, если она не очевидна.

(gdb) info locals
i = 0
ch = 10 '\n'
temp = <optimized out>
numI = 0
count = 2
matrix1 = "\001\000\061\001\060\061\060"
(gdb)

info locals отображает все локальные переменные. На данный момент у нас есть довольно полный снимок того, что происходит, но только для того, чтобы объяснить это ...

(gdb) print matrix1[0]
$1 = 1 '\001'
(gdb)

В этот момент вы должны знать, что немного C. matrix[0] просто не подходит для printf("%s"). Он ожидает символьный указатель на какое-то значимое значение, но вы даете ему номер 1, что приводит к ошибке сегмента.

Оглядываясь назад на ошибку, которую мы получили от valgrind, теперь легче понять, сказав то же самое, что мы вывели, используя gdb: что мы пытались прочитать число 1 как адрес памяти ...

==1857==    by 0x109437: main (foo.c:91)
==1857==  Address 0x1 is not stack'd, malloc'd or (recently) free'd

Ваша программа по-прежнему будет иметь ошибки после того, как вы исправите это, я уверен, и будущие программы будут иметь похожие ошибки, но с помощью этих двух инструментов вы сможете отследить большинство проблем.

1 голос
/ 10 апреля 2019

Я вижу две вещи.Сначала вы смешиваете символы с целыми числами в матричном массиве.Во-вторых, вы печатаете элементы матрицы в файл, используя формат "% s"."% s" ожидает строку с нулевым символом в конце, когда вы передаете символы и целые числа.Это приведет к тому, что printf попытается получить доступ к памяти, находящейся за пределами допустимых границ, что приведет к ошибке.

0 голосов
/ 10 апреля 2019

Если вы хотите напечатать 1 и 0, вы должны назначить

matrix[i] = '1';

вместо

matrix[i] = 1;
...