printf: fix mingw-w64 format checks, turn C99 format strings into macro#14643
printf: fix mingw-w64 format checks, turn C99 format strings into macro#14643vszakats wants to merge 32 commits intocurl:masterfrom
Conversation
|
OK, so at first try this revealed (via new /cc @bagder |
|
Clearly the format warning on those mingw compiler versions is not functional for how we do things. |
|
Another approach to try is this: --- a/include/curl/mprintf.h
+++ b/include/curl/mprintf.h
@@ -36,9 +36,9 @@ extern "C" {
defined(__IAR_SYSTEMS_ICC__)) && \
defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
!defined(CURL_NO_FMT_CHECKS)
-#if defined(__MINGW32__) && !defined(__clang__)
+#if defined(__MINGW32__)
#define CURL_TEMP_PRINTF(fmt, arg) \
- __attribute__((format(gnu_printf, fmt, arg)))
+ __attribute__((format(__MINGW_PRINTF_FORMAT, fmt, arg)))
#else
#define CURL_TEMP_PRINTF(fmt, arg) \
__attribute__((format(printf, fmt, arg)))I'll try it once fixed the stray standard printfs in http/client. |
|
The |
Ah OK, got it. It throws out the original idea here, but the format-spec patch might be a way to go that's compatible with it. Basically we need to make sure the formats and format-checker are in sync with each other and with standard printf, while curl printf accepts any format flavour anyway. Also perhaps introducing curl printf into example was a mistake in the previous PR, and should be reverted. (...along with the fprintf() converstions I'm doing now in this PR.) |
|
The initial idea checks out at this point of the PR. Now turning onto the other solution. |
bf78f32 to
01624a2
Compare
curl/system.h solution for mingw-w64 <= 7.0.0|
With the clean approach we bump into another problem: curl internally uses the (This might have been a reason why I didn't go with that after testing it in #12489) One clean (IMO), but laborous fix is to swap The upside is that this only touches internals, not the public headers. |
2b5b229 to
ca506e6
Compare
|
@bagder: After a series of tests, the only way I see to replace This brings the format-check, the format specifiers, and the (To selectively disable format checks for old mingw-w64 Do you think I should go ahead with this? |
ca506e6 to
2a112c6
Compare
|
As discussed, I replaced all |
|
Script to verify that format-string replacements were done correctly: curl -LO https://github.com/curl/curl/pull/14643.diff
grep '^-' 14643.diff > 14643-out.diff
grep '^+' 14643.diff > 14643-in.diff
grep -E -o '%[0-9]*z(x|u|d)' 14643-out.diff > 14643-out-fmt.diff
grep -E -o '%[0-9]*" CURL_FORMAT_(X|S)?SIZE_T' 14643-in.diff > 14643-in-fmt.diff
paste 14643-in-fmt.diff 14643-out-fmt.diff | sort | uniq -c > 14643-match.txtThe 493 changes checked out OK: |
|
Script to verify if the strings remained the same after this patch: curl -LO https://github.com/curl/curl/pull/14643.diff
grep -E '^(\+|@)' 14643.diff | grep -E -o '("[^"]+"|^\+\+\+.+|^@@)' | tr $'\n' $'\t' | sed -E -e 's/\"\t\"//g' -e 's/\+\+\+ b/--- a/g' | tr $'\t' $'\n' > in
grep -E '^(-|@)' 14643.diff | grep -E -o '("[^"]+"|^---.+|^@@)' | tr $'\n' $'\t' | sed -E -e 's/\"\t\"//g' -e 's/(%[0-9]*)z(x|u|d)/\1/g' | tr $'\t' $'\n' > out
diff -u out in > 14643-strings.diffThey did, except one places where I added missing space (plus code changes outside of strings): --- out
+++ in
@@ -1,9 +1,7 @@
--- a/configure.ac
@@
-"$curl_cv_native_windows$have_mingw"
--- a/docs/examples/CMakeLists.txt
@@
-"__USE_MINGW_ANSI_STDIO=1"
--- a/docs/examples/Makefile.am
@@
--- a/docs/examples/ftpgetinfo.c
@@ -85,10 +83,10 @@
"Included max number of cookies (%) in request!"
--- a/lib/curl_setup.h
@@
-"lldllucurl/mprintf.h"
@@
+"curl/mprintf.h"
@@
-"zd"
+"xudzxzuzd"
--- a/lib/cw-out.c
@@
"cw_out, wrote % %s bytes -> %"
@@ -485,7 +483,7 @@
@@
"WS: decode ending with % frame bytes remaining"
@@
-"WS: starting new frame with % bytes from last oneremaining to be sent"
+"WS: starting new frame with % bytes from last one remaining to be sent"
@@
"WS, using chunk size %"
@@
@@ -531,7 +529,6 @@
"Bad variable name length (%), skipping"
--- a/tests/http/clients/CMakeLists.txt
@@
-"__USE_MINGW_ANSI_STDIO=1"
--- a/tests/http/clients/Makefile.am
@@
--- a/tests/libtest/lib1156.c |
This reverts commit 4fe062fbb7d6a734e73f92c2fb82682d0efbca8f. Nope, this messes up tests completely, which don't expect a space here.
ba3265c to
56d9b0f
Compare
Might I ask where this is discussed? Because I fail to see the pros of this change vs the cons. This seem like a step backward for code legibility. A workaround for an older runtime over the whole code base, while there already is a less impactful workaround in place. |
|
Format masks/checks are a long time issue (and not a fun one at that). Despite spending quite a bit of time finding a workaround for making it work everywhere on all platforms (in particular all mingw-w64 versions), I have found none that doesn't have other downsides (like including This and referenced PRs (and #14703 made after this PR) have/had plenty of tries in sub commits with just as much dead-ends. edit: The current solution is build hacks for examples and tests/http/clients. That however doesn't solve this problem for anyone trying to use the public headers in the problematic envs. The root issue is using C99 format strings in a C89 project. Certainly the clean solution here is "annoying" (just like the existing solution for 64-bit formats). If you know a better one that makes pass all cases and still offers format checks, I guess everyone would be happy to use it as a better alternative. |
I would perhaps go a little further and say: The root issue is using C99 format strings in a C89 project - and asking the compiler to verify the printf formatting. |
|
We could also just switch off the printf checking and save ourselves from a lot of trouble... |
Is this the problem though? If the C99 format is parsed by C89 code this seems perfectly fine to me...
This indeed seems more like the problem, to verify with compilers that are incompatible with the format strings used.
I would agree this would be a far better choice (for incompatible compilers) than to decrease the code legibility all over the place. |
|
@vszakats we could probably switch if off for all mingw compilers without that being too complicated |
|
Switching it off for all mingw is not complicated, but in that case we'll lose checks for that platform completely. It basically means that formats will no longer be checked on Windows at all, and also that Windows-specific strings (or Windows-specific uses of strings) will no longer be checked at all. Returning to pre-PR #12489 where these fallouts were fixed after adding format checks for the first time for these. I don't think that's a useful way to go. |
C99 format is or isn't parsed perfectly depending on Windows compiler vendor, compiler version, CRT, format check configuration. Windows is a weird place. |
Right, but that's not a terribly big deal IMHO. We have not checked the format for long (meaning that we can survive pretty well without them) and most flags can still be checked fine on other platforms.
I'm beginning to think it is. Right now that seems like a lower price than this format change. |
The C99 format is parsed in curl by the code in mprintf.c, right? Then it does not depend at all on those things.
Does mingw-w64 >= v8.0.0 have a compatible format checker? Maybe it can be kept on with those versions without having to do a format change. |
Correct, the actual parsing doesn't depend on it. However the compiler's checker can only check for the standard it can understand. It doesn't know it's curl's printf, which understands everything.
This is what I tried first in this PR. It works. But to check for the mingw-w64 version, curl's public header must include mingw-w64's internal header (Notice that mingw-w64 GCC might not be the sole target affected by issues around this. mingw-w64 just happens to be the first "problematic" target where we (I) enabled format checks. We haven't tried with the more popular MSVC.) |
|
I gave #14703 another go and managed to make it work (though CI haven't fully finished yet). The idea is to override the format check in public This makes it possible to sync public format checks with public format strings in Internal format checks continue to use GNU-style, which supports The downside is that this is still a compiler-specific hack (albeit the best looking one so far). It relies on the mingw-w64 feature that allows controlling format check style, adapting to C99 code internally, while sticking to whatever the compiler default is externally. As for this PR, I agree these format macros are long and not pleasing to type or read (true for existing 64-bit ones too). |
|
Closing this one in favour of #14703. |
Change mingw-w64 printf format checks in public curl headers to use `__MINGW_PRINTF_FORMAT` instead of `gnu_printf`. This syncs the format checker with format string macros published via `curl/system.h`. (Also disable format checks for mingw-w64 older than 3.0.0 (2013-09-20) and classic-mingw, which do not support this macro.) This fixes bogus format checker `-Wformat` warnings in 3rd party code using curl format strings with the curl printf functions, when using mingw-w64 7.0.0 (2019-11-10) and older (with GCC, MSVCRT). It also allows to delete two workaounds for this within curl itself: - setting `-D__USE_MINGW_ANSI_STDIO=1` for mingw-w64 via cmake and configure for `docs/examples` and `tests/http/clients`. Ref: c730c85 #14640 The format check macro is incompatible (depending on mingw-w64 version and configuration) with the C99 `%z` (`size_t`) format string used internally by curl. To work around this problem, override the format check style in curl public headers to use `gnu_printf`. This is compatible with `%z` in all mingw-w64 versions and allows keeping the C99 format strings internally. Also: - lib/ws.c: add missing space to an error message. - docs/examples/ftpgetinfo.c: fix to use standard printf. Ref: #14643 (take 1) Follow-up to 3829759 #12489 Closes #14703
Change mingw-w64 printf format checks to use
__MINGW_PRINTF_FORMATinstead of
gnu_printf, to sync the format checker with the formatstring macros published via
curl/system.h. (Also disable format checksfor mingw-w64 older than 3.0.0 (2013-09-20) and classic-mingw, which
do not support this macro.)
This fixes bogus format checker
-Wformatwarnings in 3rd party codeusing curl format strings with the curl printf functions, when using
mingw-w64 7.0.0 (2019-11-10) and older (with GCC, MSVCRT).
It also allows to delete two workaounds for this within curl itself:
-D__USE_MINGW_ANSI_STDIO=1for mingw-w64 via cmake andconfigure for
docs/examplesandtests/http/clients.Ref: c730c85 build: make
CURL_FORMAT_CURL_OFF_T[U]work with mingw-w64 <=7.0.0 #14640curl/system.hCURL_FORMAT_CURL_OFF_T[U]format stringsto GNU-style for the curl source code.
Ref: 3829759 build: enable missing OpenSSF-recommended warnings, with fixes #12489
But,
__MINGW_PRINTF_FORMATcreates a new problem, where the C99%z(
size_t) format string is no longer accepted by the format checkerwhen using mingw-w64 7.0.0 (2019-11-10) and earlier, which default to
ms_printfformat string style.Fix this by adding new, internal,
size_tformat string macros, andreplace
%zuses across the codebase with them.The macro adapts to mingw-w64 and other build environments
automatically.
After this patch the
curl/system.hformat string macros, the formatchecker style set in
curl/mprintf.h(andlib/curl_setup.h), and theformat strings used across the source code always match.
Also:
lib/ws.c: add missing space to a string.ftpgetinfo.Verification script: