Skip to content

C: a call resolves by exact name onto a static function in another translation unit (4,448 edges on betaflight) #1730

Closed

Description

@danusha2345

A static function in C is visible only in its own translation unit, but the exact-name strategy accepts it as the target of a call from any other file. When the caller's file has no same-named definition and another file has a static one, the call resolves onto it.

Reproduction

core.c:

void coreRun(void)
{
    usbGetDescriptor();
}

usb_audio.c:

static void usbGetDescriptor(void)
{
}

codegraph init, then the edges of coreRun:

coreRun --calls--> usb_audio.c::usbGetDescriptor   resolvedBy: exact-match

The real target is whatever core.c links against — a non-static usbGetDescriptor elsewhere, a function pointer, a macro — but never that one. When a same-file static of the same name exists the proximity score in findBestMatch picks it, so the wrong edge appears exactly when the caller's file has no definition, which is the case that matters for cross-file navigation.

Scale

On a 2,109-file betaflight tree, of 42,460 cross-file calls/imports edges resolved by exact-match or fuzzy, 4,448 target a function declared static in a file other than the caller's (10%). A typical run of them:

lib/main/AT32F43x/middlewares/usb_drivers/src/usbd_sdr.c:usbd_get_descriptor
  → lib/main/AT32F43x/middlewares/usbd_class/audio/audio_desc.c:get_device_descriptor      (static)
  → …/audio/audio_desc.c:get_device_configuration                                           (static)
  → …/audio/audio_desc.c:get_device_lang_id                                                 (static)

usbd_sdr.c calls those through a descriptor table of function pointers; audio_desc.c, cdc_desc.c, hid_desc.c, … each define their own static get_device_descriptor, and the matcher hands every call to the first file it ranks.

Relationship to #1719 / #1720

This is the C form of the same defect: a binding that the language makes file-local is admitted as a cross-file candidate. #1720's isSealedModule is deliberately JS/TS-only. In C the signal is per symbol, not per file — the definition's storage class — and the extractor already sees the static specifier on the function_definition, so it could either mark the node (a visibility/isStatic flag) or the resolver could read the definition line as #1720 reads source. Same-file candidates must stay eligible, and a static in a header included by the caller is a genuine same-unit call, which is the one exception to keep in mind.

Activity

  1. danusha2345 commented on Sep 7, 2026

    @danusha2345
    ContributorAuthor

    Correction to the count above. Of the 4,448 cross-file calls onto a static in another file, 4,306 target a static inline in a header — MAVLink's mavlink_msg_*.h / protocol.h — and those are correct edges: a header is textually included, so its static inline exists in every unit that names it and is callable from each. The defect is only a static defined in a translation unit (.c, .cc, …) reached from another file: 145 rows on this tree, the USB descriptor-table shape in the body (and STM32 class sources landing on GD32's usbd_enum.c statics). The 10% figure was counting the header calls; the real share is 0.3%.

    #1732 carries the fix with the rule scoped that way (second commit, 42a9267), and a test that keeps the header case.

  2. colbymchenry commented on Sep 8, 2026

    @colbymchenry
    Owner

    Also addressed by #1745 (rebase of #1732). Leaving this issue open for whoever owns C closeout / #1732 coordination — Forge's mandate was #1731.

  3. colbymchenry commented on Sep 8, 2026

    @colbymchenry
    Owner

    Verified on Linux against current main (includes merged #1745 / rebase of #1732): the issue repro no longer produces coreRun --calls--> usb_audio.c::usbGetDescriptor.

    • Fixture: core.c calls usbGetDescriptor(); usb_audio.c defines static void usbGetDescriptor(void) {}.
    • After CodeGraph.init + resolveReferences, coreRun has no calls edge onto that static (exact-match no longer admits a TU-local static in another .c).
    • __tests__/cross-file-visibility.test.ts — 11 passed (CODEGRAPH_KERNEL=0, Node 22.19), including same-file static kept and header static inline kept.

    Fixed by #1745 (already closed this issue on merge). No duplicate PR.

  4. added a commit that references this issue on Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions