Hi, Two independent win32 fixes, found while chasing down why current V (vlang/v) programs built with tcc + Boehm GC crash on startup. Patch 1/2 is a standalone DEF-file parsing bug: pe_load_def() embeds a .def file's quoted/unsuffixed LIBRARY name verbatim into the import table, so any executable linked against a .def file like LIBRARY "libcrypto-4-x64" EXPORTS ... (exactly what OpenSSL's official Win64 installer ships) fails to start with STATUS_DLL_NOT_FOUND, since '"' is not a legal filename character. Confirmed present since at least 2020 (commit 9eef339), still present on current mob. Fix: strip a matched pair of surrounding quotes, and default a missing extension to .dll, matching MSVC's own DEF LIBRARY statement semantics. Verified against the exact repro (quoted, unsuffixed LIBRARY name now links and runs correctly), and re-tested the previously-working unquoted/quoted-with-extension forms to confirm no regression. Patch 2/2 is what actually surfaced while testing patch 1 end-to-end: any tcc-compiled program built with -bt (backtrace support, which is what tccbin's own recommended Windows build config enables by default) that calls OutputDebugString - directly, or via a library, e.g. Boehm GC's Windows logging path - crashes immediately. cpu_exception_handler() in tccrun.c falls into its default case, and therefore terminates the process, for any exception code it doesn't explicitly recognize. DBG_PRINTEXCEPTION_C (0x40010006) is raised internally by Windows as part of OutputDebugString()'s own protocol specifically so an attached debugger can read the string before the process continues; it's supposed to be silently passed through when no debugger is attached, not treated as a fault. Fix: add the missing DBG_PRINTEXCEPTION_C / DBG_RIPEXCEPTION constants to winnt.h (there was a literal gap between DBG_CONTROL_C and DBG_CONTROL_BREAK), and pass DBG_PRINTEXCEPTION_C through via EXCEPTION_CONTINUE_SEARCH instead of reporting+exiting. Verified genuine faults are unaffected - a real null-pointer dereference still reports "invalid memory access" and exits fatally as before; only this one known-benign debugger-notification code is no longer misclassified as a crash. Also verified end-to-end: a V program linking Boehm GC (which needed its own separate fix, unrelated to tcc, for a different old-tinycc-vs-new-tinycc ABI mismatch around setjmp()) now builds and runs correctly with tcc's default -bt/-bcheck flags, with no workaround flags needed. Both patches tested natively on Windows (not under emulation), against current mob (commit d9d02c56 at the time of testing).
Thanks, Richard Wheeler Patch1 From c10de82cde1a27305ea2b99742c8306b8e233d70 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <[email protected]> Date: Wed, 22 Jul 2026 17:40:38 -0400 Subject: [PATCH 1/2] tccpe: strip quotes and default .dll extension in DEF LIBRARY statements pe_load_def() copied the LIBRARY directive's value (via get_token()) verbatim into dllname, with no handling for a quoted string and no fallback to append .dll when the name has no extension. Real-world .def files commonly quote the LIBRARY name and omit the extension (this is exactly what MSVC's own DEF-file parser accepts, and what OpenSSL's official Windows installer ships, e.g. LIBRARY "libcrypto-4-x64"). Since '"' is not a legal filename character, the resulting import table entry can never match any real DLL, and the linked executable fails to start with STATUS_DLL_NOT_FOUND. Strip a matched pair of surrounding quotes, then default a missing extension to .dll, mirroring MSVC's DEF LIBRARY statement semantics. --- tccpe.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tccpe.c b/tccpe.c index c076d084..c15dada9 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1777,7 +1777,7 @@ static char *get_token(char **s, char *f) static int pe_load_def(TCCState *s1, int fd) { - int state = 0, ret = -1, dllindex = 0, ord; + int state = 0, ret = -1, dllindex = 0, ord, len; char dllname[80], *buf, *line, *p, *x, next; buf = tcc_load_text(fd); @@ -1792,7 +1792,17 @@ static int pe_load_def(TCCState *s1, int fd) case 0: if (0 != stricmp(p, "LIBRARY") || next == '\n') goto quit; - pstrcpy(dllname, sizeof dllname, get_token(&line, &next)); + x = get_token(&line, &next); + len = strlen(x); + if (len >= 2 && '"' == x[0] && '"' == x[len - 1]) { + x[len - 1] = 0; + ++x; + } + pstrcpy(dllname, sizeof dllname, x); + /* DEF LIBRARY statements may give a bare module name with no + extension; MSVC's own DEF parser assumes .dll in that case. */ + if (0 == *tcc_fileextension(dllname)) + pstrcat(dllname, sizeof dllname, ".dll"); ++state; break; case 1: -- 2.53.0.windows.2 Patch2 From 6036c98c5c2baea96b21e98dfb510c5214f19c4b Mon Sep 17 00:00:00 2001 From: Richard Wheeler <[email protected]> Date: Thu, 23 Jul 2026 12:06:08 -0400 Subject: [PATCH 2/2] win32: don't treat DBG_PRINTEXCEPTION_C as a fatal crash under -bt cpu_exception_handler(), installed via AddVectoredExceptionHandler() whenever backtrace support is active, fell into its default case - and therefore terminated the process via rt_exit() - for any exception code it didn't explicitly recognize. DBG_PRINTEXCEPTION_C (0x40010006) is raised internally by Windows as part of OutputDebugString()'s own protocol, so that an attached debugger can read the string before the process continues; it is expected to be silently passed through when no debugger is present. Any program compiled with -bt that calls OutputDebugString (directly, or via a library - e.g. Boehm GC's Windows logging path) currently gets killed by this false positive instead. Add the missing DBG_PRINTEXCEPTION_C/DBG_RIPEXCEPTION constants to winnt.h, and pass DBG_PRINTEXCEPTION_C through via EXCEPTION_CONTINUE_SEARCH instead of reporting and exiting. Genuine faults (access violation, stack overflow, divide-by-zero, etc.) are unaffected - only this one known-benign debugger-notification code is no longer misclassified as fatal. --- tccrun.c | 5 +++++ win32/include/winapi/winnt.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/tccrun.c b/tccrun.c index 4ff511df..2873d562 100644 --- a/tccrun.c +++ b/tccrun.c @@ -1409,6 +1409,11 @@ static long __stdcall cpu_exception_handler(EXCEPTION_POINTERS *ex_info) f.ip = *(addr_t*)f.sp; rt_error(&f, "breakpoint/single-step exception:"); return EXCEPTION_CONTINUE_SEARCH; + case DBG_PRINTEXCEPTION_C: + /* raised by OutputDebugString(); benign and expected to be + ignored when no debugger is attached - do not treat it as + a fatal crash. */ + return EXCEPTION_CONTINUE_SEARCH; default: rt_error(&f, "caught exception %08x", code); break; diff --git a/win32/include/winapi/winnt.h b/win32/include/winapi/winnt.h index baace123..1e9876a8 100644 --- a/win32/include/winapi/winnt.h +++ b/win32/include/winapi/winnt.h @@ -789,6 +789,8 @@ typedef DWORD LCID; #define DBG_TERMINATE_THREAD ((DWORD)0x40010003L) #define DBG_TERMINATE_PROCESS ((DWORD)0x40010004L) #define DBG_CONTROL_C ((DWORD)0x40010005L) +#define DBG_PRINTEXCEPTION_C ((DWORD)0x40010006L) +#define DBG_RIPEXCEPTION ((DWORD)0x40010007L) #define DBG_CONTROL_BREAK ((DWORD)0x40010008L) #define DBG_COMMAND_EXCEPTION ((DWORD)0x40010009L) #define STATUS_GUARD_PAGE_VIOLATION ((DWORD)0x80000001L) -- 2.53.0.windows.2
0002-win32-don-t-treat-DBG_PRINTEXCEPTION_C-as-a-fatal-cr.patch
Description: Binary data
0001-tccpe-strip-quotes-and-default-.dll-extension-in-DEF.patch
Description: Binary data
_______________________________________________ Tinycc-devel mailing list [email protected] https://lists.nongnu.org/mailman/listinfo/tinycc-devel
