Skip to content

[pulse] treat calls to C functions with mismatched arity as unknown - #2142

Open
VladimirMakaev wants to merge 1 commit into
meta:mainfrom
VladimirMakaev:pulse-c-arity-mismatch
Open

VladimirMakaev wants to merge 1 commit into
meta:mainfrom
VladimirMakaev:pulse-c-arity-mismatch

Conversation

@VladimirMakaev

@VladimirMakaev VladimirMakaev commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

C functions are identified by name only, so a call can resolve to a definition with another number
of parameters (another program analyzed together, an unprototyped declaration, a function pointer
cast). Every pre/post of that definition then failed with a FormalActualLength contradiction,
silently dropping all paths through the call.

// conn.c
#include <stddef.h>
#include <sys/socket.h>
int npe_after_shutdown(int fd) {
  int* p = NULL;
  shutdown(fd, SHUT_RDWR);
  return *p; // Infer missed: null dereference
}
// plugin.c, part of another program
void shutdown(void) {}

Treat such calls as unknown: skip the summary and havoc the arguments; a noreturn attribute of the
definition still ends the path. A new stats counter, pulse_unknown_calls_arity_mismatch, counts
these calls.

Limitations: the summary is skipped even when the definition is the real callee (e.g. casts), and a
call-site noreturn declaration (like err()) is lost when the definition returns.

Test plan

New c/pulse tests arity_mismatch.c and arity_mismatch2.c: more or fewer actuals across files,
a cast function pointer, a function pointer variable and a K&R definition; variadic, matching-arity
and noreturn controls; FP_ tests for the limitations. On main the _bad tests after mismatched
calls report nothing. All codetoanalyze tests pass.

@meta-cla meta-cla Bot added the CLA Signed label Oct 2, 2026
@VladimirMakaev
VladimirMakaev force-pushed the pulse-c-arity-mismatch branch from c0a2f35 to ed036fb Compare October 2, 2026 07:57
@dulmarod

dulmarod commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

@jvillard could you have a look?

@VladimirMakaev VladimirMakaev changed the title [pulse] treat calls to C functions with mismatched arity as unknown [DRAFT] [pulse] treat calls to C functions with mismatched arity as unknown Oct 2, 2026
@VladimirMakaev
VladimirMakaev force-pushed the pulse-c-arity-mismatch branch 2 times, most recently from 802e1d1 to 1837216 Compare October 5, 2026 06:52
@VladimirMakaev VladimirMakaev changed the title [DRAFT] [pulse] treat calls to C functions with mismatched arity as unknown [pulse] treat calls to C functions with mismatched arity as unknown Oct 5, 2026
@VladimirMakaev
VladimirMakaev marked this pull request as ready for review October 5, 2026 15:27
VladimirMakaev added a commit to VladimirMakaev/infer that referenced this pull request Oct 5, 2026
C functions are identified by name only, so a call can resolve to a definition with another number
of parameters (another program analyzed together, an unprototyped declaration, a function pointer
cast). Every pre/post of that definition then failed with a `FormalActualLength` contradiction,
silently dropping all paths through the call.

Upstream-PR: meta#2142
PR-Head: 1837216
PR-Base: 9cc2641
@VladimirMakaev
VladimirMakaev force-pushed the pulse-c-arity-mismatch branch from 1837216 to 39707f5 Compare October 7, 2026 15:54
@jvillard

jvillard commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Could you check if #2078 happens to solve this too?

@VladimirMakaev

Copy link
Copy Markdown
Contributor Author

I checked: #2078 doesn't cover this. Its changes are all behind is_clang_variadic, while #2142 is about non-variadic calls whose arity doesn't match the resolved definition (cross-TU name collisions, function-pointer casts, K&R definitions), where every pre/post currently fails with a FormalActualLength contradiction and the paths are silently dropped. Only the variadic test case overlaps. The two touch the same code in PulseCallOperations.ml, so I'll rebase #2142 once #2078 lands.

@dulmarod

dulmarod commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

There are conflicts now

@VladimirMakaev

Copy link
Copy Markdown
Contributor Author

Rebased on top of #2078.

C functions are identified by name only, so a call can resolve to a definition with another number
of parameters (another program analyzed together, an unprototyped declaration, a function pointer
cast). Every pre/post of that definition then failed with a `FormalActualLength` contradiction,
silently dropping all paths through the call.

```c
// conn.c
#include <stddef.h>
#include <sys/socket.h>
int npe_after_shutdown(int fd) {
  int* p = NULL;
  shutdown(fd, SHUT_RDWR);
  return *p; // Infer missed: null dereference
}
// plugin.c, part of another program
void shutdown(void) {}
```

Treat such calls as unknown: skip the summary and havoc the arguments; a `noreturn` attribute of the
definition still ends the path. A new stats counter, `pulse_unknown_calls_arity_mismatch`, counts
these calls.

Limitations: the summary is skipped even when the definition is the real callee (e.g. casts), and a
call-site `noreturn` declaration (like `err()`) is lost when the definition returns.

## Test plan

New `c/pulse` tests `arity_mismatch.c` and `arity_mismatch2.c`: more or fewer actuals across files,
a cast function pointer, a function pointer variable and a K&R definition; variadic, matching-arity
and `noreturn` controls; `FP_` tests for the limitations. On main the `_bad` tests after mismatched
calls report nothing. All codetoanalyze tests pass.

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants