2

次のバグにフラグを立てることができる動的チェック ユーティリティはありますか? ヴァルグリンドはできません。浄化または保険++できますか? これはLinux Ubuntuの最新バージョンにあります。

struct A {
    char buff1[8];
    int jj;
    char buff2[8];
    int ii;
    char buff3[8];
} a;

main(int argc, char *args[])
{
    // Set intermediate fields to known flag value
    a.ii = a.jj = 0xdeadbeef;

    // Write 8 char string into 8 byte buffer - null will overflow into neighboring int field. ERROR
    sprintf(a.buff2, "ABCDEFGH");
}
4

4 に答える 4

2

私の知る限りではありません。ほとんどの (またはすべての?) メモリ検証ツールは、合法的に割り当てられた領域を超えたアクセスでトラップを引き起こすために、読み取りおよび書き込み保護されたページを変数の間および周囲のガード ゾーンとして埋め込む方法で機能します。

構造の整列と完全性を著しく乱さない限り、これは構造の途中で簡単に行うことはできません。

編集: もう 1 つのポイントは: 構造体メンバーの境界を超える書き込みが完全に合法であり、目的を達成するための唯一の合理的な可能性がある構造があります。1 つの例は、構造体をヒープにコピーすることです。

struct x orig, *copy;

orig.a = 100;
strcpy (orig.str, "Test");

copy = malloc (sizeof (struct x));
memcpy (copy, &orig, sizeof (struct x));

これは構造体メンバーの境界を超えて書き込みますが、構造体をヒープに取得するための唯一の合理的な (そして完全に合法的な) 方法です (退屈で遅いメンバーごとのコピーは別として)。

別の例は次のとおりです。

p = malloc (NUM_STRUCTS * sizeof (struct x));
memset (p, NUM_STRUCTS * sizeof (struct x), 0);

これは、ヒープ上の構造体の配列をクリアできる完全に有効なコンストラクトです。また、内部構造体の境界を越えて書き込むことさえありませんが、構造体でも書き込みを行いません。

ある意味では、calloc()でさえ、構造体メンバーの境界を超えて書き込みます....

そして、(確かに古い)Purify User Manual からの明確な答えとして、たまたま机の引き出しの1つに見つけました:

Purify は、アクセスが構造全体を超えている場合にのみ、C 構造内の配列で配列境界エラーを検出します。

それは私にとって「いいえ」と見なされます。

于 2016-03-14T21:47:43.423 に答える
1

動的ツールである必要がありますか? 上記のシナリオを検出できる唯一のツールは、Synopsisの静的ツールである Coverity です。上記の場合、次の形式のレポートが生成されます。

Error: OVERRUN:
...
sprintf_overrun: "sprintf" will overrun its first argument "a.buff2" which can accommodate 8 bytes.  The number of bytes written may be 9 bytes, including the terminating null.
于 2016-04-02T19:31:32.700 に答える
-1

すべての警告を有効にしてコンパイルするのが良いスタートです:

chqrlie@mac ~/dev/stackoverflow > clang -O3 -std=c11 -Weverything -lm -o 35996676 35996676.c
35996676.c:9:1: warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
main(int argc, char *args[])
^
35996676.c:12:19: warning: implicit conversion changes signedness: 'unsigned int' to 'int' [-Wsign-conversi
    a.ii = a.jj = 0xdeadbeef;
                ~ ^~~~~~~~~~
35996676.c:15:5: warning: implicitly declaring library function 'sprintf' with type 'int (char *, const cha
    sprintf(a.buff2, "ABCDEFGH");
    ^
35996676.c:15:5: note: include the header <stdio.h> or explicitly provide a declaration for 'sprintf'
35996676.c:9:10: warning: unused parameter 'argc' [-Wunused-parameter]
main(int argc, char *args[])
         ^
35996676.c:9:22: warning: unused parameter 'args' [-Wunused-parameter]
main(int argc, char *args[])
                     ^
35996676.c:7:3: warning: no previous extern declaration for non-static variable 'a' [-Wmissing-variable-dec
} a;
  ^
6 warnings generated.

これらを簡単なパッチで修正し、明らかなバグを追加します:

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

static struct A {
    char buff1[8];
    unsigned int jj;
    char buff2[8];
    unsigned int ii;
    char buff3[8];
} a;

int main(void) {
    // Set intermediate fields to known flag value
    a.ii = a.jj = 0xdeadbeef;

    // Write 8 char string into 8 byte buffer - null will overflow into neighboring int field. ERROR
    sprintf(a.buff1, "ABCDEFGH");
    strcpy(a.buff2, "ABCDEFGH");
    sprintf(a.buff3, "%s", "ABCDEFGH");

    return 0;
}

警告なしでコンパイルされ、単純化された静的解析で発見されるべき明白なバグにsprintfもかかわらずです。strcpy

gccwith-Wall -W -Wextraも何も問題はありません。

snprintfの代わりにを使用することをお勧めしますsprintfが、それで問題が回避されるわけではありませんstrcpystrcpy一般的なケースでは安全ではありませんが、文字列リテラルをソースとして使用すると、コンパイラは間違いなく文句を言うはずです。

Frama-c は、http://frama-c.com/からオープン ソースで入手できる強力なソース コード分析フレームワークです。

于 2016-03-15T15:27:57.630 に答える
-2

私の経験では、Purify はあなたが望むことをするかもしれません。これは、インターネットに投稿された古い Purify ユーザー マニュアルからの抜粋です。

Purify が静的に割り当てられたメモリをチェックする方法

Purify は、動的メモリ内のアクセス エラーを検出するだけでなく、グローバル変数および静的変数内のデータの境界を越えた参照、つまり、実行時に動的ではなくリンク時に静的に割り当てられたデータを検出します。

静的チェック機能によって処理されるデータの例を次に示します。

int array[10];
main() {
    array[11] = 1;
}

この例で array[11]は、配列の末尾を 4 バイト超えているため、Purify は への割り当てで ABW エラーを報告します。

于 2016-03-17T10:58:37.290 に答える