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

StackOverflow https://stackoverflow.com/questions/1208644

Вопрос

Возможные дубликаты:
Как я могу получить размер массива из указателя в C?
Есть ли какой-нибудь способ определить размер массива C ++ программно?А если нет, то почему?

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

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

Заранее спасибо, Андреас

Редактировать:

Я использую VC ++ 2005 в Windows и GCC 4.3 в Linux

РЕДАКТИРОВАТЬ 2:

У меня есть _msize в VC ++ 2005 К сожалению, это приводит к исключению в режиме отладки....

РЕДАКТИРОВАТЬ 3:

Что ж.Я попробовал способ, который я описал выше, с исключением, и это работает.По крайней мере, пока я отлаживаю и гарантирую, что сразу после вызова для выхода из библиотеки я перехожу границы буфера.Работает как заклинание.

Это просто не элегантно и никоим образом не может быть использовано в производственном коде.

Это было полезно?

Решение

Это не стандартно, но если в вашей библиотеке есть msize() функция, которая даст вам нужный размер.

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

Другие советы

Если вы не возражаете против подлого насилия ради отладки, вы можете использовать макросы #define для подключения вызовов к malloc и free и дополнить первые 4 байта соответствующим размером.

Под мелодию

void *malloc_hook(size_t size) {
    size += sizeof (size_t);
    void *ptr = malloc(size);
    *(size_t *) ptr = size;
    return ((size_t *) ptr) + 1;
}

void free_hook (void *ptr) {
    ptr = (void *) (((size_t *) ptr) - 1);
    free(ptr);
}

size_t report_size(ptr) {
    return * (((size_t *) ptr) - 1);
}

тогда

#define malloc(x) malloc_hook(x)

и так далее

Библиотека времени выполнения C не предоставляет такой функции.Кроме того, преднамеренное провоцирование исключения также не скажет вам, насколько велик блок.

Обычно способ, которым эта проблема решается в C, заключается в поддержании отдельной переменной, которая отслеживает размер выделенного блока.Конечно, иногда это неудобно, но, как правило, другого способа узнать это нет.

Ваша библиотека времени выполнения C мочь предоставьте некоторые функции отладки кучи, которые могут запрашивать выделенные блоки (в конце концов, free() нужно знать, насколько велик блок), но любая из подобных вещей будет непереносимой.

С gcc и тот GNU linker, вы можете легко обернуть malloc

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


void* __real_malloc(size_t sz);
void* __wrap_malloc(size_t sz)
{
    void *ptr;

    ptr = __real_malloc(sz);
    fprintf(stderr, "malloc of size %d yields pointer %p\n", sz, ptr);

    /* if you wish to save the pointer and the size to a data structure, 
       then remember to add wrap code for calloc, realloc and free */

    return ptr;
}

int main()
{
    char *x;
    x = malloc(103);

    return 0;
}

и скомпилировать с

gcc a.c -o a -Wall -Werror -Wl,--wrap=malloc

(Конечно, это также будет работать с кодом c ++, скомпилированным с помощью g ++, и с оператором new (через его искаженное имя), если вы пожелаете.)

По сути, статически / динамически загружаемая библиотека также будет использовать ваш __wrap_malloc.

Нет, и вы не можете полагаться на исключение при выходе за его границы, если только это не указано в документации вашей реализации.Это часть того, о чем вам действительно не нужно знать, чтобы писать программы.Покопайтесь в документации вашего компилятора или исходном коде, если вы действительно хотите знать.

Для этого не существует стандартной функции C.В зависимости от вашей платформы может существовать непереносимый метод - какую ОС и библиотеку C вы используете?

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

Средства проверки памяти, такие как Проверка памяти Valgrind и TCMalloc от Google (часть проверки кучи) следите за такого рода вещами.

Вы можете использовать TCMalloc для дампа профиля кучи, который показывает, где что-то было распределено, или вы можете просто проверить, чтобы убедиться, что ваша куча одинакова в двух точках выполнения программы, используя Одинаковый уровень ().

Частичное решение:в Windows вы можете использовать Высота страницы чтобы перехватить доступ к памяти за пределами выделенного блока.

PageHeap - это альтернативный менеджер памяти, присутствующий в ядре Windows (в версиях NT, но в настоящее время никто не должен использовать какую-либо другую версию).Он принимает каждое выделение в процессе и возвращает блок памяти, конец которого совпадает с концом страницы памяти, затем делает следующую страницу недоступной (нет доступа на чтение, нет доступа на запись).Если программа попытается выполнить чтение или запись после конца блока, вы получите нарушение доступа, которое вы можете обнаружить с помощью вашего любимого отладчика.

Как это получить:Загрузите и установите пакет Debugging Tools для Windows от Microsoft: http://www.microsoft.com/whdc/devtools/debugging/default.mspx

затем запустите утилиту GFlags, перейдите на 3-ю вкладку и введите название вашего исполняемого файла, затем нажмите клавишу.Установите флажок PageHeap, нажмите OK, и все готово.

Последнее, что:когда вы закончите отладку, никогда не забудьте снова запустить GFlags и отключить PageHeap для приложения.GFlags вносит этот параметр в реестр (в разделе HKLM\Software\Microsoft\Windows NT\CurrentVersion\Параметры выполнения файла изображения\), поэтому он сохраняется даже при перезагрузках.

Кроме того, имейте в виду, что использование PageHeap может значительно увеличить потребности вашего приложения в памяти.

Способ сделать то, что вы хотите, - это БЫТЬ распределитель.Если вы отфильтруете все запросы, а затем запишете их для целей отладки, то сможете узнать, что вам нужно, когда память освободится.

Кроме того, вы можете проверить в конце программы, были ли освобождены все выделенные блоки, и если нет, то перечислите их.Амбициозная библиотека такого рода могла бы даже занять ФУНКЦИЯ и ЛИНИЯ параметры с помощью макроса, чтобы вы точно знали, где происходит утечка памяти.

Наконец, MSVCRT от Microsoft предоставляет отладочную кучу, содержащую множество полезных инструментов, которые вы можете использовать в своей отладочной версии для поиска проблем с памятью: http://msdn.microsoft.com/en-us/library/bebs9zyz.aspx

В Linux вы можете использовать valgrind для поиска множества ошибок. http://valgrind.org/

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top