Модульное тестирование для неудачного malloc () - PullRequest
8 голосов
/ 11 ноября 2009

Каков наилучший способ для модульного тестирования путей кода с ошибкой malloc()? В большинстве случаев это, вероятно, не имеет значения, потому что вы делаете что-то вроде

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

но в некоторых случаях у вас есть выбор, кроме смерти, потому что вы выделили некоторые дополнительные вещи для кэширования или чего-то еще, и вы можете восстановить эту память.

Однако в тех случаях, когда вы можете попытаться восстановиться после сбоя malloc(), когда вы делаете что-то хитрое и подверженное ошибкам в пути кода, что довольно необычно, что делает тестирование особенно важным. Как вы на самом деле делаете это?

Ответы [ 6 ]

16 голосов
/ 11 ноября 2009

Я увидел крутое решение этой проблемы, которое мне подарил С. Пааволайнен. Идея состоит в том, чтобы переопределить стандарт malloc(), который вы можете сделать только в компоновщике, с помощью специального распределителя,

  1. читает текущий стек выполнения потока, вызывающего malloc()
  2. проверяет, существует ли стек в базе данных, которая хранится на жестком диске
    1. если стек не существует, добавляет стек в базу данных и возвращает NULL
    2. , если стек уже существует, нормально распределяет память и возвращает

Затем вы просто запускаете свой модульный тест много раз: эта система автоматически перечисляет различные пути управления до отказа malloc() и является гораздо более эффективной и надежной, чем, например случайное тестирование.

2 голосов
/ 11 ноября 2009

написать свою собственную библиотеку, которая реализует malloc путем случайного сбоя или вызова реального malloc (либо статически связанного, либо явно выдавленного)

тогда LD_PRELOAD это

2 голосов
/ 11 ноября 2009

Я предлагаю создать специальную функцию для вашего специального кода malloc, которая, как вы ожидаете, может потерпеть неудачу, и вы можете обработать ее изящно. Например:

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

Тогда вы можете протестировать этот хитрый бизнес здесь, передавая некоторые плохие значения для байтов. Вы можете поместить это в отдельную библиотеку и создать mock-библиотеку, которая ведет себя специально для тестирования функций, вызывающих эту.

1 голос
/ 11 ноября 2009

Вы можете взломать 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;
}
1 голос
/ 11 ноября 2009

Это своего рода брутто, но если вам действительно нужно юнит-тестирование, вы можете сделать это с помощью #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 , но будьте осторожны.

1 голос
/ 11 ноября 2009

В FreeBSD я однажды просто перегрузил модуль malloc.o библиотеки C (символы там были слабые) и заменил реализацию malloc () на ту, которая контролировала вероятность сбоя. Поэтому я статически связался и начал проводить тестирование. srandom () завершил работу с псевдослучайной последовательностью.

Также посмотрите здесь , чтобы найти набор хороших инструментов, которые, по моему мнению, вам нужны. По крайней мере, они перегружают malloc () / free () для отслеживания утечек, поэтому кажется полезным использовать для добавления что угодно.

...