From 211d4488c36d5d54eba679fbc5775162fac52c56 Mon Sep 17 00:00:00 2001 From: JustVugg Date: Fri, 17 Jul 2026 18:49:28 +0200 Subject: [PATCH] =?UTF-8?q?win32:=20stop=20erasing=20the=20real=20ReadFile?= =?UTF-8?q?=20error=20=E2=80=94=20pread=20failures=20name=20their=20WinErr?= =?UTF-8?q?=20(#307)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit compat_pread mapped every non-EOF ReadFile failure to EIO, so the field report was always the same three words: "Input/output error". #307 then burned three rounds of guessing across three people — storage? contention? alignment? — because the actual GetLastError code never appeared anywhere. compat_pread now stashes the code in a per-thread slot and pread_full appends it to the failure line: pread qs: Input/output error (off 780592, 0/8192 bytes, WinErr=1450) That one number is the difference between "insufficient system resources" (1450 -> memory pressure), "sharing violation" (32 -> AV interference), "device not ready" (21 -> the T: drive itself) and a dozen other distinct diagnoses. Diagnostic only: no behavior change, no retry policy — that discussion lives in #361 and should be settled AFTER the first report tells us which error we are actually retrying. Linux path untouched byte-for-byte; the Windows compile is certified by the check.yml MSYS2 job. Co-Authored-By: Claude Opus 4.8 --- c/compat.h | 7 +++++++ c/glm.c | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/c/compat.h b/c/compat.h index 82de8b6..a21bbd8 100644 --- a/c/compat.h +++ b/c/compat.h @@ -143,6 +143,12 @@ static inline int compat_fadvise(int fd, off_t off, off_t len, int advice){ * Thread-safe (no shared seek position). Gestisce offset >4 GB e chunking * per letture >2 GB (anche se i tensori individuali sono nell'ordine dei * MB-centinaia di MB, il wrapper e' robusto per ogni taglia). */ +/* Ultimo GetLastError() di una ReadFile fallita, per thread: il chiamante + * (pread_full in glm.c) lo stampa accanto a strerror. Senza questo, OGNI + * fallimento Windows collassa in "EIO -> Input/output error" e la diagnosi + * dal campo diventa un tirare a indovinare (#307: tre giri di ipotesi tra + * tre persone perche' il codice vero non compariva da nessuna parte). */ +static __thread DWORD compat_pread_lasterr __attribute__((unused)); static inline ssize_t compat_pread(int fd, void *buf, size_t n, off_t off){ intptr_t osfh = _get_osfhandle(fd); if(osfh == -1 || osfh == -2){ errno = EBADF; return -1; } @@ -158,6 +164,7 @@ static inline ssize_t compat_pread(int fd, void *buf, size_t n, off_t off){ if(!ReadFile(h, (char*)buf + total, chunk32, &rd, &ov)){ DWORD err = GetLastError(); if(err == ERROR_HANDLE_EOF) break; /* past EOF → return bytes read (0 if none, matching POSIX pread) */ + compat_pread_lasterr = err; /* preserva il codice VERO per il report (#307) */ if(err == ERROR_INVALID_HANDLE || err == ERROR_INVALID_FUNCTION) errno = EBADF; else errno = EIO; return -1; diff --git a/c/glm.c b/c/glm.c index 30d970a..003a42d 100644 --- a/c/glm.c +++ b/c/glm.c @@ -1732,8 +1732,14 @@ static int pread_full(int fd, void *buf, int64_t n, int64_t off, const char *tag while(got