web-dev-qa-db-ja.com

このバッファはどのようにオーバーランする可能性がありますか?

この質問の役に立たないタイトルについては、事前に謝罪しますが、これよりも適切なものはないようです。

ここでの考え方は、argvを別の変数に複製し、基本的にそのコピーを作成することです。したがって、関数の基本的な考え方は、malloc()を使用してコピー用のスペースを要求し、argvを繰り返して各要素のコピーを作成します。

これは私が作業しているコードであり、開発環境は現在Visual Studio 2019です(厳密にはCコンパイラでなくても...):

_// Returns a copy of an array of strings (intended for argv, but should work with any of them):
wchar_t** copyArgv(size_t argc, wchar_t* argv[]) {
    // Allocate space for the array of arguments:
    wchar_t** argsCopy = malloc(((argc + 1) * sizeof(wchar_t*)));
    if (!argsCopy)
        return NULL;
    // Copy each one of them:
    for (size_t i = 0; i < argc; i++) {
        argsCopy[i] = _wcsdup(argv[i]);
        if (!argsCopy[i]) {
            // Should also free any previous copied string I left that part out in the paste.
            free(argsCopy);
            return NULL;
        }
    }
    argsCopy[argc] = NULL;
    return argsCopy;
}
_

私はargvのコピーを作成するためにさまざまな方法を試してきましたが、引数のコピー(line:argsCopy[i] = _wcsdup(argv[i]);)または読み取り時に、バッファオーバーランの可能性があるとVSに信じ込ませます次の行の無効なデータは、予約されたスペースの境界から読み取ることを意味します。

これらすべてが原因で、問題は(現在の)唯一のmalloc()呼び出しが引数の配列用にスペースを予約することにあると考えています。

それでも、私は壁に頭をぶつけて、問題が何であるかを理解しようとしています。つまり、十分なスペースを求めていると思います。

他のコンパイラも試しましたが、ClangとGCCの最新の安定バージョンでは、このような警告は表示されないようです。だから、私はあなたに問題を見つけることができるのか、それともある種のコンパイラのバグなのか(おそらく私が賭けるのではないか)、熟練したプログラマーに尋ねることに決めました。

参考までに、これらはVS2019がスローしている正確な警告です(64ビットコンパイルの場合)。

割り当て内:

「argsCopy」への書き込み中のバッファオーバーラン:書き込み可能なサイズは「((argc + 1))* sizeof(wchar_t *)」バイトですが、「16」バイトが書き込まれる可能性があります。

次の行、NULLのテスト:

「argsCopy」から無効なデータを読み取ります:読み取り可能なサイズは「((argc + 1))* sizeof(wchar_t *)」バイトですが、「16」バイトが読み取られる場合があります。

14
Alexander Row

これらは、静的アナライザーからの警告です。たとえば、バッファオーバーフローの状況を認識しようとします。

警告

これらは警告であり、エラーメッセージではないことに注意してください。コンパイラーは、何かが潜在的に間違っている可能性があると言います。静的解析は一般に難しいことです。

False Positive

バッファオーバーランの状況はないため、誤検知です。このメッセージは将来のアップデートで消えると思います。

コードを少し変更します

メモリ割り当て行を次のように変更すると、

wchar_t** argsCopy = (wchar_t**)calloc(argc + 1, sizeof(wchar_t*));

その後、Visual Studio 2019からの警告はなくなります。

割り当てられたバイト数は変わりません。ただし、警告は消えます。

テスト

変更前のVSエラーリストは次のようになっています。

before

私が提案した変更を適用した後、警告は消えました。

after

1

間違えたかもしれませんが、ビジュアルスタジオのオンラインコピー( https://rextester.com/l/c_online_compiler_visual )をいじってみたところ、string.hを含めるのを忘れていると思わざるを得ません。またはwchar.h(どちらでも機能します)。関数が定義されていないため、Visual Studioは戻り値の型がwchar_t *ではなく整数であると想定しているようです。 _で始まる予約済み関数であり、他の警告を発行しないため、少し「マジック」があるようです。私は部分的に推測することを余儀なくされていますが、あなたの正確な環境なしでもう一度(警告を変更するターゲットに関するあなたのコメントは私にうまくいけば正しいヒントを与えてくれました)。

0
Greenbeard

重要な点は、コピーしたいデータを保持するのに十分なスペースをmallocしていない可能性があります。

私があなたが何をしたいのかを実際に理解しているかどうかはわかりませんが、2次元の文字配列を別のメモリセグメントにコピーしてそのアドレスを返したいと思います。配列には各行のアドレスである「argc」行があります文字列のargvの配列に格納されます。

しかし、なぜargcではなく_argc+1_を使用したのですか?バッファオーバーランを防ぐためのmallocの余分なスペースについては?さらに重要なのは、sizeof(wchar_t*)がポインターのサイズを返すことです(64ビットシステムでは8バイト)。必要な2次元配列の文字列の1つのサイズは返しません。

0
Green