3

すでに解放されているアドレスにアクセスしようとすると、プログラムは正常に実行されます。避けるべき商品はありますか?名前付きの関数のように、有効なアドレスhave_alloca(void *p)かどうかを返すことができます。 私はそれができることを知っています。しかし、コードからそれを回避できるかどうか知りたいです。 簡単な例を次に示します。p
valgrindtool=memcheck

#include <stdlib.h>

int main(int argc, char *argv[])
{
    int *p = malloc(sizeof(int) * 10);
    free(p);
    *(p + 1) = 100;

    return 0;
}

無効なアドレスにアクセスできるのはなぜですか? プログラムは警告なしでコンパイルおよび実行できます。ところで:Linux。

4

4 に答える 4

11

いいえ、これは自分で処理する必要があります。
技術的には、自分のものではないメモリ位置への書き込みは、言語標準の観点からは未定義の動作です。

C および C++ 言語は、変数のアドレスに到達し、変数/オブジェクトが所有する有効な値をそれらのアドレスに含めるのは自分の責任であるという犠牲を払って、変数のアドレスに到達し、それらをいじる柔軟性を提供します。

根拠は次のとおりです。

「大きな力には大きな責任が伴う」

したがって、責任はあなたが負うべきです。

于 2012-12-29T05:40:20.530 に答える
8

p は通常の変数のようなものです

関数 free(p) の呼び出しは、割り当てたメモリを解放するだけですが、p はまだアドレス値を保持しています。自分でリセットしない限り:

p = NULL;

そのため、次のヒントを念頭に置いてください。

  1. ポインタを使用する前に毎回、それが NULL ポインタかどうかを確認してください。
  2. メモリを解放するたびに、ポインターに NULL を設定します。
于 2012-12-29T05:55:32.280 に答える
2
  • NULLポインタを解放した後、ポインタに割り当てます。
  • NULLアクセスする前に確認してください。
于 2012-12-29T05:59:26.103 に答える
1

他の回答に加えて、Boehm の保守的なガベージ コレクターGC_mallocを使用することを検討できます。その場合は、代わりに使用mallocし、何もしませんfree(メモリ ゾーンが役に立たなくなり、到達不能になることが絶対に確実な場合でも、明示的にそれを行うことができますGC_free) 。 .

ただし、Cfreeのポイントは、 -d データ ゾーンを使用できないことです。これを行うことは未定義の動作であり、何かが起こる可能性があります。

「なぜまだ無効なアドレスにアクセスできるのか」( free-d ゾーン内) という質問については、答えは実装固有です。実際には、Linux では、カーネルからのメモリの取得はmmap(2) (または場合によってsbrk(2)は ) を介して行われ、解放はシステムコールを介して行われmunmap(2)ます。これは、何らかの理由で高価な操作であり、複数のページ長 (多くの場合 4K バイト) を処理します。そのため、実装は多くのsyscallmallocを実行することを回避しようとします。そのため、通常は -d メモリ ゾーンを別の方法で管理し、syscallを実行せずにさらに再利用できるように編成します。これは、メモリ ゾーンがまだ存在していることを示しています (内部にある場合でも)。mmapmunmapfreemallocmmapmalloc内部簿記)にアクセスできます。しかし、そうすることで の内部不変条件が壊れ、malloc大混乱が後で起こります。

/proc/1234/mapsところで、アドレスがアドレス空間内にある場合、アドレスは有効であり、ファイル (Linux で指定されたテキスト コンテンツを含む疑似ファイル) を (順次) 読み取ることで、プロセス 1234 のアドレス空間を照会できます。プロセス内から読み取ります/proc/self/maps。詳細を理解するcat /proc/self/mapsには、そのコマンドを実行しているプロセスのアドレス空間を表示するコマンドを試してください。proc(5)の man ページcatを参照してください。

簡単なプログラムを試してstrace、どのようなシステムコールを行っているかを理解してください。

于 2012-12-29T07:55:25.217 に答える