Skip to content

test(coverage): union coverage across re-imported instances of a module - #35346

Closed
robobun wants to merge 5 commits into
mainfrom
farm/44ef4ced/coverage-reimport-union
Closed

robobun wants to merge 5 commits into
mainfrom
farm/44ef4ced/coverage-reimport-union

Conversation

@robobun

@robobun robobun commented Jul 24, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #35345

Repro

A per-test fresh module instance via cache-busting query imports loses coverage for every instance except the last:

let n = 0;
const load = () => import(`./qs-target?v=${++n}`);

test("instance 1 calls only fnA", async () => {
  expect((await load()).fnA(1)).toBe(4);
});
test("instance 2 calls only fnB", async () => {
  expect((await load()).fnB(1)).toBe(33);
});

bun test --coverage --coverage-reporter=lcov reported FNF:2 FNH:1 and DA:n,0 for fnA's body even though a passing test executed it. Swapping test order swapped which function read 0.

Cause

Each evaluation of the same source URL creates a new JSC source provider with a new sourceID, but the coverage byte-range map (src/sourcemap_jsc/CodeCoverage.rs) is keyed by sourceURL and ByteRangeMapping__generate overwrote the entry on every re-import. Report::generate then queried the control flow profiler for only the surviving (last) sourceID, so basic-block hits from earlier instances were never read. This affected all reporters (lcov DA/FNH, the text table) identically.

Fix

  • ByteRangeMapping keeps the sourceIDs of earlier instances (prior_source_ids) when an entry for the same URL is regenerated; source_id stays the latest, preserving the existing lookup behavior of ByteRangeMapping__find / sourceIDForSourceURL.
  • Report::generate queries the profiler for every instance's sourceID, collects the basic-block and function ranges, and unions per byte range: a range counts as executed if it executed in any instance, and execution counts are summed. The source text is identical across instances, so ranges line up byte-for-byte and one line-offset table serves all of them.
  • The single-instance path is unchanged (no merge step runs), so existing reporter output is byte-identical; the lcov snapshot tests confirm that.

Verification

New test in test/cli/test/coverage.test.ts (two instances, each exercising a different function; asserts FNH:2, no DA:n,0, and LH == LF). Fails on the current release with FNH:1 and zeroed DA lines, passes with this change. The full coverage.test.ts suite (13 tests, including lcov snapshots) passes.


[review] gate passed · iteration 1 · 5 files touched

fails on main (without fix)
ASAN without fix: 1 FAILED
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/cli/test/coverage.test.ts
bun test v1.4.0 (94d6a3ab7)

test/cli/test/coverage.test.ts:
bun test v1.4.0 (94d6a3ab7)

demo.test.ts:
--------------|---------|---------|-------------------
File          | % Funcs | % Lines | Uncovered Line #s
--------------|---------|---------|-------------------
All files     |    0.00 |   66.67 |
 demo.test.ts |    0.00 |   66.67 | 
--------------|---------|---------|-------------------

 0 pass
 0 fail
Ran 0 tests across 1 file. [215.00ms]
(pass) coverage crash [282.17ms]
bun test v1.4.0 (94d6a3ab7)

demo2.ts:

 0 pass
 0 fail
Ran 0 tests across 1 file. [219.00ms]
(pass) lcov coverage reporter [280.07ms]
(pass) coverage excludes node_modules directory [277.34ms]
(pass) coveragePathIgnorePatterns - single pattern string [297.91ms]
(pass) coveragePathIgnorePatterns - partial coverage without nan [302.87ms]
(pass) coveragePathIgnorePatterns - array of patterns [305.05ms]
(pass) coveragePathIgnorePatterns - glob patterns [315.42ms]
(pass) coveragePathIgnorePatterns - lcov reporter [299.67ms]
(pass) cov
... (truncated)

release without fix: all passed
bun test v1.4.0-canary.1 (22b5277de)

test/cli/test/coverage.test.ts:
bun test v1.4.0-canary.1 (22b5277de)

demo.test.ts:

 0 pass
 0 fail
Ran 0 tests across 1 file. [4.00ms]
(pass) coverage crash [6.81ms]
bun test v1.4.0-canary.1 (22b5277de)

demo2.ts:

 0 pass
 0 fail
