Skip to content

[DRAFT] [inferbo] fix the units of offsets and sizes of pointer parameters - #2193

Draft
VladimirMakaev wants to merge 1 commit into
facebook:mainfrom
VladimirMakaev:inferbo-pointer-strides
Draft

VladimirMakaev wants to merge 1 commit into
facebook:mainfrom
VladimirMakaev:inferbo-pointer-strides

Conversation

@VladimirMakaev

@VladimirMakaev VladimirMakaev commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Inferbo gave integer pointer parameters a stride in bits and counted the offset and size behind
void* parameters in caller elements, missing overruns in helpers taking a pointer and a length.

#include <stdint.h>
#include <string.h>

void zero(uint8_t* p, size_t n) { memset(p, 0, n); }
void set_byte(void* p, int i) { ((char*)p)[i] = 0; }

void f(void) {
  uint8_t b[16];
  zero(b, 17); // Infer missed: buffer overrun
  int w[16];
  set_byte(w, 64); // Infer missed: buffer overrun
}

Offsets and sizes behind pointer parameters now count bytes or n-byte units. strncpy reads its
source only up to a known string length, which raw writes and unknown calls forget, also through
reachable pointers. Substituting c * x for an unsigned x and a negative c keeps the term.
The frontend gives char8_t, char16_t, char32_t, wchar_t and __int128 their real integer
types, also fixing their ranges in Pulse.

Limitations:

  • A pointer to the first element of a 2D array only knows the first row.
  • Byte units expose existing imprecision: 36 new false positives on lua (7 other reports gone,
    zlib loses one), 8 on leveldb, pugixml, tinyxml2 and workflow.
  • Analyzing pugixml takes 15% more instructions.

Test plan

New tests in c/bufferoverrun/stride.c, c/bufferoverrun/void_ptr.c,
cpp/bufferoverrun/stride.cpp and cpp/frontend-20/char8.cpp, new strncpy tests in
c/bufferoverrun/models.c, and call_casting_void_ptr_Bad in cpp/bufferoverrun/void_ptr.cpp.
The codetoanalyze tests pass. Counts above: --bufferoverrun-only on lua 5.4.6 (without lgc.c
and luac.c) and zlib 1.3.1, --bufferoverrun on 13 C++ projects.

Inferbo gave integer pointer parameters a stride in bits and counted the offset and size behind
`void*` parameters in caller elements, missing overruns in helpers taking a pointer and a length.

```c
#include <stdint.h>
#include <string.h>

void zero(uint8_t* p, size_t n) { memset(p, 0, n); }
void set_byte(void* p, int i) { ((char*)p)[i] = 0; }

void f(void) {
  uint8_t b[16];
  zero(b, 17); // Infer missed: buffer overrun
  int w[16];
  set_byte(w, 64); // Infer missed: buffer overrun
}
```

Offsets and sizes behind pointer parameters now count bytes or n-byte units. strncpy reads its
source only up to a known string length, which raw writes and unknown calls forget, also through
reachable pointers. Substituting `c * x` for an unsigned `x` and a negative `c` keeps the term.
The frontend gives `char8_t`, `char16_t`, `char32_t`, `wchar_t` and `__int128` their real integer
types, also fixing their ranges in Pulse.

Limitations:
- A pointer to the first element of a 2D array only knows the first row.
- Byte units expose existing imprecision: 36 new false positives on lua (7 other reports gone,
  zlib loses one), 8 on leveldb, pugixml, tinyxml2 and workflow.
- Analyzing pugixml takes 15% more instructions.

## Test plan
New tests in `c/bufferoverrun/stride.c`, `c/bufferoverrun/void_ptr.c`,
`cpp/bufferoverrun/stride.cpp` and `cpp/frontend-20/char8.cpp`, new strncpy tests in
`c/bufferoverrun/models.c`, and `call_casting_void_ptr_Bad` in `cpp/bufferoverrun/void_ptr.cpp`.
The codetoanalyze tests pass. Counts above: `--bufferoverrun-only` on lua 5.4.6 (without `lgc.c`
and `luac.c`) and zlib 1.3.1, `--bufferoverrun` on 13 C++ projects.
@meta-cla meta-cla Bot added the CLA Signed label Oct 2, 2026
@VladimirMakaev
VladimirMakaev force-pushed the inferbo-pointer-strides branch from 3c342a9 to e979c5b Compare October 3, 2026 22:57
VladimirMakaev added a commit to VladimirMakaev/infer that referenced this pull request Oct 4, 2026
Inferbo did not model `std::array::data()` or know the size of `std::array` elements, so it
missed overruns through `data()` and reported false positives on `memset`/`memcpy` of a whole
`std::array`, on `new`/`malloc` of one, and on `std::array`s reached through pointers or
references into C arrays or vectors of them.

```cpp
#include <array>
#include <cstring>

void f(const char* src) {
  std::array<int, 4> a;
  a.data()[4] = 0; // Infer missed: buffer overrun
  memcpy(a.data(), src, 20); // Infer missed: buffer overrun
  auto* p = new std::array<int, 4>;
  (*p)[3] = 0; // false positive: buffer overrun reported here
  delete p;
}
```

