Какое ограничение на параметр malloc типа size_t в C?Документы говорят, что он имеет верхний предел UINT_MAX, но я не могу выйти за пределы INT_MAX - PullRequest
3 голосов
/ 02 марта 2012

Я хочу выделить массив из 2.9GB с

  database = (char*) malloc((2900 * 1000000 * sizeof(char)));

. Это дает целочисленное предупреждение о переполнении, и malloc возвращает NULLПараметр malloc имеет тип size_t, который согласно документации имеет тип unsigned int.

Таким образом, максимальное значение должно быть UINT_MAX, что составляет не менее 2,9 ГБ.Однако, если я пытаюсь выделить больше, чем MAX_INT, malloc завершится неудачно.Означает ли это, что size_t в моей системе имеет тип int?Как мне это проверить?Я просмотрел

/usr/include/stdlib.h 

и

./lib/gcc/x86_64-redhat-linux/4.1.1/include/stddef.h 

, но не могу найти определение size_t.Большое спасибо

Ответы [ 3 ]

10 голосов
/ 02 марта 2012

Параметр имеет тип size_t, и malloc требуется для принятия любого возможного значения типа size_t. Обратите внимание, что «принять» не означает, что требуется выделять так много; все это означает, что malloc не разрешается неверно истолковывать очень большое число, которое вы даете ему, как маленькое / отрицательное число из-за проблем переполнения, тем самым возвращая слишком маленький буфер и создавая критическую необнаружимую уязвимость, от которой ваша программа не может защитить. Существует множество возможных причин, по которым malloc может не выделить очень большие объекты:

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

В этом случае я подозреваю, что вы могли видеть третьи, произвольные пределы, хотя я бы не считал их настолько произвольными. Есть очень веская причина, чтобы запретить выделения (и существование любых объектов) больше SIZE_MAX/2: учет различий между указателями в таких больших объектах приведет к (чрезвычайно опасному) переполнению целых чисел и неопределенному поведению, когда результат не помещается в (подписанный) тип ptrdiff_t. Таким образом, в надежной 32-разрядной системе размер виртуального адресного пространства составляет 4 ГБ, а максимальный размер любого отдельного объекта - 2 ГБ.

9 голосов
/ 02 марта 2012

Здесь есть два вопроса.

Во-первых, предупреждение о переполнении: 2900 и 1000000 имеют тип int, поэтому результат их умножения также имеет тип int. Результат не может быть представлен 32-разрядным целым числом со знаком, поэтому он переполняется. Вам нужно привести один (или оба) аргумента к size_t, чтобы использовать арифметику без знака.

(Или вы можете переместить sizeof(char) в качестве одного из первых двух слагаемых, поскольку его тип - size_t, хотя вы также можете просто удалить sizeof(char), поскольку это всегда 1.)

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

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

size_t определенно не int, потому что int всегда подписано, а size_t всегда без знака.

1 голос
/ 28 сентября 2017

Максимальный размер, который может выделить malloc, зависит как от платформы, на которой вы работаете, так и от текущего состояния программы.Если для удовлетворения запроса недостаточно смежного адресного пространства, то malloc явно потерпит неудачу.

...