Ran 0 tests across 1 file. [4.00ms]
(pass) lcov coverage reporter [6.68ms]
(pass) coverage excludes node_modules directory [7.43ms]
(pass) coveragePathIgnorePatterns - single pattern string [7.11ms]
(pass) coveragePathIgnorePatterns - partial coverage without nan [6.58ms]
(pass) coveragePathIgnorePatterns - array of patterns [7.87ms]
(pass) coveragePathIgnorePatterns - glob patterns [6.77ms]
(pass) coveragePathIgnorePatterns - lcov reporter [5.99ms]
(pass) coveragePathIgnorePatterns - invalid config type [1.69ms]
(pass) coveragePathIgnorePatterns - invalid array item [1.60ms]
(pass) coveragePathIgnorePatterns - empty array [6.44ms]
(pass) coveragePathIgnorePatterns - ignore all files [6.46ms]
bun test v1.4.0-canary.1 (22b5277de)

qs-repro.test.ts:
(pass) instance 1 calls only fnA [1.03ms]
(pass) instance 2 calls only fnB [0.32ms]
(pass) bun:jsc codeCoverageForFile sees both instances [2.05ms]

 3 pas
... (truncated)
passes on PR (with fix)
ASAN with fix: all passed
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/cli/test/coverage.test.ts
bun test v1.4.0 (94d6a3ab7)

test/cli/test/coverage.test.ts:
bun test v1.4.0 (94d6a3ab7)

demo.test.ts:
--------------|---------|---------|-------------------
File          | % Funcs | % Lines | Uncovered Line #s
--------------|---------|---------|-------------------
All files     |    0.00 |   66.67 |
 demo.test.ts |    0.00 |   66.67 | 
--------------|---------|---------|-------------------

 0 pass
 0 fail
Ran 0 tests across 1 file. [295.00ms]
(pass) coverage crash [372.90ms]
bun test v1.4.0 (94d6a3ab7)

demo2.ts:

 0 pass
 0 fail
Ran 0 tests across 1 file. [233.00ms]
(pass) lcov coverage reporter [301.28ms]
(pass) coverage excludes node_modules directory [282.38ms]
(pass) coveragePathIgnorePatterns - single pattern string [329.59ms]
(pass) coveragePathIgnorePatterns - partial coverage without nan [342.40ms]
(pass) coveragePathIgnorePatterns - array of patterns [330.22ms]
(pass) coveragePathIgnorePatterns - glob patterns [341.72ms]
(pass) coveragePathIgnorePatterns - lcov reporter [335.17ms]
(pass) cov
... (truncated)

