Skip to content

fix(cfnptr): link registrations only to C/C++ functions - #1989

Closed
bompus wants to merge 3 commits into
colbymchenry:mainfrom
bompus:contribute/cfnptr-c-only-targets
Closed

bompus wants to merge 3 commits into
colbymchenry:mainfrom
bompus:contribute/cfnptr-c-only-targets

Conversation

@bompus

@bompus bompus commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

The C function-pointer pass resolves a registered handler by name with ctx.getNodesByName(name), filtered only to function and method kinds. In a repository with other languages, a C table can therefore link to a Python or Rust function that shares the handler's name. When that function sorts first, it also takes the place of the real C handler.

On a Linux kernel index, 193 fn-pointer-dispatch edges pointed into Rust (171) or Python (22). Examples:

  • touch_atime → new in drivers/android/binder/allocation.rs
  • kobj_lookup → lock in rust/kernel/gpu/buddy.rs
  • sja1105_static_config_upload → cmd in tools/net/ynl/pyynl/lib/ynl.py

The fix limits candidates to functions in C/C++ files, using the pass's existing C_CPP_EXT. That is the file set the pass scans, so headers the language detector labels Objective-C still count. We measured this change in our fork on the same index: the 193 cross-language edges go away and 133 C targets they had displaced come back.

Checks:

  • New case in c-fnptr-synthesizer.test.ts: a C table registering impl_read (defined in impl.c and also in a Python script) and gen_probe (defined only in Python). The table links to impl.c, and nothing links to Python. On main it links impl_read to the Python file.
  • The C function-pointer suite passes (19 tests); tsc --noEmit is clean.
  • Full suite: 258 files / 4,536 passed, 192 skipped.

resolveFn looked a registered handler's name up across every language,
so a C table could link to a same-named Python or Rust function, and
such a function could take the place of the real C handler.
colbymchenry pushed a commit that referenced this pull request Oct 27, 2026
…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>
@colbymchenry

Copy link
Copy Markdown
Owner

Thanks @bompus! Your C/C++-only filter landed unchanged in #2935, with you as the commit author; we only moved the CHANGELOG line from the released 1.6.1 section into Unreleased. Pure C and C++ graphs come out byte-identical (redis, GLFW, jq, leveldb, and a 6,580-file Linux subtree), so it costs nothing where there's no other language, and your test pins the mixed-language case. We kept Objective-C .m/.mm out as you had it, since the pass never reads those files. It ships in the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants