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

Предположим, что я выделил память для некоторого указателя в функции foo:

void foo()
{    
    // ...  
    int *ptr = malloc(20*sizeof(int));  

    bar (ptr);
}  

От foo(), я передаю этот указатель на bar() и скажу от bar() к другой функции.

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

Есть ли какой-либо возможный способ, не ища выражения:

int *ptr = malloc(20*sizeof(int)); 

чтобы выяснить, сколько памяти выделено указателю, используя GDB?

Спасибо.

Ответ 2

В общем, нет. C не предоставляет способ получить размер выделенного блока памяти. Вам нужно следить за тем, сколько памяти вы выделили себе.

НО, в некоторых библиотеках C есть функция для получения полезного размера блока памяти - malloc_usable_size (найдено в <malloc.h> в системах Linux без man-страницы). Обратите внимание, что это не работает на всех libcs ​​и может сообщить значение больше, чем вы запросили. Пожалуйста, используйте его только для отладки.

Для полноты моего первоначального ответа, который погружается в метаданные низкоуровневого кучи, до @Employed Russian, указывающего malloc_usable_size:

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

ПРЕДУПРЕЖДЕНИЕ: серьезно, НЕ используйте это, кроме как для отладки в gdb. В самом деле. Я имею в виду.

Распределитель памяти glibc хранит такие фрагменты памяти (из комментария doc в malloc/malloc.c):

    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of previous chunk, if allocated            | |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of chunk, in bytes                       |M|P|
      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             User data starts here...                          .
            .                                                               .
            .             (malloc_usable_size() bytes)                      .
            .                                                               |
nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |             Size of chunk                                     |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Ваши данные здесь находятся в "mem", а размер чанка включает заголовок. Флаг P указывает, действительны ли данные предыдущего блока, а M указывает, что это отображение mmap (для больших mallocs). Все это не слишком важно; важно то, что размер живет с одним размером указателя до вашей памяти; вам просто нужно замаскировать эти флаги и вычесть размер заголовка:

Breakpoint 1, main () at test.c:8
8               char *a = malloc(32);
(gdb) n
10              free(a);
(gdb) print (*((unsigned long long*)a - 1) & ~3) - sizeof(unsigned long long)*2
$14 = 32

Предостережение. Фактически выделенный размер может быть больше, чем вы запросили. Не пытайтесь умудряться и использовать избыток. Спросите, сколько вам нужно в начале.

Caveat 2: Это работает только с glibc. И он работает только с определенными версиями glibc. и, таким образом, может прерываться в любой момент без предупреждения. Я не могу это подчеркнуть; НЕ используйте это в своем действительном коде; только для отладки, когда вы исчерпали все остальные варианты. Ваш код должен самостоятельно отслеживать размеры своих буферов.

Ответ 3

Нет. Вы должны хранить эту информацию самостоятельно, когда вы malloc().