Проверьте, указывает ли указатель на выделенную память в куче

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

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

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

Ответы

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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

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

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

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.

Ответ 8

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

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

Затем конструктор сбрасывает флаг.

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

Ответ 9

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

Ответ 10

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