The `std::array` type model now records the element size. Pointers to `std::array` count
`std::array`s, using the byte-unit symbols of facebook#2193, and the models of its methods, now including
`data()`, recount their receiver in elements and keep its offset.

Limitations: `std::array` fields of local structs are not modelled.

## Test plan
New tests in `cpp/bufferoverrun/std_array.cpp`, with `FN_` and `FP_` tests for the overruns from
one `std::array` of a C array into the next, C arrays in a `std::array` and vectors of
`std::array`s. The codetoanalyze tests pass; the example behaves the same with libstdc++.
@VladimirMakaev
VladimirMakaev force-pushed the inferbo-pointer-strides branch from e979c5b to 0eb8408 Compare October 5, 2026 02:40
VladimirMakaev added a commit to VladimirMakaev/infer that referenced this pull request Oct 5, 2026
Inferbo did not model `std::array::data()` or know the size of `std::array` elements, so it
missed overruns through `data()` and reported false positives on `memset`/`memcpy` of a whole
`std::array`, on `new`/`malloc` of one, and on `std::array`s reached through pointers or
references into C arrays or vectors of them.

```cpp
#include <array>
#include <cstring>

void f(const char* src) {
  std::array<int, 4> a;
  a.data()[4] = 0; // Infer missed: buffer overrun
  memcpy(a.data(), src, 20); // Infer missed: buffer overrun
  auto* p = new std::array<int, 4>;
  (*p)[3] = 0; // false positive: buffer overrun reported here
  delete p;
}
```

The `std::array` type model now records the element size. Pointers to `std::array` count
`std::array`s, using the byte-unit symbols of facebook#2193, and the models of its methods, now including
`data()`, recount their receiver in elements and keep its offset.

Limitations: `std::array` fields of local structs are not modelled.

## Test plan
New tests in `cpp/bufferoverrun/std_array.cpp`, with `FN_` and `FP_` tests for the overruns from
one `std::array` of a C array into the next, C arrays in a `std::array` and vectors of
`std::array`s. The codetoanalyze tests pass; the example behaves the same with libstdc++.
@VladimirMakaev
VladimirMakaev force-pushed the inferbo-pointer-strides branch from 0eb8408 to 0a1737f Compare October 5, 2026 06:54
VladimirMakaev added a commit to VladimirMakaev/infer that referenced this pull request Oct 5, 2026
Inferbo did not model `std::array::data()` or know the size of `std::array` elements, so it
missed overruns through `data()` and reported false positives on `memset`/`memcpy` of a whole
`std::array`, on `new`/`malloc` of one, and on `std::array`s reached through pointers or
references into C arrays or vectors of them.

```cpp
#include <array>
#include <cstring>

void f(const char* src) {
  std::array<int, 4> a;
  a.data()[4] = 0; // Infer missed: buffer overrun
  memcpy(a.data(), src, 20); // Infer missed: buffer overrun
  auto* p = new std::array<int, 4>;
  (*p)[3] = 0; // false positive: buffer overrun reported here
  delete p;
}
```

The `std::array` type model now records the element size. Pointers to `std::array` count
`std::array`s, using the byte-unit symbols of facebook#2193, and the models of its methods, now including
`data()`, recount their receiver in elements and keep its offset.

Limitations: `std::array` fields of local structs are not modelled.

## Test plan
New tests in `cpp/bufferoverrun/std_array.cpp`, with `FN_` and `FP_` tests for the overruns from
one `std::array` of a C array into the next, C arrays in a `std::array` and vectors of
`std::array`s. The codetoanalyze tests pass; the example behaves the same with libstdc++.
@VladimirMakaev
VladimirMakaev force-pushed the inferbo-pointer-strides branch from 0a1737f to b232f2e Compare October 7, 2026 15:56
VladimirMakaev added a commit to VladimirMakaev/infer that referenced this pull request Oct 7, 2026
Inferbo did not model `std::array::data()` or know the size of `std::array` elements, so it
missed overruns through `data()` and reported false positives on `memset`/`memcpy` of a whole
`std::array`, on `new`/`malloc` of one, and on `std::array`s reached through pointers or
references into C arrays or vectors of them.

```cpp
#include <array>
#include <cstring>

void f(const char* src) {
  std::array<int, 4> a;
  a.data()[4] = 0; // Infer missed: buffer overrun
  memcpy(a.data(), src, 20); // Infer missed: buffer overrun
  auto* p = new std::array<int, 4>;
  (*p)[3] = 0; // false positive: buffer overrun reported here
  delete p;
}
```

The `std::array` type model now records the element size. Pointers to `std::array` count
`std::array`s, using the byte-unit symbols of facebook#2193, and the models of its methods, now including
`data()`, recount their receiver in elements and keep its offset.

Limitations: `std::array` fields of local structs are not modelled.

## Test plan
New tests in `cpp/bufferoverrun/std_array.cpp`, with `FN_` and `FP_` tests for the overruns from
one `std::array` of a C array into the next, C arrays in a `std::array` and vectors of
`std::array`s. The codetoanalyze tests pass; the example behaves the same with libstdc++.

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