9

失敗したコードパスをユニットテストするための最良の方法は何malloc()ですか?ほとんどの場合、あなたが次のようなことをしているので、それはおそらく問題ではありません

thingy *my_thingy = malloc(sizeof(thingy));
if (my_thingy == NULL) {
  fprintf(stderr, "We're so screwed!\n");
  exit(EXIT_FAILURE);
} 

ただし、場合によっては、キャッシュなどに余分なものを割り当てて、そのメモリを再利用できるため、死ぬ以外の選択肢があります。

malloc()ただし、コードパスでトリッキーでエラーが発生しやすいことを実行しているという失敗からの回復を試みることができる場合は、テストが特に重要になります。実際にこれをどのように行っていますか?

4

6 に答える 6

16

私は、S。Paavolainenによって提示されたこの問題のクールな解決策を見ました。アイデアはmalloc()、リンカーで実行できる標準を、カスタムアロケータによってオーバーライドすることです。

  1. 呼び出し元のスレッドの現在の実行スタックを読み取りますmalloc()
  2. スタックがハードディスクに保存されているデータベースに存在するかどうかを確認します
    1. スタックが存在しない場合は、スタックをデータベースに追加して、NULL
    2. スタックがすでに存在していた場合は、通常どおりメモリを割り当てて、

次に、単体テストを何度も実行します。このシステムは、さまざまな制御パスを介してmalloc()障害を自動的に列挙し、ランダムテストなどよりもはるかに効率的で信頼性があります。

于 2009-11-10T21:17:45.860 に答える
2

これはちょっとグロスですが、本当にユニットテストが必要な場合は、#ifdefsを使用して行うことができます。

thingy *my_thingy = malloc(sizeof(thingy));
#ifdef MALLOC_UNIT_TEST_1
my_thingy = NULL;
#endif
if (my_thingy == NULL) {
  fprintf(stderr, "We're so screwed!\n");
  exit(EXIT_FAILURE);
}

残念ながら、このソリューションでは多くの再コンパイルが必要になります。

Linuxを使用している場合は、ulimitを使用して、メモリ不足でコードを実行することも検討できますが、注意が必要です。

于 2009-11-10T21:17:18.460 に答える
2

失敗する可能性があり、適切に処理できると予想される、特別なmallocコード用の特定の関数を作成することをお勧めします。例えば:

void* special_malloc(size_t bytes) {
  void* ptr = malloc(bytes);
  if(ptr == NULL) {
    /* Do something crafty */
  } else {
    return ptr;
  }
}

次に、バイトにいくつかの悪い値を渡すことによって、ここでこの巧妙なビジネスを単体テストすることができます。これを別のライブラリに入れて、これを呼び出す関数のテスト用に特別に動作するモックライブラリを作成することができます。

于 2009-11-10T21:21:53.253 に答える
2

ランダムに失敗するか、実際のmallocを呼び出すことによってmallocを実装する独自のライブラリを作成します(静的にリンクされているか、明示的に傾斜している)

次にLD_PRELOADit

于 2009-11-10T21:59:47.600 に答える
1

FreeBSDでは、かつてCライブラリのmalloc.oモジュール(シンボルが弱かった)をオーバーロードし、malloc()の実装を失敗する確率を制御したものに置き換えました。そこで、静的にリンクしてテストを開始しました。srandom()は、制御された疑似ランダムシーケンスで画像を終了しました。

また、私の意見ではあなたが必要と思われる一連の優れたツールをここで探してください。少なくとも、それらはリークを追跡するためにmalloc()/ free()をオーバーロードするので、必要なものを追加するための有用なポイントのようです。

于 2009-11-10T21:16:42.580 に答える
1

いくつかの定義とグローバルパラメータを使用してmallocを乗っ取ることができます...少しハックですが、機能しているようです。

#include <stdio.h>
#include <stdlib.h>

#define malloc(x) fake_malloc(x)

struct {
  size_t last_request;
  int should_fail;
  void *(*real_malloc)(size_t);
} fake_malloc_params;

void *fake_malloc(size_t size) {
  fake_malloc_params.last_request = size;
  if (fake_malloc_params.should_fail) {
    return NULL;
  }
  return (fake_malloc_params.real_malloc)(size);;
}

int main(void) {
  fake_malloc_params.real_malloc = malloc;
  void *ptr = NULL;
  ptr = malloc(1);
  printf("last: %d\n", (int) fake_malloc_params.last_request);
  printf("ptr: 0x%p\n", ptr);
  return 0;
}
于 2009-11-10T22:18:50.063 に答える