Хорошо подмечено про movslq. Именно на этом шаге INT_MIN превращается в тот запрос на 16 эксабайт, о котором я говорил выше.
Одна придирка. 2^31 байт — это 2 GiB, а не 256 MB. drawer6 был прав. Это только усиливает ваш аргумент. В Linux с overcommit по умолчанию malloc на 2 GiB обычно проходит мгновенно, потому что страницы ещё не тронуты. Так что "исправленная" версия с size_t не падает чисто. Она возвращает указатель, а проблемы начинаются позже, когда чтение или memset подгружают страницы. (Спросите, откуда я знаю. Однажды обработчик загрузок у клиента делал ровно это, и OOM killer прибил не тот процесс.)
Так что да, сначала сравнивайте с реальной длиной файла. Размер даёт fstat. Вычтите байты заголовка, которые уже прочитаны, и проверьте count * rec_size против оставшегося, в форме, безопасной от переполнения.
Кроме того, если кто-то собирает это под 32 бита, size_t там 32-битный, и умножение может законно завернуться в беззнаковой арифметике. Проверка переполнения там всё равно нужна. Одна проверка длины файла вас не спасёт, если завёрнутое произведение случайно окажется маленьким.
Переведено с английского·Показать оригиналGood catch on the movslq. That's the exact step where INT_MIN turns into the 16-exabyte request I was waving at earlier.
One nit, though. 2^31 bytes is 2 GiB, not 256 MB. drawer6 had it right. That makes your point stronger. On Linux with default overcommit, a 2 GiB malloc will usually succeed instantly, because the pages aren't touched yet. So the "fixed" size_t version doesn't fail cleanly. It returns a pointer, and the trouble starts later, when the reads or a memset fault the pages in. (Ask me how I know. A client's upload handler once did exactly this, and the OOM killer took out the wrong process.)
So yes, compare against the real file length first. fstat gives you the size. Subtract the header bytes you've already consumed, and check count * rec_size against what's left, using the overflow-safe form.
Also, if anyone builds this for 32-bit, size_t is 32 bits and the multiply can wrap legally in unsigned arithmetic. The overflow check still matters there. The file-length check alone won't save you if the wrapped product happens to be small.