1

私の質問に対する答えを理解しようとしています

要求された以上の量を割り当てるヒープマネージャによって割り当てられたメモリを解放しようとするとどうなりますか?

私はこの関数を書き、その出力に戸惑いました

int main(int argc,char **argv){
  char *p,*q;
  p=malloc(1); 
  strcpy(p,"01234556789abcdefghijklmnopqrstuvwxyz"); //since malloc allocates atleast 1 byte
  q=malloc(2);
  //    free(q);
  printf("q=%s\n",q);
  printf("p=%s\n",p);

  return 0;
}

出力

q=vwxyz
p=01234556789abcdefghijklm!

誰かがこの振る舞いを説明できますか?または、この実装は特定のものですか?

また、free(q)がコメント化されていない場合、SIGABRTを取得しています。

4

7 に答える 7

8

割り当てたよりも多くのバイトをコピーし*p、割り当てられたスペースの後にメモリ位置にあった可能性のあるものを上書きします。

次に再度呼び出すとmalloc、現時点で使用されていないことがわかっているメモリの一部を*p取得し(この時点から数バイト後)、そこに簿記情報を書き込み、その場所への新しいポインタを返します。

簿記情報のmalloc書き込みは、たまたま「!」で始まります。この実行では、ゼロバイトが続くため、最初の文字列は切り捨てられます。新しいポインタは、前に上書きしたメモリの終わりを指します。

これはすべて実装固有であり、実行ごとに、または月の満ち欠けに応じて、異なる結果につながる可能性があります。への2番目の呼び出しmalloc()も、プログラムを恐ろしい方法でクラッシュさせるだけの権利があります(特に、malloc内部で使用するメモリを上書きしている可能性があるため)。

于 2010-02-25T19:16:02.977 に答える
7

今回は幸運です。これは未定義の動作であり、期待しないでください。

通常、ただしOSによっては、メモリは「ページ」(つまり複数バイト)で割り当てられます。Malloc()一方、これらの「ページ」からより「きめ細かい」方法でメモリを割り当てます。を介して管理される各割り当てに関連付けられた「オーバーヘッド」がありますmalloc

あなたが得ている信号は、freeおそらくあなたが割り当てられたものを超えて書き込むことによってメモリ管理を台無しにするという事実に関連しています。pつまり、メモリブロックなどを追跡するためにメモリマネージャによって使用されるオーバーヘッド情報に書き込みます。

于 2010-02-25T19:05:48.610 に答える
4

これは古典的なヒープオーバーフローです。pには1バイトしかありませんが、ヒープマネージャーは割り当てを埋めます(この場合は32バイト)。qはpの直後に割り当てられるため、自然に次の利用可能なスポットを取得します。たとえば、pのアドレスが0x1000の場合、qに割り当てられるアドレスは0x1020です。これは、qが文字列の一部を指す理由を説明しています。

さらに興味深い質問は、pが「01234556789abcdefghijklm」だけで「01234556789abcdefghijklmnopqrstuvwxyz」ではない理由です。その理由は、メモリマネージャが内部の簿記のために割り当て間のギャップを使用するためです。メモリマネージャの観点から、メモリレイアウトは次のとおりです。pD qここで、Dはメモリマネージャの内部データ構造です(この例では0x1010から0x1020)。qにメモリを割り当てている間、ヒープマネージャはその内容を簿記領域(0x1010から0x1020)に書き込みます。バイトが0に変更されると、文字列はNULLターミネータとして扱われるため、文字列が切り捨てられます。

于 2010-02-25T19:17:00.087 に答える
1

「p」の値:

これに合うように十分なスペースを割り当てました: ""

[[文字列はnullで終了します、覚えていますか?表示されませんが、そこにあります。つまり、1バイトが使い果たされています。]]

しかし、あなたはこれを保存しようとしています: "01234556789abcdefghijklmnopqrstuvwxyz"

したがって、結果として、「123 ..」で始まる「もの」は、割り当てたメモリを超えて格納されます。おそらく、他の「もの」を他の場所に上書きします。そのため、結果は乱雑になり、「jidupont」が言ったように、クラッシュするだけではないのは幸運です。

