casaroli opened a new issue, #21467: URL: https://github.com/apache/nuttx/issues/21467
## Summary `printf` in NuttX can hang, can read outside a buffer, and gives wrong output for valid formats. I want to fix this in small steps, with a test suite to measure each step, and without growth on small boards. This issue holds the plan and links the PRs. Comments on the plan are welcome before the larger steps. ## The measurement The suite is https://github.com/casaroli/printf-report: 45,084 tests, each tagged with the document that requires the behaviour (C99, C23, POSIX), and expected results that come from a model of the standard text, not from another C library. The published run of NuttX 13.1 on sim, with `LIBC_FLOATINGPOINT`, `LIBC_NUMBERED_ARGS` and `LIBC_LOCALE`: | Measure | Result | |---|---| | C99 required | 61.70% | | Correctly rounded | 57.28% | | C23 | 1.08% | | POSIX | 65.85% | | XSI | 36.36% | | Tests that crash or hang | 42 | Findings from that report, each reproduced with a standalone program. Some code has changed since, so the first step runs the suite again on current master: - It hangs on integer widths of 256 or more, and on `%.Ne` with a precision of 255 or more. - `%#.0x` of 0 reads `buf[-1]`. - `%.0g` writes a NUL byte. - `%n` is printed as text, and the arguments after it are then misread. - `%Lf` reads a `long double` as a `double`. - `-0.0` loses its sign. - There is no `%a`, and output has only 15 significant digits. ## Rules 1. `printf` never crashes or hangs, in any configuration. 2. A configuration has at least what it has today. The default stays as it is: floating point with `!DEFAULT_SMALL && ARCH_FPU`. 3. The default configuration does not grow in flash. Each PR shows flash and stack, and any growth has a reason. A wrong argument is outside rule 1: `printf` cannot detect a bad pointer for `%s` or an argument of the wrong type. The documentation will say so. ## Design The parser is not optional. A crash comes from a format that is misread, not from a missing feature. - Always on: the full format grammar, and each argument read at its right size. - A conversion that is disabled still reads its argument, then prints `?` padded to the width, so the rest of the line stays correct. - An unknown conversion has no known size, so the rest of the format is printed as text and no more arguments are read. The features are options, and a profile (Minimal, Default, Full) only sets their defaults. `LIBC_FLOATINGPOINT` and `LIBC_NUMBERED_ARGS` keep their names. | Option | Note | |---|---| | 64-bit integers on 32-bit CPUs | Can pull in libgcc division | | Floating point: none, as today, exact | Exact rounding costs stack and flash | | `%a` | Separate from exact rounding | | `long double` | Only where it differs from `double` | | Wide characters | | | Positional arguments | `LIBC_NUMBERED_ARGS` | | Locale and `'` grouping | | | `%n` | Off by default: it reads its pointer and stores nothing | | C23 `%b` and `%wN` | | The sizes are not measured yet, so this list can change. ## Steps One topic in each PR: - [ ] Safety: no crash and no hang, no new options - [ ] Options and profiles: the existing features behind options, with no change in the default - [ ] Argument sizes: `%n`, `%L`, unknown conversions - [ ] Output: `-0.0`, then `%a` and C23, each behind its option - [ ] Exact floating point behind its option, after a discussion here A new feature comes in off in the Default profile, so it does not grow the default configuration. Tests: the suite on each profile with 0 crashes and hangs, a fuzz run on the host under ASan and UBSan, and a test in nuttx-apps where CI can run it. ## Alternatives - One large PR: hard to review, and it conflicts with other work in the file. - All of it always on: it grows the small boards. - A new library for `printf`: more risk than a fix, and the small boards still need a small path. ## Related #21340 refactors the same file. The order of that PR and these steps is for its author and me to agree. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
