Repository navigation
fix(cfnptr): a C function-pointer table links only to C and C++ functions - #2935
Merged
Merged
Conversation
…ions resolveFn in the C function-pointer pass looked a registered handler's name up across every language, filtered only to function and method kinds. In a repository that also holds Rust or Python, a C table could link to a same-named Rust or Python function, and when that function sorted first it also took the place of the real C handler. The fix keeps candidates in C and C++ files only, using the pass's own C_CPP_EXT, the file set it scans for tables and dispatch. Headers the language detector labels Objective-C still count. Objective-C `.m` and `.mm` files stay out, like they are out of the scan: a table in a `.m` file is never read, and allowing them would let an Objective-C method named `init` or `read` stand in for a C handler of that name. On GLFW, which mixes C and Objective-C, main links 354 table entries, none into a .m file; its one C table naming a .m function (_glfwConnectCocoa) is an anonymous-struct table the pass doesn't bridge on main either. Validation, main b6379e6 vs this: - c-fnptr-synthesizer.test.ts: the new case fails on main (impl_read links to aaa/gen.py) and passes here; 19/19. - Linux d135ab45 subtree (rust/, drivers/android, drivers/base, drivers/net/dsa, fs, tools/net, include/linux; 6,580 files): byte-identical, 12,244 fn-pointer-dispatch edges, all into C or C++ files on both arms. Main links none of this tree into Rust or Python, so the PR's 193 (a whole-kernel index on its fork) don't show here; a subtree holding its three example sites (pmcraid's `->reset_cmd = cmd`, afs's `->update_time = new`, map.c's `p->lock = lock`) has none either, since a plain assignment of a variable doesn't register on main. - C and C++ controls byte-identical (dump-graph, every table): redis 7f440372 (863 fn-pointer-dispatch edges), GLFW 92dcf4ce (354), jq 49fbca12 and leveldb 7ee830d0. - The resolver change is TS-side; the kernel ports only the per-file sweep, so both engines take the same edges. kernel-parity on the kernel's drivers/base, drivers/net/dsa and drivers/android (279 C files): 240 at parity, 0 diffs, 39 deferred to wasm by policy. Ours on top: the CHANGELOG bullet moved from the released 1.6.1 section to Unreleased and reworded. Original PR #1989 by @bompus. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 27, 2026
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.
Summary
The C function-pointer pass (
fn-pointer-dispatch) now links a table's registered handlers only to functions in C and C++ files. Before, a C table could link to a Python or Rust function that shares the handler's name, and that function could also take the place of the real C handler.Root cause
resolveFninsrc/resolution/c-fnptr-synthesizer.tslooks a registered name up withctx.getNodesByName(name), filtered only to function and method kinds. In a repository that also has Rust or Python, the candidates included those languages' functions. A registered name with no C function node behind it, likegen_probein the test, landed on the foreign function. With several candidates, the first wins unless one is in the registering file, so a Pythonimpl_readthat sorted first took the place of the Cimpl_readthe table names. Both reproduce on main with the PR's test.What came from the contributor, and what we changed
From @bompus, unchanged: the filter (
C_CPP_EXT.test(n.filePath), the pass's own scan set, so a header the language detector labels Objective-C still counts) and the test.Ours:
[1.6.1]section into[Unreleased]and was reworded..m/.mmfiles stay out, as the PR has it. The pass never reads a table or dispatch in a.mfile. Allowing those files as targets would let an Objective-C method namedinitorreadstand in for a C handler of that name, the same cross-language mistake this fixes. On GLFW, which mixes C and Objective-C, main links 354 table entries and none into a.mfile. Its one C table that names a.mfunction,_glfwConnectCocoainplatform.c, is an anonymous-struct table that main doesn't bridge either.Validation
Linux kernel subtree (
d135ab45:rust/,drivers/android,drivers/base,drivers/net/dsa,fs,tools/net,include/linux; 6,580 files, under the big-index rule): the graph is byte-identical on both arms, with 12,244fn-pointer-dispatchedges, all into C or C++ files. On current main this tree has no edge into Rust or Python, so the PR's 193, from a whole-kernel index on its fork, don't show here.->reset_cmd = cmd, afs's->update_time = newand map.c'sp->lock = lock, withrust/andtools/net/ynl. On main, a plain assignment of a variable doesn't register; only struct-value initializers, arrays and propagation between function-pointer fields do.Red→green. The new case in
c-fnptr-synthesizer.test.tsfails on main, whereimpl_readlinks toaaa/gen.py, and passes here; the suite has 19/19.Controls. C and C++ graphs are byte-identical (dump-graph, every table): redis
7f440372(863 fn-pointer edges), GLFW92dcf4ce(354), jq49fbca12, leveldb7ee830d0.Kernel parity. The change is TS-side: the kernel ports only the pass's per-file sweep, not its linking, so both engines take the same edges.
kernel-parity.mjson the kernel'sdrivers/base,drivers/net/dsaanddrivers/android(279 C files) gives 240 at byte parity, 0 with diffs and 39 deferred to wasm by policy.Full suite: 762 files passed, 6 skipped; 9,075 tests passed, 85 skipped, 0 failed, on
ece90943(the same patch, one rebase earlier; the rebase brought only perf(resolution): read a bare JS/TS call's local binding once per match — graph byte-identical #2934, which touchesname-matcher.ts).Lands #1989 by @bompus.
🤖 Generated with Claude Code