release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped) in 700ms (unchanged)
ninja: Entering directory `/workspace/bun/build/release'
[1/13] cxx obj/unified/UnifiedSource-src_jsc_bindings-3.cpp.o
[2/13] cxx obj/unified/UnifiedSource-src_jsc_bindings-2.cpp.o
[3/13] cxx obj/unified/UnifiedSource-src_jsc_bindings-4.cpp.o
[4/13] cxx obj/unified/UnifiedSource-src_jsc_bindings-1.cpp.o
[5/13] cxx obj/src/jsc/bindings/ZigGlobalObject.cpp.o
[6/13] cxx obj/unified/UnifiedSource-src_jsc_bindings-0.cpp.o
[7/13] gen cpp.rs (cppbind)
[8/13] gen generated_host_exports.rs
generated_host_exports.rs: 91 exports (host=3, lazy=10, generic=78, rust=0); 237 extern-C blocks audited
[8/13] cargo bun_bin → libbun_rust.a (--target x86_64-unknown-linux-gnu)

  nightly-2026-07-20-x86_64-unknown-linux-gnu unchanged - rustc 1.99.0-nightly (9f36de775 2026-07-19)

�[1m�[92m   Compiling�[0m bun_core v0.0.0 (/workspace/bun/src/bun_core)
�[1m�[92m   Compiling�[0m bun_errno v0.0.0 (/workspace/bun/src/errno)
�[1m�[92m   Compiling�[0m bun_ptr v0.0.0 (/workspace/bun/src/ptr)
�[1m�[92m   Compiling�[0m bun_boringssl_sys v0.0.0 (/workspace/bun/src/boringssl_sys)
�[1m�[92m   Co
... (truncated)
diff hotspot
src/jsc/bindings/ZigSourceProvider.cpp |  11 --
 src/jsc/bindings/ZigSourceProvider.h   |   1 -
 src/jsc/modules/BunJSCModule.h         |  40 ++-----
 src/sourcemap_jsc/CodeCoverage.rs      | 183 ++++++++++++++++++++++-----------
 test/cli/test/coverage.test.ts         |  69 +++++++++++++
 5 files changed, 198 insertions(+), 106 deletions(-)

gate history · 3 passed · 0 rejected · iteration 1

evidence per changed file
file                                    reads  edits  tests
src/jsc/bindings/ZigSourceProvider.cpp      1      1      0
src/jsc/bindings/ZigSourceProvider.h        1      1      0
src/jsc/modules/BunJSCModule.h              1      2      0
src/sourcemap_jsc/CodeCoverage.rs           5     10      0
test/cli/test/coverage.test.ts              2      1      0

root cause · written by the author bot

When the same source file was imported multiple times, such as through cache-busting query imports, each new instance registered a fresh JSC source ID that overwrote the existing byte range mapping for that URL, so hit counters from earlier instances were discarded and the lcov report reflected only the last instance. The fix makes the mapping retain all prior source IDs for a URL, then collects coverage and function blocks across every instance and merges duplicate ranges before generating the report. As a result, line and function hits are aggregated across all instances of a file, so cod…

Each evaluation of the same source URL (e.g. cache-busting
import("./mod?v=" + n)) creates a new JSC source provider with a new
sourceID, but the coverage byte-range map is keyed by sourceURL and
overwrote the entry on every re-import. Report generation then queried
the control flow profiler for only the last instance's sourceID, so
line and function hits from earlier instances were silently dropped
(lcov showed FNH:1 and DA:n,0 for functions exercised by passing tests).

Keep every sourceID recorded for a URL and, at report time, query the
profiler for each instance and union the basic-block data: a range
counts as executed if it executed in any instance, and execution counts
are summed.

Fixes #35345
@robobun

robobun commented Jul 24, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 9:41 PM PT - Jul 23rd, 2026

❌ @robobun, your commit 94d6a3a has 2 failures in Build #79153 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 35346

That installs a local version of the PR into your bun-35346 executable, so you can run:

bun-35346 --bun

@coderabbitai

coderabbitai Bot commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

Cross-instance coverage aggregation

Layer / File(s) Summary
Source instance tracking
src/sourcemap_jsc/CodeCoverage.rs
ByteRangeMapping stores prior JSC source IDs, and repeated mappings for the same URL preserve earlier instances.
Block collection and reporting
src/sourcemap_jsc/CodeCoverage.rs
Coverage blocks and function blocks are collected across source IDs, duplicate ranges are merged, and one report is generated from the aggregate.
Coverage regression validation
test/cli/test/coverage.test.ts
A regression test verifies lcov coverage counters and line hits across re-imported module instances.

Suggested reviewers: jarred-sumner

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The code and test address issue #35345 by unioning coverage across all instances of the same source file.
Out of Scope Changes check ✅ Passed The changes stay focused on coverage aggregation and a regression test, with no clear unrelated additions.
Title check ✅ Passed The title clearly matches the main change: coverage is unioned across re-imported module instances.
Description check ✅ Passed The PR description covers the problem, root cause, fix, and verification, though it doesn't use the template headings verbatim.

Comment @coderabbitai help to get the list of available commands.

Comment thread src/sourcemap_jsc/CodeCoverage.rs
robobun and others added 3 commits July 24, 2026 01:57
…e collector

The bun:jsc entry point still queried the control flow profiler for only
the latest sourceID, so it kept the last-instance-wins behavior fixed
for the test reporters. Move the profiler collection loop into a shared
ByteRangeMapping::collect_blocks and have both Report::generate and
ByteRangeMapping__findExecutedLines use it; the C++ side now just passes
the source URL. Removes the now-unused sourceIDForSourceURL and
ByteRangeMapping__getSourceID.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — the follow-up commit routes both Report::generate and bun:jsc codeCoverageForFile through the shared collect_blocks helper, removes the now-dead sourceIDForSourceURL/ByteRangeMapping__getSourceID, and adds a codeCoverageForFile assertion to the fixture, so my earlier concern is fully addressed.

What was reviewed:

  • Single-instance path: merge_duplicate_ranges is gated on !prior_source_ids.is_empty(), so block order/content is unchanged and the existing lcov snapshot tests stay byte-identical.
  • Multi-instance merge: sort+dedup by (start_offset, end_offset) with has_executed |= and saturating count sum; generate_report_from_blocks is order-agnostic (bitset/count-based), and BasicBlockRange is Copy so the in-place compaction is sound.
  • BlockCollector::collect applies the per-instance function_blocks[1..] drop before extending, matching the previous per-sourceID behavior; the empty-blocks → empty-array return in ByteRangeMapping__findExecutedLines preserves the old C++ contract.
  • No remaining callers of the removed C++/Rust symbols; CodeCoverage__withBlocksAndFunctions C ABI unchanged (callback ctx is void*).
Extended reasoning...

Overview

The PR fixes #35345: when a module is re-imported with a cache-busting query string, each evaluation gets a fresh JSC SourceID, but the coverage ByteRangeMapping map (keyed by source URL) previously overwrote the entry, so only the last instance's profiler data was read. The fix adds prior_source_ids: Vec<i32> to ByteRangeMapping, carries earlier IDs forward in ByteRangeMapping__generate, and introduces a shared collect_blocks helper that queries CodeCoverage__withBlocksAndFunctions for every instance and unions identical byte ranges via merge_duplicate_ranges. Both consumers — Report::generate (the bun test --coverage reporters) and ByteRangeMapping__findExecutedLines (bun:jsc codeCoverageForFile) — now route through it. The C++ functionCodeCoverageForFile shrinks to a thin call into Rust, and the dead sourceIDForSourceURL / ByteRangeMapping__getSourceID pair is deleted along with the now-unused ControlFlowProfiler.h include.

Security risks

None. This is coverage-report generation over profiler data from JSC; no untrusted input parsing, no network/auth/crypto surface. The one unsafe block added (from_raw_parts in BlockCollector::collect) is guarded by the pre-existing blocks_len == 0 early return and mirrors the code it replaces.

Level of scrutiny

Moderate. The change touches Rust↔C++ FFI signatures and a thread-local map, but the FFI ABI is unchanged (CodeCoverage__withBlocksAndFunctions still takes void* ctx and the same callback shape; the Rust-side type rename from Generator to BlockCollector is invisible to C++). The critical single-instance path is guaranteed unchanged because the merge/sort step is skipped when prior_source_ids is empty — confirmed by the existing lcov inline-snapshot tests still passing. The multi-instance path is new and was previously broken outright, so there is no regression surface there.

Other factors

  • My earlier review flagged that bun:jsc codeCoverageForFile still read only the latest source_id; commit 75900d4 addressed this exactly as suggested (shared helper, C++ passes only the URL, dead code deleted, test assertion added for the sibling path). That thread is resolved.
  • I checked merge_duplicate_ranges against generate_report_from_blocks: the downstream code sizes stmts_which_have_executed/functions_which_have_executed from the (post-merge) slice length and only ever consumes them via .count(), so reordering/compaction is safe. BasicBlockRange derives Copy, so ranges[out] = ranges[i] is a plain copy.
  • BlockCollector::collect drops the leading function block per callback invocation (i.e. per instance), matching the previous per-sourceID slicing in both the old Generator::do_ and the old C++/Rust findExecutedLines paths.
  • Grep confirms no remaining references to sourceIDForSourceURL or ByteRangeMapping__getSourceID anywhere in src/.
  • The map.insert overwrite of the old ByteRangeMapping (and its source_url) is pre-existing behavior; this PR only adds a mem::take of the old prior_source_ids before the overwrite, which is leak-neutral.
  • Evidence in the PR body shows the new test failing on both ASAN-debug and release builds without the fix and passing with it, and the full 13-test coverage.test.ts suite green.

@robobun

robobun commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator Author

CI status: the diff itself is green. The remaining failures are unrelated to this change:

  • test/js/bun/spawn/spawn.test.ts fails on main as well (pre-existing, reported separately)
  • test/js/node/test/parallel/test-https-server-connections-checking-leak.js crashed on debian 13 aarch64; this PR's code only runs under --coverage, which that test never enables (reported separately)
  • the rest (bun-install-registry, complex-workspace migration, child_process, message-port-closed-leak, solc, fs-promises-file-handle-readFile) all passed on retry

The coverage changes are covered by test/cli/test/coverage.test.ts, which passes on every lane. Ready for review.

Jarred-Sumner added a commit that referenced this pull request Aug 15, 2026
…++ (#38943)

### Problem

- Rust and C++ each spell out bun's internal C-ABI functions by hand,
and the two copies only meet in the linker, which matches names, not
signatures. 13 symbols are spelled differently on the two sides. Each
works by accident of the x64/arm64 calling conventions (an extra
argument lands in a register the callee never reads, a 32-bit
declaration reads the low half of a 64-bit return) and is undefined
behaviour on the Rust side. All of them predate the Rust port (checked
against the removed Zig sources).
- Parameter count: `Bun__JSWrappingFunction__create` (Rust passes a 5th
`strong` argument, `JSWrappingFunction.cpp:57` takes 4),
`ByteRangeMapping__getSourceID` (`ZigSourceProvider.cpp:43` passes a 2nd
`BunString`, `CodeCoverage.rs:845` takes 1), `ffi_vfprintf` /
`ffi_vprintf` / `ffi_vsscanf` (declared variadic in `ffi_body.rs`,
defined with a `va_list` parameter in `c-bindings.cpp`).
- Return width: `URL__originLength` (`url/lib.rs:74` says `u32`,
`BunString.cpp:570` returns `size_t`); `Bun__setExitCode`,
`Bun__closeChildIPC`, `Bun__ensureProcessIPCInitialized`
(`BunProcess.cpp`), `Bun__setTLSRejectUnauthorizedValue`,
`Bun__setVerboseFetchValue` (`JSEnvironmentVariableMap.cpp`) declared
with a scalar return in C++ while the Rust definitions return nothing;
`Bun__reportUnhandledError` returns a constant `undefined` that
`ZigGlobalObject.h:90` declares as `void`;
`WebCore__AbortSignal__signal` returns its argument, which the Rust
declaration (void) never reads.

### Fix

- Makes each pair agree, on whichever side carries information:
- the phantom `strong` / `sourceURL` arguments are dropped (C++ never
read `strong`; Rust never read `sourceURL`, and the `Bun::toString` that
built it is a non-owning view, so nothing was leaked or needs
releasing);
- the three `ffi_v*` declarations get a `va_list` parameter, spelled as
an opaque pointer (only their addresses are taken, for TinyCC; on every
target bun builds for a `va_list` argument travels as one pointer-sized
value);
- `URL__originLength` becomes `usize`, and the `as usize` at its only
call site goes away;
- the five C++ declarations of void Rust functions become `void` (every
C++ caller already discards the value);
- `report_unhandled_error` stops returning its constant (no Rust
callers; the C++ declaration and all eight C++ callers already treat it
as void);
- `WebCore__AbortSignal__signal` returns void in `bindings.cpp` and
`headers.h` (no C++ callers; the Rust declaration was already void).
- No behaviour changes: every call site either ignored the dropped value
or never passed anything the callee read. Verified with `bun bd` (the
regenerated `Bun__reportUnhandledError` thunk is now `-> ()`) and `bun
bd test` on `test/js/bun/test/expect-extend*.test.*` and
`jest-extended.test.js` (JSWrappingFunction),
`test/cli/test/coverage.test.ts` plus a manual `bun:jsc`
`codeCoverageForFile` run (`ByteRangeMapping__getSourceID`),
`test/js/node/process/process.test.js`,
`test/js/web/abort/abort.test.ts`,
`test/js/bun/spawn/spawn.ipc.test.ts`,
`test/js/node/child_process/child_process_ipc.test.js`,
`test/js/node/events/event-emitter.test.ts`,
`test/js/node/timers/node-timers.test.ts`,
`test/js/web/fetch/fetch.tls.test.ts`. `cargo fmt --check` and
clang-format are clean.
- There is no test: these are declaration-only corrections with nothing
observable at runtime. The source lint that found them was part of the
first revision and was removed from the PR by @Jarred-Sumner (31377e1);
its output is kept below for the record.
- Related, not duplicated: #35346 removes
`ByteRangeMapping__getSourceID` altogether as part of a larger coverage
change; this PR only corrects its declaration.

### Background

- `extern "C"` linkage: a Rust `extern "C" { fn X(..); }` item (or
`#[unsafe(no_mangle)] extern "C" fn X` definition) and a C++ `extern
"C"` declaration or definition are matched by the linker purely by the
name `X`; each compiler generates its calls and prologues from its own
local copy of the signature, so the copies can disagree without any
diagnostic.
- `HOST_EXPORT`: a `// HOST_EXPORT(Sym)` comment above a safe Rust fn
makes `src/codegen/generate-host-exports.ts` emit the
`#[unsafe(no_mangle)]` thunk for `Sym` with the impl's parameters and
return type, which is why changing `report_unhandled_error`'s Rust
signature is what changes the exported symbol's.
- `headers.h` spells `extern "C"` as `CPP_DECL`; `bindings.cpp` includes
it, so its `WebCore__AbortSignal__signal` line has to change together
with the definition.

