обновление библиотеки C, повреждение кучи

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

HANDLE BmiDibAlloc(size_t uBytes)
{   
    HANDLE alloc = malloc(uBytes + sizeof (size_t));

    if (alloc != NULL) 
    {
        memcpy_s(alloc, sizeof (alloc), &uBytes, sizeof (size_t));
    }

    return BmiDibAttach(alloc); //just tracks the number of memory allocs for logging
}

BOOL BmiDibFree(HANDLE hdib)
{
    if (!hdib) {
        return TRUE;
    }
    free(hdib);
    // Forget this handle:
    return BmiDibDetach(hdib);
}

Поскольку я больше не могу использовать GlobalSize, я увеличиваю размер выделения в первом байте sizeof (size_t)...

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


person Tom Fobear    schedule 20.01.2012    source источник
comment
Ваш код выглядит нормально, возможно, проблема где-то в остальной части кода; единственная ошибка, которую я вижу, это то, что sizeof(alloc) неверно, должно быть sizeof(size_t) (хотя я думаю, что на каждой платформе Windows sizeof(HANDLE)==sizeof(void *)==sizeof(size_t)).   -  person Matteo Italia    schedule 21.01.2012
comment
@MatteoItalia, вы понимаете, почему мне нужно это сделать, верно? Некоторые части библиотеки ранее использовали GlobalSize() при распределении. Возможно, я мог бы заменить его на sizeof (*alloc), если бы он не был пустым *.   -  person Tom Fobear    schedule 21.01.2012
comment
если вы добавляете размер, убедитесь, что все, что использует эту память, не испортит ее? И учтите, что блок памяти на самом деле является uBytes + sizeof (size_t), если вы, например. изменить его размер?   -  person nos    schedule 21.01.2012
comment
@Matteo: На самом деле в Win64 void * 64-битный, а size_t 32-битный...   -  person R.. GitHub STOP HELPING ICE    schedule 21.01.2012
comment
@R.: ну, это интересно, это означает, что даже на 64-битных платформах объект (таким образом, даже динамически выделяемый массив) не может быть больше 4 ГБ ... звучит как компромисс совместимости.   -  person Matteo Italia    schedule 21.01.2012
comment
Да, винда отстой. Что вы ожидали? :-)   -  person R.. GitHub STOP HELPING ICE    schedule 21.01.2012


Ответы (2)


Когда вы выделяете блок, вы выделяете немного больше места, сохраняете свой заголовок в начале блока, а затем возвращаете указатель на смещение внутри блока (не начало блока). Например, «вернуть alloc + sizeof (MY_HEADER)».

Когда вы освобождаете блок, вы должны сделать обратное. Например:

BOOL BmiDibFree(HANDLE callerPointer)
{
    actualPointer = callerPointer - sizeof(MY_HEADER);
    free(actualPointer);

Примечание 1. Для повышения производительности вы должны убедиться, что "sizeof(MY_HEADER)" кратен минимальному выравниванию, обеспечиваемому "malloc()"; так что вы не вызываете проблемы с неправильным выравниванием для вызывающего абонента.

Примечание 2. Вы можете добавить «канареечки» (магические числа) в реальное начало блока и в реальный конец блока и проверить их (во время free и realloc), чтобы увеличить вероятность обнаружения повреждения кучи. Я делаю это и устанавливаю флаг «куча была повреждена» и проверяю этот флаг перед любой malloc/free/realloc (если куча была повреждена, все последующие операции завершатся сбоем немедленно, чтобы избежать увеличения беспорядка).

Примечание 3. Вы можете использовать условную компиляцию (например, "#ifdef DEBUGGING") для включения/отключения различных функций вашей оболочки. Я также делаю это - один для включения дополнительной проверки (канареек) и один для включения сбора/отчетности статистики (общее количество выделенных блоков, максимальное количество блоков, выделенных в любое время, общее количество выделенных байтов, максимальное количество байтов, выделенных в любое время).

person Brendan    schedule 21.01.2012

Q: Вы действительно имеете в виду "sizeof (size_t)"? Обычно это всего 4 байта. То же самое с "sizeof(alloc)" - это, наверное, просто "4".

person paulsm4    schedule 20.01.2012
comment
предназначен sizeof (size_t), я хочу выделить дополнительные 4 байта для хранения размера выделения. Размер (alloc), о котором я даже не думал, должен быть количеством (элементов?) в alloc... но, учитывая, что alloc - это void * (HANDLE), который будет размером с указатель? (4 байта также на моей 32-битной ОС, не ломается, но также технически неправильно) - person Tom Fobear; 21.01.2012