0

このコード スニペットを使用します。

// stackoverflow.c 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char** argv)
{
    int i;
    int a[10];
    // init
    a[-1] = -1;
    a[11] = 11;
    printf(" a[-1]= = %d, a[11] = %d\n", a[-1], a[11]);
    printf("I am finished.\n");
    return a[-1];
}

コンパイラは Linux x86 用の GCC です。実行時エラーなしで正常に動作します。また、このコードを Valgrind でテストしましたが、メモリ エラーも発生しません。

$ gcc -O0 -g -o stack_overflow stack_overflow.c
$ ./stack_overflow
   a[-1]= = -1, a[11] = 11
   I am finished.

$ valgrind ./stack_overflow
==3705== Memcheck, a memory error detector
==3705== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==3705== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==3705== Command: ./stack_overflow
==3705==
   a[-1]= = -1, a[11] = 11
   I am finished.
==3705==
==3705== HEAP SUMMARY:
==3705==     in use at exit: 0 bytes in 0 blocks
==3705==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==3705==
==3705== All heap blocks were freed -- no leaks are possible
==3705==
==3705== For counts of detected and suppressed errors, rerun with: -v
==3705== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

私の理解では、ヒープとスタックは同じ種類のメモリです。唯一の違いは、それらが反対方向に成長することです。

だから私の質問は:

スタック オーバーフロー/アンダーフローでは発生しないのに、ヒープ オーバーフロー/アンダーフローによってラムタイム エラーが発生するのはなぜですか?

なぜ C 言語設計者は、未定義の動作のままにする以外に、ヒープと同じようにこれを考慮に入れなかったのですか?

4

6 に答える 6

4

valgrindスタック バッファ オーバーフローを検出しません。を使用しAddressSanitizerます。少なくとも gcc 4.8 が必要であり、libasan がインストールされている必要があります。

gcc -g -fsanitize=address stackbufferoverflow.c

==1955==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x7fffff438d4c at pc 0x000000400a1d bp 0x7fffff438d10 sp 0x7fffff438d00
WRITE of size 4 at 0x7fffff438d4c thread T0
    #0 0x400a1c in main /home/m/stackbufferoverflow.c:9
    #1 0x7fe7e24e178f in __libc_start_main (/lib64/libc.so.6+0x2078f)
    #2 0x400888 in _start (/home/m/a.out+0x400888)

Address 0x7fffff438d4c is located in stack of thread T0 at offset 28 in frame
    #0 0x400965 in main /home/m/stackbufferoverflow.c:5

  This frame has 1 object(s):
    [32, 72) 'a' <== Memory access at offset 28 underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-underflow /home/m/stackbufferoverflow.c:9 main
于 2015-05-31T11:30:24.647 に答える
0

編集

ここに興味深いチュートリアルがあります:

http://gribblelab.org/CBootcamp/7_Memory_Stack_vs_Heap.html

ところで、Clang (OSX) はそれを検出しますが、それは単なる余分な機能であり、古き良き gcc で実行できます。

ctest.c:6:5: warning: array index 42 is past the end of the array (which contains 1 element) [-Warray-bounds]
    a[42] = 42;
    ^ ~~
cpp.cpp:4:5: note: array 'a' declared here
    int a[1];
    ^
1 warning generated.

a[11] = 11;

セグメンテーション違反をトリガーします (ただし、ここでは別の変数の値を上書きするだけの 1 バイトです)。スタック オーバーフローが必要な場合は、無限再帰を行うものを試してください。

また、コードを segfault から保護したい場合 (malloc のみ)、テスト用に電気フェンスでコンパイルすることをお勧めします。プログラムが割り当てられたメモリを超えるのを防ぎます(最初のバイトから開始)

http://linux.die.net/man/3/efence

コメントで示唆されているように、Valgrind も便利なツールです。

http://valgrind.org/

于 2015-05-31T10:49:30.963 に答える
0

スタック オーバーフロー/アンダーフローが実行時エラーをトリガーしないのはなぜですか?

C は「ヒープ」と「スタック」の実装に限定されません。例: の変数はmain()「スタック」にある必要はありません。GCC でさえ、単純な理解に反する方法で最適化する場合があります。 多くのメモリ アーキテクチャが可能です。C は基礎となるメモリ アーキテクチャを指定していないため、以下は単に未定義の動作です。 @KarolyHorvath

// Undefined behavior: accessing memory outside array's range.
int a[10];
a[-1] = -1;
a[11] = 11;

任意の分析は、特定の曜日の特定のメモリ モデルで意味がある場合がありますが、その動作は多くの可能性の 1 つにすぎません。

于 2015-05-31T22:17:34.200 に答える
0

C は、範囲外の配列インデックスなどをチェックしません。この場合は、10 個の要素の配列で要素番号 11 を変更します。通常、これは、プログラムが、この項目が存在する場合に格納されるべきメモリ内の場所に書き込むことを意味します。これにより、クラッシュなどの目に見えるエラーが発生する場合と発生しない場合があります。効果がないか、プログラムが奇妙なことをする可能性があります。それは、メモリ内のその場所にたまたま何が格納されていたか、およびそれがどのように使用されているかによって異なります。

他のプログラミング言語の中には、これらのようなチェックを実行し、エラーが報告されることを保証するものがあります。C標準はそのような保証を与えておらず、「未定義の動作」を引き起こすとだけ言っています。この理由の 1 つは、C で非常に効率的なプログラムを作成できるようにする必要があるためです。この場合、チェックによってわずかではあるが、場合によっては許容できない遅延が発生する可能性があります。また、C が設計された頃には、コンピューターは遅く、遅延はより深刻な問題でした。

C では、ヒープ エラーが検出または報告されるという保証もありません。Valgrind は C 言語の一部ではなく、別のツールであり、C よりも効果的な他のメカニズムを使用してエラーを検出するために最善を尽くしますが、すべてのエラーを検出できるという保証はありません。

于 2015-05-31T10:52:41.977 に答える