-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
[RFC] Add compile-time checking of mp_printf format strings #17556
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: Jeff Epler <[email protected]>
Signed-off-by: Jeff Epler <[email protected]>
This side-steps the problem where the output does not match when the host python version is 3.12.x (as it is on unix ci today). Signed-off-by: Jeff Epler <[email protected]>
If the fields added for MICROPY_PY_SYS_SETTRACE are not initialized properly, their value in a thread is indeterminate. In particular, if the callback is not NULL, it will be invoked as a function. Signed-off-by: Jeff Epler <[email protected]>
When MICROPY_PY_SYS_SETTRACE was enabled, a crash was seen in the qemu_mips build. It seems likely that this was due to these added fields not being initialized. Signed-off-by: Jeff Epler <[email protected]>
The argument corresponding to a `%q` specifier must be of type `qstr`, not a narrower type like `int16_t`. Not ensuring this caused an assertion error on one Windows x64 build. The argument corresponding to a `%d` specifier must be of type `int`, not a potentially-wider type like `mp_uint_t`. Not ensuring this prevented the function name from being printed on the unix nanbox build. Signed-off-by: Jeff Epler <[email protected]>
Example diagnostic:
|
df0062d
to
c39e2bd
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #17556 +/- ##
==========================================
- Coverage 98.56% 98.23% -0.34%
==========================================
Files 169 171 +2
Lines 21950 22160 +210
==========================================
+ Hits 21636 21769 +133
- Misses 314 391 +77 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Code size report:
|
59942b2
to
41fcad4
Compare
This test is flaky on GitHub CI in the sanitize_undefined build. This build adds extra runtime overhead, but there's not a simple way to test for its presence at runtime from micropython. So, just bump the top spec thread count down globally. Signed-off-by: Jeff Epler <[email protected]>
The name field of type objects is of type uint16_t for efficiency, but when the type is passed to mp_printf it must be cast explicitly to type qstr. These locations were found using an experimental gcc plugin for mp_printf error checking, cross-building for x64 windows on Linux. Signed-off-by: Jeff Epler <[email protected]>
The type of the argument must match the format string. Add casts and/or modify format strings in order to ensure that they do. These locations were found using an experimental gcc plugin for mp_printf error checking, cross-building for x64 windows on Linux. In one case there was already a cast, but it was written incorrectly and did not have the intended effect. Signed-off-by: Jeff Epler <[email protected]>
Signed-off-by: Jeff Epler <[email protected]>
Signed-off-by: Jeff Epler <[email protected]>
Signed-off-by: Jeff Epler <[email protected]>
Signed-off-by: Jeff Epler <[email protected]>
we still want this not to crash a runtime but the new static checker wouldn't like it. Signed-off-by: Jeff Epler <[email protected]>
Signed-off-by: Jeff Epler <[email protected]>
Signed-off-by: Jeff Epler <[email protected]>
0153502
to
536f6fb
Compare
the plugin can also run during the gcc windows builds. I tested it locally using the cross-building steps but I assume it'd work on windows too. I won't complicate this PR by adding it, but I'd plan to add it in a subsequent PR. Some of the format string "findings" came out of me doing that locally. |
@dpgeorge Please let me know if you think this is worth pursuing. |
I did some checks in a sibling branch, and on macos, |
Plugin support on Windows/MinGW has a number of limitations and additional requirements so adding support for that would better be postponed to a subsequent PR. |
Signed-off-by: Jeff Epler <[email protected]>
On the nanbox build, `o->obj` is a 64-bit type but `%p` formats a 32-bit type. This is incorrect, as detected by the format string checker plugin. Signed-off-by: Jeff Epler <[email protected]>
Summary
It's always nice when errors can be detected at compile time. In traditional C programs, gcc can check that the printf argument types match the printf format string. This has not been possible up to now with mp_printf, because it has both extensions to standard printf (e.g., the
%q
format type) and is missing things in standard printf (e.g.,%zd
is not supported).To that end, I have developed a GCC plugin that does this checking at compile time. I've also made the necessary changes for the unix coverage build to complete with the plugin enabled, and enabled it during the coverage build process.
Creating in draft mode to get feedback and also because this is cumulative with some other outstanding PRs that are needed to get the CI board to green.
Testing
I built the unix port coverage variant & ran the tests locally. The plugin itself should cause no code changes. There is a small code growth reported, so one of the added casts must not actually be a no-op. I have not determined which one.
Trade-offs and Alternatives
As a gcc plugin this can only support gcc-based toolchains. clang and proprietary compilers would not work. This does not seem important, as this feature only produces diagnostics.
The plugin is GPL licensed. I started with a GPL-licensed plugin template, and plugins need to be GPL-or-compatible in license in order to be loaded in gcc anyway. The plugin code IMO does not affect the license situation of the output object code, as you'd get the exact same code with or without the plugin.
Missing support for:
%ll
is runtime-supportedPRId32
for printing mp_{u,}int_t values: some ports need%d
and others%ld
, and maybe some even need%lld
(I think maybe 32-bit nanbox builds would require this, for example). e.g.,#define PRIdPY "lld"
next totypedef long long mp_int_t
. This would replace(int)
casts which was the easiest way to get local builds to finish.CI may need a new package installed -- debian needed
gcc-12-plugin-dev
and there's nogcc-plugin-dev
(w/o version number) package to install the 'usual' one). I tried to code this, we'll see if it works.Whether to enable it on more ports. This could catch problems in port-specific files, or for different fundamental object sizes.
Adding support for cmake-based builds and any other oddball build configurations