Как работает Mallo c со строгим псевдонимом - его можно нарушать только в пределах одного модуля компиляции? - PullRequest
3 голосов
/ 12 апреля 2020

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

Все распределители памяти кучи, на которые я смотрел до сих пор, делят свою память на какие-то блоки с заголовком впереди. Однако mallo c возвращает void * и обычно указывает на память сразу после заголовка. Вот очень суженный пример, чтобы проиллюстрировать это.

#include <stddef.h>

struct block_header {
  size_t size;
};

struct block_header *request_space(size_t size);

void *malloc(size_t size) {
    struct block_header *block = request_space(size);

    // I guess this violates strict aliasing, because the caller will 
    // convert the pointer to something other than struct block_header?
    // Or why wouldn't it?
    return block + 1;
}

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

Ответы [ 3 ]

3 голосов
/ 13 апреля 2020

Согласно стандарту, эти вещи никогда не нарушают строгое псевдонимы:

  • Создание указателя.
  • Выполнение арифметики указателя c.
  • Запись в mallo c пробел.

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

Текст правила находится в C11 6.5 / 7:

Объект должен иметь свое сохраненное значение, доступное только [...]

и текст в 6.5 / 6 объясняет, что если мы находимся в малло c d, то запись записывает тип записи в место назначения (и, следовательно, не может быть несовпадения типов).

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

Сноска 1: 6.5 / 6, по-видимому, неисправна согласно ответу комитета на DR236 , но никогда не исправлялся, поэтому кто знает, где это нас оставляет.

Сноска 2: , как указывает Эри c, стандарт не относится к внутренним компонентам реализации, но учтите, что мой комментарии в контексте какого-то написанного пользователем распределителя, как и в другом вопросе, на который вы ссылались.

3 голосов
/ 12 апреля 2020

Исходный код malloc не обязательно должен соответствовать стандарту C так, как нормальный исходный код. Это часть реализации C.

Люди, работающие с malloc, компилятором и другими частями реализации C, несут ответственность за совместную работу. Это может включать компилятор, обрабатывающий malloc специально и malloc с использованием поведения, гарантированного ему компилятором C, но не стандартом C.

0 голосов
/ 13 апреля 2020

Стандарт C сознательно избегает требования, чтобы все реализации были пригодны для всех целей. Вместо этого он предназначен для того, чтобы реализации, предназначенные для различных целей, могли в качестве формы «соответствующего расширения языка» конструктивно обрабатывать конструкции способами, которые были бы полезны для этих целей, даже если Стандарт не предъявляет никаких требований. Таким образом, Стандарт позволяет реализациям, предназначенным для задач, требующих ручного управления памятью, поддерживать «популярные расширения», которые облегчают такие задачи, даже если он намеренно избегает необходимости такой поддержки от реализаций, которые не предназначены для таких задач.

Многие Использование распределителей памяти нецелесообразно для реализации, реализация которой ограничена семантикой, предусмотренной стандартом. Реализации, которые поддерживают принцип Spirit of C, описанный Комитетом как «Не мешайте программисту делать то, что необходимо сделать», однако, и спроектированы и настроены так, чтобы подходить для построения таких распределителей, однако, будут распознавать признаки того, что хранилище будет использоваться как более одного типа. Точный диапазон ситуаций, в которых составители признают такие признаки, был оставлен как вопрос «качества реализации» вне юрисдикции Стандарта. С практической точки зрения авторы clang и g cc решили вести себя минимально допустимым образом, за исключением случаев использования -fno-strict-aliasing, но все это означает, что программисты, которые хотят сделать что-то "интересное" с этими компиляторами должен использовать эту опцию. Нет никаких доказательств того, что авторы Стандарта предполагали, что программисты должны будут прыгать через обручи, чтобы приспособиться к ограничениям некачественных реализаций; вместо этого они ожидали, что рынок окажется лучше, чем Комитет, чтобы судить, как компиляторы должны наиболее эффективно вести себя при выполнении sh различных задач.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...