Указатель, переданный free (), должен указывать на начало блока памяти, или он может указывать на внутреннюю часть? - PullRequest
6 голосов
/ 04 января 2011

Вопрос в названии ... Я искал, но ничего не смог найти.


Edit:

Я не вижу необходимости объяснять это, но поскольку люди думают, что то, что я говорю, не имеет смысла (и что я задаю неправильные вопросы), вот проблема:

Так как люди, кажется, очень заинтересованы в "коренной" причине всей проблемы, а не в самом задаваемом вопросе (так как это, очевидно, помогает решить проблемы лучше, давайте посмотрим, так ли это), вот проблема:

Я пытаюсь создать библиотеку времени выполнения D на основе NTDLL.dll, чтобы я мог использовать эту библиотеку для подсистем, отличных от подсистемы Win32. Так что это заставляет меня связываться только с NTDLL.dll.

Да, я знаю, что функции «недокументированы» и могут измениться в любое время (даже если бы я поспорил на сто долларов, что wcstombs все равно будет делать то же самое точно вещь 20 лет, если он еще существует). Да, я знаю, что людям (особенно Microsoft) не нравятся разработчики, ссылающиеся на эту библиотеку, и что меня, вероятно, будут критиковать за право здесь. И да, эти два пункта выше означают, что такие программы, как chkdsk и defragmenters, которые запускают до подсистему Win32, даже не должны создаваться в первую очередь, потому что в буквальном смысле невозможно связать что-либо вроде kernel32. dll или msvcrt.dll и до сих пор имеют исполняемые файлы, родные для NT, поэтому мы, разработчики, должны просто притвориться, что эти этапы навсегда останутся за пределами нашей досягаемости.

Но нет , я сомневаюсь, что кто-то здесь хотел бы, чтобы я вставил несколько тысяч строк кода и помог мне просмотреть их и попытаться выяснить, почему отказывающие выделения памяти отклоняются Исходным кодом я модифицирую. Вот почему я спросил о проблеме, отличной от «первопричины», хотя якобы она известна сообществу как лучшая практика.

Если что-то все еще не имеет смысла, не стесняйтесь оставлять комментарии ниже! :)


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

После примерно 8 часов отладки я наконец нашел проблему:

Оказывается, что RtlReAllocateHeap() действительно не автоматически работает как RtlAllocateHeap(), если указатель на него равен NULL.

Ответы [ 4 ]

12 голосов
/ 04 января 2011

Он должен указывать на начало блока.Безопасно передавать нулевой указатель на free(), но передача любого указателя, не выделенного malloc() или одним из его родственников, вызовет неопределенное поведение.Некоторые системы выдадут вам ошибку времени выполнения - что-то вроде «Отмена выделения указателя, не имеющего неправильного расположения».

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

Я написал тестовую программу для получения сообщения об ошибке.На моей машине эта программа:

#include <stdlib.h>

int main(int argc, char **argv)
{
  int *x = malloc(12);
  x++;

  free(x);

  return 0;
}

Вылетает с этим сообщением:

app(31550) malloc: *** error for object 0x100100084: pointer being freed was not allocated
4 голосов
/ 04 января 2011

Элемент only , который вы можете передать free, - это указатель, возвращенный вам из malloc (или calloc, realloc и т. Д.) Или NULL.

Я предполагаю, что вы спрашиваете, потому что у вас есть какая-то функция, когда вы делаете malloc, и вы хотите связываться с блоком данных, а затем избавляться от него, когда вы закончите, и вы не хотите возьмите с собой копию оригинального указателя. Это не работает таким образом.

1 голос
/ 04 января 2011

Судя по комментариям, которые вы добавили к существующим ответам, вы задаете неправильный вопрос.Если вам нужно выравнивание памяти, почему бы вам не задать этот вопрос?Спросите о коренной проблеме, а не спрашивайте о своем решении!

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

Выравнивание выделенной памяти поддерживается в Win32на _aligned_malloc().Это более или менее эквивалентно POSIX memalign()

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

void* aligned_malloc( size_t size, size_t alignment )
{
    void* unaligned = malloc( size + alignment ) ;
    void* aligned = (void*)(((intptr_t)unaligned + alignment) & ~(alignment - 1));
    void** free_rec_ptr = ((void**)aligned - 1) ;
    *free_rec_ptr = unaligned ;

    return aligned ;
}

void aligned_free( void* block )
{
    void** free_rec_ptr = ((void**)block - 1) ;
    free( *free_rec_ptr ) ;
}

Аргумент alignment должен бытьсила двух.

0 голосов
/ 05 января 2011

FWIW, в прошлый раз, когда я смотрел, как библиотека времени выполнения C работала с malloc и free, блок, который дает вам malloc, на самом деле имеет несколько дополнительных слов с отрицательными смещениями относительно указателя, который дает вам,Они говорят такие вещи, как, насколько большой блок, и другие вещи.free полагался на возможность найти эти вещи.Не знаю, проливает ли это свет.

...