3

私のコードは次のようなものです:

int find_test(int argc, char *argv[])
{
    char line[MAX_LINES];
    int c, except = 0, found = 0, number = 0;
    long lineno = 0;
    int i = 0;

    while(--argc > 0 && (*++argv)[0] == '-'){
        while(c = *++argv[0]){
            switch(c){
                case 'x':
                    except = 1;
                    break;
                case 'n':
                    number = 1;
                    break;
                default:
                    printf("find:illegal option %c\n", c);
                    argc = 0;
                    found = -1;
                    break;
            }
        }
    }
    if(argc != 1){
        printf("Usage:find -x -n pattern\n");
    }else{
        while(getline(line, MAX_LENGTH) > 0){
            lineno++;
            if((strstr(line, *argv) != NULL) != except){
                if(number)
                    printf("%ld:", lineno);
                printf("%s\n", line);
                found++;
            }
        }
    }
    return found;
}

getlineこのような:

int getline(char *line, int maxline)
{
    char *p = line;
    int c;

    while(maxline-- && (c = getchar()) != EOF && c != '\n'){
        *line++ = c;
    }
    if(maxline > 0)
        *line = '\0';

    return line - p;
}

を使用gcc -Wall -O2 -g a.c -o a.outして実行するa.out -x -n 111<find_testと、find_testテストデータは次のようになります。

line1:111111111111111
line2:222222222222222
line3:222222222222222
line4:444444444444444
line2:kasdskskdk

エラーメッセージが表示されました:

*** stack smashing detected ***: ./a.out terminated
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x48)[0xb7ead138]
/lib/tls/i686/cmov/libc.so.6(__fortify_fail+0x0)[0xb7ead0f0]
./a.out[0x8048e95]
./a.out[0x8048ec2]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe0)[0xb7dd6450]
./a.out[0x8048641]
======= Memory map: ========
08048000-0804a000 r-xp 00000000 08:08 17488      /home/jyc/prgm/the_c_p_l/a.out
0804a000-0804b000 rw-p 00001000 08:08 17488      /home/jyc/prgm/the_c_p_l/a.out
0804b000-0806c000 rw-p 0804b000 00:00 0          [heap]
b7dbf000-b7dc0000 rw-p b7dbf000 00:00 0 
b7dc0000-b7f09000 r-xp 00000000 08:08 694644     /lib/tls/i686/cmov/libc-2.7.so
b7f09000-b7f0a000 r--p 00149000 08:08 694644     /lib/tls/i686/cmov/libc-2.7.so
b7f0a000-b7f0c000 rw-p 0014a000 08:08 694644     /lib/tls/i686/cmov/libc-2.7.so
b7f0c000-b7f0f000 rw-p b7f0c000 00:00 0 
b7f0f000-b7f32000 r-xp 00000000 08:08 694648     /lib/tls/i686/cmov/libm-2.7.so
b7f32000-b7f34000 rw-p 00023000 08:08 694648     /lib/tls/i686/cmov/libm-2.7.so
b7f3a000-b7f44000 r-xp 00000000 08:08 677855     /lib/libgcc_s.so.1
b7f44000-b7f45000 rw-p 0000a000 08:08 677855     /lib/libgcc_s.so.1
b7f45000-b7f49000 rw-p b7f45000 00:00 0 
b7f49000-b7f4a000 r-xp b7f49000 00:00 0          [vdso]
b7f4a000-b7f64000 r-xp 00000000 08:08 678556     /lib/ld-2.7.so
b7f64000-b7f66000 rw-p 00019000 08:08 678556     /lib/ld-2.7.so
bfa26000-bfa3b000 rw-p bffeb000 00:00 0          [stack]

しかし、私が使用gcc -Wall -O2 -g -fno-stack-protector a.c -o a.outして実行すれば、a.out -x -n 111<find_testすべてが大丈夫です。理由がわかりませんでした。誰か助けてもらえますか?

4

2 に答える 2

5

と を混同しているようMAX_LINESですMAX_LENGTH。前者にスペースを割り当てているように見えますが、読み込んだのは後者です。

int find_test(int argc, char *argv[])
{
    char line[MAX_LINES];            <-------------
    int c...

    ....

    while(getline(line, MAX_LENGTH) > 0){  <-------

fgets()ところで、代わりにを使用しないのはなぜgetline()ですか?

アップデート

しかし、gcc -Wall -O2 -g -fno-stack-protector ac -o a.out を使用し、a.out -x -n 111 < find_test を実行すると、すべて問題ありません

いいえ、間違いなくすべてがOKというわけではありません。まだメモリ領域を上書きしています。上書きは現在この特定のプラットフォームでは「ほとんど無害」かもしれませんが、それでも潜在的に致命的です。別のコンテキストでは、何らかの保護が行われていない限り (幸いなことに、最近は非常に頻繁に行われていますが、運が悪いとは言えません)、同じエラーにより、リモートの攻撃者がマシンを制御できるようになる可能性があります。より長い行を試してみると、スタック プロテクタのない「OK」プログラムが再びセグメンテーション違反を起こす可能性があります (または、より複雑なプログラムの場合、誤った結果を返したり、システムに損傷を与えることさえあります)。

于 2012-11-15T16:14:16.000 に答える
2

行に到達MAX_LENGTHするstrstrと、バッファーに「\0」文字がないため、バッファーを超えてスキャンできます。

編集:そして、私が作りたい別のポイントさえあります。どちらの可能性にも議論があるため、これは議論の余地があります。unsigned私の意見では、バッファ インデックスを使用する方がよいでしょう。これにより、ループを別の方法で処理することが強制されます。これは、正しく行うのが簡単です。さらに、配列を でインデックス付けするunsigned場合、アンダーフローの場合segmentation fault、符号付き積分よりも を取得する可能性が高くなります。最近私たちのプロジェクト (1998 年から運用されているシステム) でケースがあり、コード内の 1 つの変数を に変更しsize_t、最初から見逃されていた 2 つのアンダーフロー バグを見つけました。

EDIT2:私が作りたいもう一つの文体のポイント. ループ式でのポスト (イン|デ) クリメントは避けてください。これは非常に頻繁に微妙なバグ (上記のようなもの) につながります。pre-(in|de)crement は問題ではありません。post-(in|de)crement が問題となる理由は、式の条件 (続行または中断) を精神的に解析すると、すぐに無効になるためです。つまり、式の最後で、頭の中で使用した値が結果が存在しないことを確認します。多分それは私だけかもしれませんが、私がCでプログラミングした25年間で、ループのポスト(イン|デ)クリメントが間違っていたことが何度もあり、常にプリ(イン|デ)クリメントのいずれかによって修正されましたまたはブール式からインクリメントを持ち上げます。

于 2012-11-15T16:20:48.763 に答える