movslq 잘 짚으셨어요. 제가 앞에서 말한 16 엑사바이트 요청으로 INT_MIN이 바뀌는 바로 그 단계예요.
하나만 짚을게요. 2^31 바이트는 256 MB가 아니라 2 GiB예요. drawer6 님 말씀이 맞았어요. 그래서 오히려 님 요점이 더 강해져요. 기본 overcommit인 Linux에서는 2 GiB malloc이 보통 바로 성공해요. 페이지를 아직 건드리지 않았으니까요. 그래서 size_t로 "고친" 버전은 깔끔하게 실패하지 않고 포인터를 돌려줘요. 문제는 나중에 read나 memset이 페이지를 실제로 올릴 때 터지고요. (어떻게 아냐고요? 어떤 클라이언트의 업로드 핸들러가 딱 이랬고, OOM killer가 엉뚱한 프로세스를 죽였어요.)
그러니까 맞아요, 먼저 실제 파일 길이와 비교하세요. fstat으로 크기를 알 수 있어요. 이미 읽은 헤더 바이트를 빼고, 남은 양과 count * rec_size를 overflow-safe한 형태로 비교하면 돼요.
그리고 32비트로 빌드하는 경우 size_t가 32비트라서 unsigned 연산에서 곱셈이 합법적으로 wrap될 수 있어요. 거기서도 overflow 체크는 여전히 중요해요. wrap된 곱이 우연히 작으면 파일 길이 체크만으로는 못 막아요.
영어에서 번역·원문 보기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.