2011-12-27 10 views
2

例コード:無効な読み取り/書き込み時にセグメンテーションフォールトを作成し、時にはない

int main() 
{ 
    char b[] = {"abcd"}; 
    char *c = NULL; 
    printf("\nsize: %d\n",sizeof(b)); 
    c = (char *)malloc(sizeof(char) * 3); 
    memcpy(c,b,10); // here invalid read and invalid write 
    printf("\nb: %s\n",b); 
    printf("\nc: %s\n",c); 

    return 0; 
} 

私はいくつかの不正な読み取りや無効な書き込みが、この小さなプログラムが正常に動作して作成されません行っているコードで参照してください。 a core dump

私の大きなライブラリでは、1バイトの無効な読み取りまたは無効な書き込みを行うたびに、常にコアダンプを作成していました。

質問:

なぜ私は時々、無効な読み取り/書き込みからコア・ダンプを取得しないと、時々コアダンプを得ることはありませんか?

答えて

5

は、基本的には、より具体的にheap overflowあなたのコードサンプルで溢れ&をバッファです。あなたがクラッシュするのは時々だけです。その理由は、あなたがアクセス/書き込み権限を持っているかどうかにかかわらず、&にアクセスしているメモリ領域によって決まります(これはDan Fegoによってよく説明されています)。 Dan Fegoが提供している例は、スタックオーバーフロー(修正歓迎!)の詳細です。 gccはスタック上のバ​​ッファオーバーフローに関連する保護を持っています(スタックスマッシング)。次の例では、この(スタックベースのオーバーフローを)見ることができます:

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

int main (void) 
{ 
    char b[] = { "abcdefghijk"}; 
    char c [8]; 
    memcpy (c, b, sizeof c + 1);  // here invalid read and invalid write 
    printf ("\nsize: %d\n", sizeof b); 
    printf ("\nc: %s\n", c); 
    return 0; 
} 

サンプル出力を:

$ ./a.out 

size: 12 

c: abcdefghi��� 
*** stack smashing detected ***: ./a.out terminated 

この保護は、GCCで-fno-stack-protectorオプションを使用して無効にすることができます。
バッファオーバーフローがセキュリティ上の脆弱性の大きな原因の1つです。残念ながら、memcpyのような機能は、この種の問題をチェックしませんが、この種の問題を防ぐためにwaysがあります。
これが役立つことを願っています!

+0

+1、そうです。 'c'にあるメモリはヒープ上にあり、' b'はスタック上にあります。だからこの状況では、あなたはヒープをあふれている。良いキャッチ。 ;) –

6

無効な読み取り/書き込みを実行すると、上書きまたは間接参照の対象に依存します。具体的には、たとえば、逆参照されるポインタを上書きする場合、最も重要なバイトの1つを考えれば、まったく異なる(完全に無効な)領域に逆参照される可能性があります。

ので、例えば、スタックは、cの終わり過去のmemcpyがbの一部を上書きするように配置された場合は、引数としてbprintf()を呼び出そうとするとき、それはそのポインタを取るしようとすると、それはへの間接参照文字列を出力します。これはもはや有効なポインタではないため、セグメンテーションが発生します。しかし、スタック配置のようなものはプラットフォーム(そしておそらくコンパイラ?)に依存しているので、異なるプログラムでも同様の例で同じ動作をすることはできません。

+0

+1あなたの例は私に理解している..! –

0

3文字の文字列cを作成しますが、10文字をコピーします。エラーです。

バッファオーバーフローと呼ばれ、あなたが属していないメモリに書き込みます。その動作は未定義です。それはクラッシュかもしれません、それはうまく動作するか、またはあなたが作成した別の変数を変更することができます。

そうするグー事はBの内容が含まれているために、Cのための十分なメモリを割り当てることです:

c = (char *)malloc(sizeof(char) * (sizeof(b)+1)); // +1 is for the '\0' char that ends every string in c. 

2 - あなたはcbをコピーした文字列の文字の終止符を打つことを忘れてはいけない:'\0' 。これはC標準では必須です。 だからprintf("%s",c);は文字列の終わりを知っています。 - あなたはcbから10個の文字をコピーしたが、b containdのみ5(a、b、c、dおよび '\ 0')文字memcpyの動作が定義されていないので、(例えば:memcpyの読み取りしようとすることができます読めないメモリ、...)。

あなたが所有するメモリだけをコピーすることができます.5文字はbです。

4 - 私はbを定義するための良好な指示があると思う:何をしようとするchar b="abcd";またはchar b={'a','b','c','d',0};