Является ли malloc детерминированным? - PullRequest
25 голосов
/ 17 ноября 2011

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

Примечание: Здесь я говорю только о виртуальной памяти, а не физической.

Ответы [ 7 ]

27 голосов
/ 17 ноября 2011

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

Эта случайность может быть полезна при написании трудностей. Чтобы успешно использовать переполнение буфера, вам обычно нужно сделать две вещи:

  1. Доставить полезную нагрузку в предсказуемую / известную область памяти
  2. Заставить выполнение перейти к этому месту

Если область памяти непредсказуема, сделать этот переход может быть намного сложнее.

Соответствующая цитата из стандарта §7.20.3.3 / 2:

Функция malloc выделяет пространство для объекта, размер которого определяется размером и значение которого не определено

Если бы это было намерение сделать его детерминированным, тогда это было бы четко указано как таковое.

Даже если сегодня это выглядит детерминистически, я бы не стал делать ставку на то, чтобы оно оставалось таким с более новым ядром или более новой версией libc / GCC.

11 голосов
/ 17 ноября 2011

Спецификация C99 (по крайней мере, в ее окончательном открытом проекте ) в 'J.1 Unspecified поведения' гласит:

Следующие не определены: ... Theпорядок и непрерывность памяти, выделяемой последовательными вызовами функций calloc, malloc и realloc (7.20.3).

Таким образом, кажется, что malloc не должен быть детерминированным.Поэтому небезопасно предполагать, что это так.

7 голосов
/ 17 ноября 2011

Это полностью зависит от реализации malloc.Не существует внутренней причины, по которой конкретная реализация malloc могла бы вводить недетерминированность (за исключением, возможно, в виде нечеткого теста приложения, но даже тогда он должен быть отключен по умолчанию).Например, Doug Lea's malloc не использует rand(3) или каких-либо аналогичных методов в нем.

Но, поскольку malloc выполняет вызовы ядра, такие как sbrk(2) или mmap(2) в Linux или VirtualAlloc в Windows, эти системные вызовы не всегда могут быть детерминированными, даже в иных идентичных процессах.Ядро может решить намеренно предоставить разные mmap 'ed-адреса в разных процессах по любой причине.

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

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

2 голосов
/ 17 ноября 2011

Да, в некоторой степени это детерминировано, но это не обязательно означает, что он даст одинаковые результаты в двух форках процесса.

Например, в спецификации Single Unix сказано: "[...] чтобы избежать ошибок, дочерний процесс может выполнять только асинхронно-безопасные операции до тех пор, пока не будет вызвана одна из функций exec. "

К лучшему или худшему, malloc равно не в списке функций «async-signal-safe».

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

Вывод: вы не можете рассчитывать на malloc, производящие идентичные результаты в родительском и дочернем элементах.Если программа многопоточная, вы не можете рассчитывать на malloc, работающую вообще на дочернем объекте, пока она не вызовет exec - и есть место для резкого вопроса, действительно ли она гарантированно работает даже в однопоточном дочернем процессоредо того, как ребенок вызовет exec.

Ссылки:

  1. fork спецификация
  2. функции асинхронного безопасного сигнала
2 голосов
/ 17 ноября 2011

Это зависит от подробных реализаций malloc.Типичная реализация malloc (например, dlmalloc ) была детерминированной.Это просто потому, что сам алгоритм является детерминированным.

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

Кроме того, когда вы форкаете процесс,различные источники случайности, включая ASLR .

0 голосов
/ 17 ноября 2011

Вы не получите тот же физический адрес. Если у вас есть процессы A и B, каждый вызов malloc возвращает адрес свободного блока. Порядок, в котором A и B вызывают malloc, непредсказуем. Но это никогда не происходит "в один и тот же момент".

0 голосов
/ 17 ноября 2011

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

Linux использует копирование при записи для разветвления, поэтому разветвленные дети делят память своих родителей, пока что-то не изменится ни в одном из процессов. В этот момент ядро ​​проходит последовательность копирования памяти, чтобы дать разветвленному потомку свою собственную выделенную / уникальную копию своего пространства памяти.

...