<details>
<summary>How the 13 were found (lint output from the first revision; the
lint itself is no longer in this PR)</summary>

```
(fail) every extern "C" symbol is declared with the same parameter count at every site
  Bun__JSWrappingFunction__create
      rust src/runtime/test_runner/expect.rs:3253: 5 params, returns JSValue
      c++ src/jsc/bindings/JSWrappingFunction.cpp:57: 4 params, returns JSC::EncodedJSValue
  ByteRangeMapping__getSourceID
      rust src/sourcemap_jsc/CodeCoverage.rs:845: 1 params, returns i32
      c++ src/jsc/bindings/ZigSourceProvider.cpp:43: 2 params, returns int
  ffi_vfprintf
      rust src/runtime/ffi/ffi_body.rs:322: 2+... params, returns c_int
      c++ src/jsc/bindings/c-bindings.cpp:822: 3 params, returns int
  ffi_vprintf
      rust src/runtime/ffi/ffi_body.rs:323: 1+... params, returns c_int
      c++ src/jsc/bindings/c-bindings.cpp:815: 2 params, returns int
  ffi_vsscanf
      rust src/runtime/ffi/ffi_body.rs:329: 2+... params, returns c_int
      c++ src/jsc/bindings/c-bindings.cpp:867: 3 params, returns int

(fail) every extern "C" symbol is declared with the same return width at every site
  Bun__closeChildIPC
      rust src/runtime/hw_exports.rs:171: 1 params, returns void
      c++ src/jsc/bindings/BunProcess.cpp:175: 1 params, returns bool
  Bun__ensureProcessIPCInitialized
      rust src/runtime/ipc_host.rs:602: 1 params, returns void
      c++ src/jsc/bindings/BunProcess.cpp:179: 1 params, returns bool
  Bun__reportUnhandledError
      rust src/jsc/virtual_machine_exports.rs:75: 2 params, returns JSValue
      c++ src/jsc/bindings/ZigGlobalObject.h:90: 2 params, returns void
  Bun__setExitCode
      rust src/jsc/VirtualMachine.rs:592: 2 params, returns void
      c++ src/jsc/bindings/BunProcess.cpp:174: 2 params, returns uint8_t
  Bun__setTLSRejectUnauthorizedValue
      rust src/jsc/virtual_machine_exports.rs:196: 1 params, returns void
      c++ src/jsc/bindings/JSEnvironmentVariableMap.cpp:355: 1 params, returns int
  Bun__setVerboseFetchValue
      rust src/jsc/virtual_machine_exports.rs:241: 1 params, returns void
      c++ src/jsc/bindings/JSEnvironmentVariableMap.cpp:357: 1 params, returns int
  URL__originLength
      rust src/url/lib.rs:74: 2 params, returns u32
      c++ src/jsc/bindings/BunString.cpp:570: 2 params, returns size_t
  WebCore__AbortSignal__signal
      rust src/jsc/AbortSignal.rs:57: 3 params, returns void
      c++ src/jsc/bindings/bindings.cpp:5969: 3 params, returns WebCore::AbortSignal*
      c++ src/jsc/bindings/headers.h:127: 3 params, returns WebCore::AbortSignal*
```

The lint compared parameter counts and return widths of every
hand-written `extern "C"` site on both sides (1342 symbols declared in
both languages); these 13 were the only disagreements in the tree.

</details>

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
@robobun

robobun commented Sep 13, 2026

Copy link
Copy Markdown
Collaborator Author

Closing as part of a cleanup of stale pull requests. This PR has had no new commits since 2026-07-24, it conflicts with main, and its last CI run failed. This is not a judgment on the fix itself. The linked issue (#35345) stays open. If the problem still reproduces on a current build, reopen this PR after a rebase or open a new one against main.

@robobun robobun closed this Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Coverage: lcov reporter keeps only the LAST instance of a re-imported module — earlier instances' line hits are silently zeroed

1 participant