rastray 0.15.0

Blazing-fast static analysis CLI for security, dependency, and performance audits.
# RSTR-MEM-002 — scanf with unbounded %s

## Summary

A `scanf`-family call uses `%s` (or `%[…]`) without a width specifier.
The format directive reads characters into the destination buffer
until it encounters whitespace — and if the input is longer than the
buffer, the write overflows. The buffer's declared size is *not*
visible to `scanf` at runtime, so the only protection is the width
specifier in the format string itself.

This is one of the most common buffer-overflow vectors in C teaching
material and legacy code: the call looks innocuous next to a
"reasonable" buffer like `char name[64]`, and most inputs fit, so
the bug goes undetected until someone hands the program a long line.

## Severity

`High`.

## Languages

C, C++ (`.c`, `.cc`, `.cpp`, `.cxx`, `.h`, `.hpp`, `.hh`, `.hxx`).

## What rastray flags

```c
char name[64];

scanf("%s", name);                          // ← flagged
sscanf(input, "%d %s", &age, name);         // ← flagged

FILE *fp = fopen(path, "r");
fscanf(fp, "%s", line);                     // ← flagged
```

The vararg variants are also flagged: `vscanf`, `vfscanf`, `vsscanf`.

## What rastray deliberately does *not* flag

- Width-specified `%s`: `scanf("%63s", name)`.
- Other format directives: `%d`, `%f`, `%c`, `%lf`.
- `fgets(buf, sizeof(buf), stdin)` — bounded by construction.
- `getline` — self-allocating, can't overflow.

## How to fix it

The width is one less than the destination size (leaves room for the
null terminator):

```c
char name[64];
scanf("%63s", name);                        // explicit width
```

For the common "read a line" case, `fgets` is simpler and safer:

```c
char line[256];
if (fgets(line, sizeof(line), stdin) != NULL) {
    line[strcspn(line, "\n")] = '\0';       // strip trailing newline
}
```

For unbounded line input, `getline` allocates as much as it needs:

```c
char *line = NULL;
size_t cap = 0;
if (getline(&line, &cap, stdin) > 0) {
    // …
}
free(line);
```

In C++, `std::getline` over a `std::string` is the idiomatic choice.

## How to suppress

If the format width is computed dynamically and the regex can't see it
(rare):

```c
// rastray-ignore: RSTR-MEM-002 — width is pinned via WIDTH macro = sizeof(name)-1
char fmt[16];
snprintf(fmt, sizeof(fmt), "%%%zus", sizeof(name) - 1);
scanf(fmt, name);
```

## References

- [SEI CERT C INT05-C]https://wiki.sei.cmu.edu/confluence/display/c/INT05-C.+Do+not+use+input+functions+to+convert+character+data+if+they+cannot+handle+all+possible+inputs
- [SEI CERT C ARR38-C]https://wiki.sei.cmu.edu/confluence/display/c/ARR38-C.+Guarantee+that+library+functions+do+not+form+invalid+pointers
- [CWE-120]https://cwe.mitre.org/data/definitions/120.html