Fix 15 pre-release-audit issues (GH 201-244): preprocessor, lexer, VM, mem2reg, object writers, linker, driver, headers#267
Merged
Merged
Conversation
…orce macro arity The #if constant-expression evaluator carried its integer value in a bare i64 with no signedness, so `>>` forced a logical shift on every operand (C99 6.5.7p5 requires arithmetic for a signed value) and the relational operators compared signed regardless of operand type. IfValue::Int now carries an `unsigned` flag set from a u/U suffix or an over-i64 literal; `>>` and the relational operators select the interpretation from it (6.3.1.8). A zero divisor silently folded to 0; it is now a diagnostic (6.6p4), suppressed by a `live` flag while parsing a short-circuited or not-taken subexpression so a dead operand (`1 ? 2 : 1/0`) still compiles. Function-like macro calls accepted any argument count; a mismatch is now diagnosed per 6.10.3p4 (variadic and the zero-parameter single-empty-arg rule honored), routed through a parked-error slot drained at the Result-returning chokepoints. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…prefix A wide-string element was written at wchar_t width unconditionally, so a code point above U+FFFF truncated to its low 16 bits on a 2-byte wchar_t target. It is now emitted as a UTF-16 surrogate pair (C99 6.4.5, Unicode D91). Separately, `0x` with no following digit was accepted as 0; C99 6.4.4.1 requires at least one hex digit, checked after the hex-float branch so `0x.5p0` stays valid. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
read_cstring widened each C-string byte to a Rust char (Latin-1), then printf re-encoded it as UTF-8, mangling any byte >= 0x80. The formatter now carries a Vec<u8> end to end via read_cstring_bytes and writes raw bytes; the &str host-bridge callers use a from_utf8_lossy wrapper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A slot read on a path with no dominating store was promoted, injecting a join phi with an undefined predecessor edge that the rename could not complete; the dead phi still held a register and drove a predecessor-exit move. Such slots are now excluded from promotion up front by testing entry-block live-in (the liveness the pruned-SSA placer already computes), which is exactly the rename's failed set. Only c4 snapshots change: the orphan phi and its register are gone. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0.1.0The symbol-version payloads were wired into PT_DYNAMIC but had no entries in the section-header table or shstrtab, so section-based tooling could not locate them. SHT_GNU_versym / SHT_GNU_verneed headers are now emitted when a versioned import is present, with a single ver_shdrs term shifting every following section index (including the export st_shndx) uniformly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The comment attributed the missing callee-saved GPR descriptions to a zero FrameOffset; the real blockers are the descending-prologue-offset rule and the body's per-call RSP moves, so a faithful description needs a push-before-setframe prologue restructure. Corrected the rationale and added a regression test asserting the current no-UWOP_SAVE_NONVOL shape, to be flipped when that restructure lands. Execution is unaffected; badc emits no exception-using code. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bind-opcode dylib selector only used the 4-bit IMM form and masked the ordinal, so more than 15 dylibs would bind against the wrong library. It now emits BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB past 15. The nlist entry for a flat-lookup import now shares the bind stream's flat-lookup branch and carries DYNAMIC_LOOKUP_ORDINAL instead of a two-level ordinal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The defined-symbol pass skipped every binding other than STB_GLOBAL, so a weak definition in a foreign object was dropped and a reference to it reported as undefined. Weak definitions are now collected into a separate table and folded behind strong ones: a strong definition wins silently and order-independently, a weak definition on its own satisfies a reference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Input classification treated the first token with an unrecognized extension, and everything after it, as the program's argv, but only --jit / --interp consume argv; a mistyped source in a native/-c/--ar build was silently dropped. Program-argv collection is now gated on the run modes; other modes report the unrecognized input. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
INT32_MIN and INT64_MIN were unary minus applied to an out-of-range positive literal, giving the macro a wider-than-intended type (and an unrepresentable operand for the 64-bit case). They now use the `(-MAX-1)` form, matching C99 7.18.2 and the limits.h sibling; every derived signed minimum aliases these. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Note in std-conformance.md and the README/preprocessor docs that string equality in a #if controlling expression is a c5 extension over C99 6.10.1p4 (the string-valued __BADC_TARGET__ / __BADC_VERSION__ gating relies on it), and record the x86_64 Windows unwind limitation so it is not mistaken for working SEH support. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A #pragma binding(data dll::local, "export") admitted as a PE import recorded the local name in the import table and fell back to dylib 0: the loader then looked up the local name in the wrong DLL and failed with STATUS_ENTRYPOINT_NOT_FOUND when the two names differed. Carry each data binding's dylib index through the .note.badc binding map (keyed by the local name, which is the UNDEF the linker records) and resolve the import's real_symbol from the copy-reloc local->host pair at synth time. Every shipped binding names local == export and lives in the first dylib, so current images are byte-identical. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… slots The runtime defined environ and _environ as zeroed locals that shadowed <stdlib.h>'s msvcrt data bindings, so direct iteration saw an empty environment; a spawned child inheriting that view got a block without SystemRoot and Winsock init failed in it (WSAEPROVIDERFAILEDINIT). On arm64 the same emptiness came from _wenviron reading ucrtbase's separate environment copy, which msvcrt's _wgetenv priming never touches. x64 msvcrt exports the vectors as data: bind _environ / _wenviron by export name and alias POSIX environ to the _environ export, all loader-filled imports of the live CRT view. arm64 msvcrt exports no environment data, so route the family through its _get_environ / _get_wenviron accessors instead of ucrtbase's. The runtime defines none of them, and putenv now binds to msvcrt _putenv. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… Mach-O) Symbol resolution prefers a definition, so a #pragma binding(data ...) local defined anywhere in the image silently lost the binding and read a slot nothing populates; on ELF that dual is the COPY-relocation design, but PE and Mach-O have no copy semantics. Fail the link with the collision named instead of shipping the dead read. The Win64 DLL-name test drops its host prelude: on a Linux host the prelude's time.h data bindings ride into the PE-target link and are now rejected as collisions with the tentative tz slots. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The ignore attributed the child's WSAStartup failure (WinError 10106) to the spawn environment, but script_helper copies os.environ into the child verbatim: a block missing SystemRoot meant the parent's os.environ was already empty. That was the wide-environment defect -- _wenviron read ucrtbase's copy, which msvcrt's _wgetenv priming never populates -- fixed by routing the family through msvcrt's accessors, so the test now passes where it runs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the 15 open issues from the v0.0.9 pre-release audit in the GH 201–244 range. Each is a structural fix motivated by C99 or existing platform practice, with a regression test. 12 commits, one per subsystem cluster.
Fixes by area
IfValue::Intgains a signedness flag → arithmetic vs logical>>and unsigned-aware relational (C99 6.5.7p5 / 6.3.1.8);#ifdiv/mod-by-zero diagnosed with aliveflag for short-circuited arms (6.6p4); function-like macro arity checked (6.10.3p4)0xwith no hex digits (6.4.4.1)printf%s/%ccarry raw bytes end-to-end; no Latin-1↔UTF-8 round-tripSHT_GNU_versym/verneedsection headers when a versioned import is presentDYNAMIC_LOOKUP_ORDINAL-c/--armodes(-MAX-1)idiom forINT32_MIN/INT64_MINenviron/_environ/_wenvironpublished from__getmainargsenvp#ifstring-literal extension and the x64 unwind gap recorded in std-conformance.mdNotes
UWOP_SAVE_NONVOLcannot describe the current mov-below-rbp saves given the descending-offset rule and the body's per-call RSP moves. It has zero execution impact (badc emits no exception-using code), so this PR takes the issue's documented-limitation option: accurate rationale + a test that locks the current no-SAVE_NONVOLshape (to be flipped when the restructure lands).c4.*SSA/asm snapshots change (the read-before-write fixture): the orphan single-incoming phi and its register are gone (−52 x64 instructions); the other 595 fixtures are byte-identical.Validation
cargo test(debug): 1018 passed, 0 failedcargo test --release --lib: passedcargo fmt --check+clippy -D warnings --all-targets: cleanCloses #201
Closes #202
Closes #204
Closes #205
Closes #213
Closes #214
Closes #219
Closes #221
Closes #222
Closes #223
Closes #229
Closes #234
Closes #239
Closes #240
Closes #244
Closes #240 #268 #269 #270
🤖 Generated with Claude Code