На практике это то же самое. Но есть одна важная функция, которую это дает вам.
Скажите, что вы получаете некоторые данные из сети, а протокол имеет поле, в котором указано, сколько элементов будет содержать массив, который будет отправлен вам. Вы делаете что-то вроде:
uint32_t n = read_number_of_array_elements_from_network(conn);
struct element *el = calloc(1, n * sizeof(*el));
if (el == NULL)
return -1;
read_array_elements_from_network(conn, el, n);
Это выглядит безвредным, не так ли? Ну, не так быстро. Другая сторона соединения была злой и на самом деле отправила вам очень большое число в виде количества элементов, чтобы перевернутое умножение. Предположим, что sizeof(*el)
- 4, а n
- 2^30+1
. Умножение 2^30+1 * 4
обертывает, и результат становится 4, и это то, что вы выделили, пока вы сказали своей функции читать 2^30 + 1 элементов. Функция read_array_elements_from_network
быстро переполнит ваш выделенный массив.
Любая приличная реализация calloc
будет проверять переполнение в этом умножении и будет защищать от такого рода атак (эта ошибка очень распространена).
+1; Я сам это задался. Я хотел бы знать, будет ли это во всех случаях одинаковым; т.е. существует ли стандартный мандат? – Bathsheba