0

次のコード スニペットがあります。

#include<stdio.h>
#include<stdlib.h>
int main()
{
        char *c = malloc(1);
        printf("%p\n", c);
        c = c + 20;

        printf("%p\n", c);
        printf("%d\n", *c);

        free(c - 20);
        return 0;
}

このコードでは、1 バイトのメモリをポインターに割り当てています。次に、メモリが割り当てられてから20ユニット後のメモリ位置にアクセスしています。そのポインターを逆参照すると、メモリ アクセス違反エラーやセグメンテーション フォールトなどのエラーが発生することが予想されます。そのようなエラーは発生しません。

これが未定義の動作のケースであると仮定しましょう。そこで、よく知られたモデルチェッカーであるCBMCを使って、以下のコマンドでこのプログラムを検証してみました。

cbmc test01.c --pointer-check

CBMC は、プログラムが安全であることを報告しています。それはCBMCの問題ですか、それとも何か不足していますか?

4

2 に答える 2

1

質問で述べたように、ステートメントprintf("%d\n", *c);は未定義の動作を公開します。undefinedであるため、それに対する期待はすべて誤りです。これには、特定のエラーまたはエラーの発生が含まれます。

C ランタイム ライブラリは、プログラムがメモリにアクセスする方法をチェックしません。それができれば、プログラムの実行速度ははるかに遅くなります。ヒープに関しては、C ランタイム ライブラリがいくつかの基本的なチェックを行います。たとえば、0プログラムの起動時にアドレスに特定の値を設定し、プログラムの終了時にその値がまだそこにあるかどうかを確認します。値が変更された場合、null ポインターは書き込みのために逆参照され、これについて警告することができます。

の後c = c + 20;cほとんどの場合、プログラムに属するメモリ ブロックを指します。ヒープ上の空き領域にすることも、ヒープ マネージャーがヒープを処理するために使用するデータ構造内にすることもできますが、同じメモリ ページ上にある可能性が高くなります。

(不運な) 運がありc + 20、格納されているメモリ ページの外に出たc場合、オペレーティング システムによって処理される例外的な状況が発生します。プログラムを終了し、質問に記載されているものと同様のエラー メッセージを表示します (考え方は同じですが、言葉と表現は OS ごとに異なります)。


アップデート

メモリの割り当ては、ある種の魔法ではありません。プログラムは、この目的のために OS によってプログラムに割り当てられたメモリのブロック ( 「ヒープ」と呼ばれる) から開始します。

C ランタイム ライブラリには、ヒープを管理するコードが含まれています。このコードは、簿記のためにこのメモリのごく一部を使用します。<memory.h>一般的な実装では、二重リンク リストが使用されます。リストの各ノードのペイロードは、 (など)malloc()で宣言された関数を使用してプログラムによって "割り当てられた" メモリ ブロックです。calloc()への呼び出しがmalloc()発生すると、このコードが実行され、リストに新しいノードが作成され、ノードのペイロードのアドレス (ヒープ内のアドレス) が返されます。

プログラムはこのポインタを必要に応じて使用します。c-1たとえば、あなたのプログラムは自由に書くことができます。実際、その中malloc()には実際にそこに情報が書かれていました。return の後、あなたのコードは at にも書くことができmalloc()ます。観点からは、これら 2 つの書き込み操作に違いはありません。また、マネージ言語またはインタープリター言語ではないため、作成したコードの動作を監視したり、間違った場所に書き込まないように手を握ったりするコードがプログラムに含まれていません。cc-1OSC

で書き込むとc-1、ヒープ マネージャーが使用するデータ構造が破損する可能性が高くなります。すぐに悪いことは起こりません。エラー メッセージは表示されず、プログラムは正常に動作し続けます。しかし、ヒープを処理する関数への次の呼び出し (メモリ割り当てまたは解放) で、プログラムは大混乱を引き起こし始めます。ヒープ データ構造が壊れていると、何かが起こる可能性があります。


CBMCに関しては、私はそれがどのように機能するかわかりません。そのような状況を検出できない可能性があります。cまたは、プログラムがインクリメントされた後に書き込みを行わないため、プログラムが安全であると報告される場合があります。

于 2016-03-31T09:51:50.900 に答える
0

ところで。gcc -fsanitize=address警告なしでこのファイルをコンパイルしますが、コードを実行すると、アドレスサニツァーからメッセージが表示されます

=================================================================
==24198==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000f004 at pc 0x400921 bp 0x7ffe1e66b900 sp 0x7ffe1e66b8f0
READ of size 1 at 0x60200000f004 thread T0
    #0 0x400920 in main (/home/ingo/test/c/sanitize_address+0x400920)
    #1 0x7fdd9ddca7af in __libc_start_main (/lib64/libc.so.6+0x207af)
    #2 0x4007d8 in _start (/home/ingo/test/c/sanitize_address+0x4007d8)

0x60200000f004 is located 19 bytes to the right of 1-byte region [0x60200000eff0,0x60200000eff1)
allocated by thread T0 here:
    #0 0x7fdd9e19c7b7 in malloc (/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.3/libasan.so.1+0x577b7)
    #1 0x4008b7 in main (/home/ingo/test/c/sanitize_address+0x4008b7)
    #2 0x7fdd9ddca7af in __libc_start_main (/lib64/libc.so.6+0x207af)

SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 main
Shadow bytes around the buggy address:
  0x0c047fff9db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9dc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9dd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9de0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9df0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa 01 fa
=>0x0c047fff9e00:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff9e50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Contiguous container OOB:fc
  ASan internal:           fe
==24198==ABORTING

このような出力は、そのようなリークやオーバーランを見つけるのに非常に役立ちます。

しかし、実行時に発生するこのようなエラーをコンパイラが見つけるのは簡単なことではありません。

于 2016-03-31T11:12:45.800 に答える