Skip to content

[DRAFT] [pulse] add --pulse-havoc-interrupted-loops to reach the code after long loops - #2201

Draft
VladimirMakaev wants to merge 1 commit into
meta:mainfrom
VladimirMakaev:pulse-havoc-interrupted-loops
Draft

VladimirMakaev wants to merge 1 commit into
meta:mainfrom
VladimirMakaev:pulse-havoc-interrupted-loops

Conversation

@VladimirMakaev

@VladimirMakaev VladimirMakaev commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Pulse unrolls a loop at most --pulse-widen-threshold times, so the code after a loop that needs
more iterations to exit is never analyzed (#1887). Callers treat such functions as unknown calls,
or lose their paths with --no-pulse-force-continue.

#include <stddef.h>

int a[16];

void f() {
  for (int i = 0; i < 16; i++) {
    a[i] = 0;
  }
  int* p = NULL;
  *p = 42; // Infer missed: null dereference
}

This experimental, off-by-default option exits a cut loop from copies of the dropped states in
which what the body may modify, found syntactically, is havoced. It finds the null dereferences and
a leak of #1887. On main, --pulse-over-approximate-reasoning --pulse-max-disjuncts 0 also
reaches this code, with only the over-approximate domain.

Limitations:

  • not sound: it reports false positives, e.g. on a counter's final value, on memory the explored
    iterations did not access, or after an infinite loop, besides Pulse's usual ones;
  • the copies, and what callers derive from them, are dropped first at --pulse-max-disjuncts;
  • the extra states cost time when it is on; results do not change when it is off.

Test plan

New tests in c/pulse-havoc-loops and cpp/pulse-havoc-loops, run with the option, including FP_ and
FN_ tests for the limitations. Without the option, only the three *_with_many_paths_bad tests,
where the copies must not displace the other states, are reported. The other codetoanalyze tests
pass unchanged.

…ong loops

Pulse unrolls a loop at most `--pulse-widen-threshold` times, so the code after a loop that needs
more iterations to exit is never analyzed (meta#1887). Callers treat such functions as unknown calls,
or lose their paths with `--no-pulse-force-continue`.

```c
#include <stddef.h>

int a[16];

void f() {
  for (int i = 0; i < 16; i++) {
    a[i] = 0;
  }
  int* p = NULL;
  *p = 42; // Infer missed: null dereference
}
```

This experimental, off-by-default option exits a cut loop from copies of the dropped states in
which what the body may modify, found syntactically, is havoced. It finds the null dereferences and
a leak of meta#1887. On main, `--pulse-over-approximate-reasoning --pulse-max-disjuncts 0` also
reaches this code, with only the over-approximate domain.

Limitations:
- not sound: it reports false positives, e.g. on a counter's final value, on memory the explored
  iterations did not access, or after an infinite loop, besides Pulse's usual ones;
- the copies, and what callers derive from them, are dropped first at `--pulse-max-disjuncts`;
- the extra states cost time when it is on; results do not change when it is off.

## Test plan

New tests in c/pulse-havoc-loops and cpp/pulse-havoc-loops, run with the option, including FP_ and
FN_ tests for the limitations. Without the option, only the three `*_with_many_paths_bad` tests,
where the copies must not displace the other states, are reported. The other codetoanalyze tests
pass unchanged.
@meta-cla meta-cla Bot added the CLA Signed label Oct 2, 2026
@VladimirMakaev
VladimirMakaev force-pushed the pulse-havoc-interrupted-loops branch 4 times, most recently from 4ff8a24 to d380798 Compare October 7, 2026 15:56

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.

1 participant