印刷出力[壊れた]「p」

言ったように、あなたは「p」の終わりを過ぎて書いた。しかし、mallocはこれを知りません。したがって、「q」のメモリの別のブロックを要求すると、「p」のメモリに続くメモリが得られた可能性があります。そして多分それはメモリ(典型的)を整列させたので、そのポインタはいくつかの良い数に切り上げられます。そして多分それはあなたが気にしないはずの簿記情報を保存するためにこの記憶のいくらかを使うでしょう。でも分かりませんね あなたも知っているはずではありません-あなたは自分で割り当てていないメモリに書き込むべきではありません!

そしてその結果は?あなたはあなたが期待したもののいくつかを見ます-しかしそれは切り捨てられます!なぜなら...別のブロックがおそらくあなたが使用したメモリに割り当てられた(そして許可なく使用された、私は追加するかもしれない)、または他の何かがそのブロックを所有してそれを変更し、そしていずれにせよいくつかの値が変更された-結果: "01234556789abcdefghijklm !"。繰り返しになりますが、物事が爆発しただけではなかったのは幸運でした。

「q」を解放する

「q」を解放してから、それにアクセスしようとすると(印刷しようとしているように)、(通常は)厄介なエラーが発生します。これは当然のことです。その「free(q)」のコメントを外してはいけません。しかし、まだ何も入れていないので、「q」を印刷しようとしないでください。ご存知のとおり、ジブリッシュが含まれている可能性があるため、印刷はNULLに遭遇するまで続行されます。これは、世界の終わりまで発生しない可能性があります。または、プログラムが必要以上のメモリにアクセスするまで、印刷は続行されます。 t、OSがあなたに満足していないためにクラッシュします。:)

于 2010-02-25T19:33:09.880 に答える
0

これらの関数を意図的に誤用すると、無意味な結果が生じるという不可解なことではありません。

2つの連続したmallocが、2つの連続したメモリ領域を提供することは保証されていません。mallocは、要求した量より多くのメモリを割り当てることを選択する場合がありますが、割り当てが成功した場合はそれより少なくなることはありません。未割り当てのメモリを上書きすることを選択した場合のプログラムの動作は、予測可能であるとは限りません。

これがCのやり方です。mallocから返されたメモリ領域を簡単に誤用する可能性があり、言語は関係ありません。それは、正しいプログラムでは決してそうしないことを前提としているだけであり、他のすべては手に入れる準備ができています。

于 2010-02-25T19:18:40.413 に答える
0

Mallocはあなたと同じような機能です:)

mallocの実装がたくさんあるので、無駄な詳細には立ち入りません。

最初のmallocの呼び出しで、システムにメモリを要求します。例として、適切な標準メモリページサイズである4096としましょう。したがって、mallocを呼び出して1バイトを要求します。関数mallocは、システムに4096バイトを要求します。次に、このメモリのごく一部を使用して、使用可能なブロックの位置などの内部データを格納します。次に、このブロックの一部を切り取り、返送します。

内部アルゴリズムは、freeの呼び出し後にブロックを再利用して、システムにメモリを再要求しないようにします。

したがって、この小さな説明で、コードが機能している理由を理解できるようになりました。

あなたは私のmallocにシステムに尋ねたメモリに書き込んでいます。プロセスに割り当てられたメモリにとどまるため、この調整によってシステムが煩わされることはありません。問題は、ソフトウェアメモリの重要な部分に書き込みを行っていないことを確実に知ることができないことです。この種のオフエラーはバッファオーバーフローと呼ばれ、ほとんどの「神秘的なバグ」を引き起こしています。

それらを回避する最善の方法は、Linuxでvalgrindを使用することです。このソフトは、あなたが書いているのか読んでいるのかを教えてくれます。

それは十分に明確ですか?

于 2010-02-25T19:33:20.197 に答える
0

この紹介を読むことをお勧めします。

ポインタとメモリ

スタックとヒープの割り当ての違いを理解するのに役立ちました。非常に良い紹介です。

于 2010-02-25T19:55:20.973 に答える