Проверьте, указывает ли указатель на выделенную память в куче - PullRequest
15 голосов
/ 17 июня 2010

Я хочу знать, указывает ли указатель на часть памяти, выделенную с помощью malloc / new.Я понимаю, что ответом для произвольного адреса является «Нет, вы не можете», но я думаю, что возможно переопределить malloc / free и отслеживать выделенные диапазоны памяти.

Знаете ли вы библиотеку управления памятьюПредоставление этого конкретного инструмента?
Знаете ли вы что-нибудь для производственного кода?

Valgrind - это здорово, но это слишком много инструментов (медленно) и, как сказал Уилл, мы не хотимиспользовать Valgrind следующим образом (достаточно мягкого сбоя).
Mudflap - очень хорошее решение, но оно предназначено для GCC, и, к сожалению, проверка не просто возвращает логическое значение (см. мойответ ниже).
Обратите внимание, что проверка правильности записи в память - это проблема безопасности .Так что поиск производительности мотивирован.

Ответы [ 10 ]

13 голосов
/ 17 июня 2010

Доказательство того, что это, вероятно, не может быть сделано с пользой:

char * p1 = malloc(1);
free( p1 );
char * p2 = malloc(1);   // probably allocates same block as first malloc

Теперь и p1, и p2 указывают на одну и ту же память в куче, но действителен только p2.

10 голосов
/ 18 июня 2010

Нет стандартного способа сделать это, но различные инструменты отладки malloc могут иметь способ сделать это.Например, если вы используете valgrind , вы можете использовать VALGRIND_CHECK_MEM_IS_ADDRESSABLE, чтобы проверить это и связанные вещи

5 голосов
/ 18 июня 2010

Вы можете сделать это самостоятельно, если производительность не является реальной проблемой для вашего приложения:

Определите MyMalloc (...) и MyFree (...), в которых наряду с вызовом malloc / free вы обновляете (упорядоченный) список пар {address - результат malloc, blockSize - the amt запрошенной памяти}. Затем, когда вам нужно проверить указатель p, вы ищите пару, удовлетворяющую: address <= p <= address + blockSize. </p>

Могут / должны быть проверены другие условия, если вы действительно хотите использовать этот указатель, он будет только сообщать, используется адрес или нет.

2 голосов
/ 18 июня 2010

Mudflap (для gcc) кажется очень сладким.Вы должны скомпилировать ваш софт, но он проверит любой неверный указатель доступа (куча / стек / статический)Он предназначен для работы с рабочим кодом с замедлением, оцениваемым от 1,5 до 5 раз.Вы также можете отключить проверку при доступе на чтение для ускорения.
Пользовательская проверка может быть выполнена с помощью

void __mf_check (void *ptr, __mf_size_t sz, int type, const char *location)

Вызов этой функции приводит к: none, fork to gdb, segv или abort в зависимости от параметров среды.

1 голос
/ 22 июня 2011

См. Наш CheckPointer инструмент, который будет проверять правильность каждого доступа к указателю.Это не особенно быстро, но он будет ловить ошибки, которые не распознает даже Valgrind (например, указатели на освобожденные кадры стека и т. Д.)

Другой ответ на этот вопрос показывает случай, когда выполнение чистогопроверка диапазона памяти на правильность указателя не сможет обнаружить проблему.Он в некотором роде прав в том, что если у вас есть только адреса диапазонов памяти, вы не можете надежно проверить, что перераспределенный блок хранилища используется не по назначению.Это называется temporal error.Связав событие выделения с блоком памяти и диапазоном, вы можете обнаружить это.И Checkpointer сделает это и обнаружит ошибку.

1 голос
/ 18 июня 2010

Вы можете использовать LD_PRELOAD и обернуть malloc внутри своей собственной функции.

0 голосов
/ 16 декабря 2016

Вы можете позвонить malloc_size(my_ptr) в malloc/malloc.h, чтобы получить размер, выделенный вам malloc для вашего указателя, и 0, если указатель не был выделен. Имейте в виду, что malloc изменяет размер выделенного блока, чтобы гарантировать, что из этого указателя можно разыменовать самую ограничительную переменную типа и выровнять память. Поэтому, если вы вызываете malloc (1) (а также malloc (0)), malloc на самом деле возвращает 16 байт (на большинстве машин), потому что самый ограничительный тип имеет размер 16 байт

0 голосов
/ 19 июня 2010

Вы можете использовать те же методы, что и консервативный сборщик мусора , чтобы определить, указывает ли объект, похожий на указатель, на кучу или нет.На самом деле вы, вероятно, могли бы получить исходный код самого bdwgc.Это было бы нетривиальной задачей, но это было бы то, что вы могли бы контролировать и портировать по мере необходимости.(Большая часть работы по переносу уже выполнена).

0 голосов
/ 18 июня 2010

Я сделал нечто подобное, но не могу вспомнить, как именно это было закодировано, и у меня нет кода под рукой.

Но основная идея состояла в том, чтобы переопределить new и deleteдля базового класса.В new был установлен статический флаг (например, bool inDynamicAlloc=true).Этот флаг ставится под сомнение в конструкторе базового класса.Когда это было так, объект был размещен в куче, иначе в стеке.

Конструктор сбрасывает флаг впоследствии.

Надеюсь, это поможет.

0 голосов
/ 18 июня 2010

Выделения памяти имеют (виртуальный) адрес и длину.

Указатель содержит только адрес.

Если вы отслеживаете длину отдельно, вы можете проверить ее содержимое, например:

int check_contained(const char* src,size_t srclen,const char* sub,size_t sublen) {
   return (sub >= src) && (sub+sublen < src+srclen);
}

В Symbian есть функция AllocLen, но нет ни POSIX, ни эквивалента win32.

...