web-dev-qa-db-ja.com

セグメンテーションフォルト(コアダンプ)がCで発生するのは何ですか?

ただし、。ただし、コンパイル後./a.outを実行しようとしたときに、セグメンテーションフォルト(コアダンプ)エラーが発生し続けています。それはエラーなしでコンパイルされています、そして私はこのエラーが解放されようとしたり、文字列リテラルを変更したりするときに発生する可能性があることを理解しています。私はそれらのことのどちらかをやっているとは思わない、私は単純な行列を持っています私は充填して交差チェックしています。問題に関する洞察が高く評価されるでしょう、私は私がこれまでに私が持っているコードを残しました:

これは、Data.dat入力を処理するハミングコードプログラムを作成することを含む宿題の問題です.1のソートリスト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配列に変更されたとき、私は今このエラーを得ています(私はそれが必要ではなかったことに気づいたので変えました)

3
V.Bean

私はそれをコンパイルしていませんが、私が気付くのは、i<7にループするが、1つのインスタンスでi+1のインデックスを使用している潜在的にあなたが潜在的に潜在的に発生する可能性があるように見えることです。

AddressSanitizerが有効になっている場合は、上記の潜在的な問題をチェックしたら、どのランタイムの警告を取得しても構いません。 (gccコマンドに次のフラグを追加することの問題があるはずです。-g -fsanitize = address-fno-out-framic-pointer

3
Gwyn Evans

デバッガの使い方を学ぶことができます。

私はあなたがここでLinuxで取り組んであなたがあなたのコードのためのデバッグプロセスを踏むことを想定してリスクを立てるつもりです。

まずDebug Info Enabledでコンパイルします。

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

今、2つのツールでそれを行こうとしましょうvalgrindgdb


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]が初期化されていないので、バグがあります。これはSEG障害ではありません。

もう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実行スタックを印刷します。システムファイルレベルでエラーを気にしないため、メインのエラーが発生します。 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)

この時点では、いくつか知っていなければなりません。matrix[0]printf("%s")の適切な引数ではありません。それは意味のある値を意味のあるものに指しているのを期待していますが、あなたはそれを数字1に与えていますが、それはSEG断層になります。

私たちがヴァルグランドから得たエラーを振り返って、それは私たちがgdbを使って推測したものと同じことを言って、私たちがメモリアドレスとして1を読みようとしていたのと同じことを理解しやすいです。

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

あなたのプログラムはこれを解決した後にエラーが発生し続けるでしょう。

1
QuestionC

1と0を印刷したい場合は、割り当て中です。

matrix[i] = '1';
 _

それ以外の

matrix[i] = 1;
 _
0