Warning, gcc 10.2.0 incompatible changes!

All off topic discussions go here. Everything from the funny thing your cat did to your favorite tv shows. Non-programming computer questions are ok too.
Octocontrabass
Member
Member
Posts: 5501
Joined: Mon Mar 25, 2013 7:01 pm

Re: Warning, gcc 10.2.0 incompatible changes!

Post by Octocontrabass »

I tried it. The strings appear fine in the compiled binary, but it crashes anyway. Perhaps the buffer you're writing the string into is too small?
linuxyne
Member
Member
Posts: 211
Joined: Sat Jul 02, 2016 7:02 am

Re: Warning, gcc 10.2.0 incompatible changes!

Post by linuxyne »

PRIu64 is "llu" according to c9x standard. But windows doesn't understand "llu". It understands I64u, but that's non-standard.

_mingw.h has the following:

Code: Select all

/* We are activating __USE_MINGW_ANSI_STDIO for various define indicators.
 * printf ll modifier (unsupported by msvcrt.dll) is required by C99 and C++11 standards. */
#if (defined (_POSIX) || defined (_POSIX_SOURCE) || defined (_POSIX_C_SOURCE) \
     || defined (_ISOC99_SOURCE) \
     || (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && __MSVCRT_VERSION__ < 0xE00) \
     || (defined (__cplusplus) && __cplusplus >= 201103L && __MSVCRT_VERSION__ < 0xE00) \
     || defined (_XOPEN_SOURCE) || defined (_XOPEN_SOURCE_EXTENDED) \
     || defined (_GNU_SOURCE) \
     || defined (_SVID_SOURCE)) \
    && !defined(__USE_MINGW_ANSI_STDIO)
/* Enable __USE_MINGW_ANSI_STDIO if user did _not_ specify it explicitly... */
#  define __USE_MINGW_ANSI_STDIO			1
#endif

inttypes.h has the following

Code: Select all

/* 7.8.1 Macros for format specifiers
 * 
 * MS runtime does not yet understand C9x standard "ll"
 * length specifier. It appears to treat "ll" as "l".
 * The non-standard I64 length specifier causes warning in GCC,
 * but understood by MS runtime functions.
 */
#if defined(_UCRT) || __USE_MINGW_ANSI_STDIO
#define PRId64 "lld"
#define PRIi64 "lli"
#define PRIo64 "llo"
#define PRIu64 "llu"
#define PRIx64 "llx"
#define PRIX64 "llX"
#else
#define PRId64 "I64d"
#define PRIi64 "I64i"
#define PRIo64 "I64o"
#define PRIu64 "I64u"
#define PRIx64 "I64x"
#define PRIX64 "I64X"
#endif
On a win10-2004 machine, with latest msys2 and mingw64-gcc compiler 10.2.0-3, the following code outputs "lu" instead of the number 1337.

Code: Select all

#include <stdio.h>
#include <inttypes.h>
#include <windows.h>

int wmain(int argc, wchar_t ** argv, wchar_t **env)
{
	unsigned long long a = 1337;

	wchar_t str[100];
	wsprintfW(str, L"%" PRIu64 "\n", a);
	wprintf(str); // Prints lu, not the number
	return 0;
}
The wsprintfW above results in the below call

Code: Select all

wsprintfW(str, L"%llu", a);
Force-undefing __USE_MINGW_ANSI_STDIO causes PRIu64 to resolve to I64u.

Code: Select all

#include <stdio.h>

#undef __USE_MINGW_ANSI_STDIO
#include <inttypes.h>
#include <windows.h>

int wmain(int argc, wchar_t ** argv, wchar_t **env)
{
	unsigned long long a = 1337;

	wchar_t str[100];
	wsprintfW(str, L"%" PRIu64 "\n", a);
	wprintf(str); // Prints 1337
	return 0;
}

Compilation command

Code: Select all

gcc -Wall -municode a.c
People ought to know their tools before using them.

Edit: I can't build usbimager's tree @ commit e216859db725 with msys2.
It gives error:

Code: Select all

disks_win.c:33:10: fatal error: ddk/ntdddisk.h: No such file or directory
There are warnings about casting pointer to integer of difference size, and about mismatches in format specifiers.

Also, when I exposed a 100MB usb disk to the machine, usbimager wasn't able to see it unless I also created a partition on it. Then, in its device selector drop down listed the volume size as 1.0 GB, when it is merely 97 MB!

----

Edit: The older msys(1.0) defaults PRIu64 to I64u (for C code). Its inttypes.h file:

Code: Select all

#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS)

/* 7.8.1 Macros for format specifiers
 *
 * MS runtime does not yet understand C9x standard "ll"
 * length specifier. It appears to treat "ll" as "l".
 * The non-standard I64 length specifier causes warning in GCC,
 * but understood by MS runtime functions.
 */

. . .

#define PRIu64 "I64u"

. . .
So the difference is between in the toolchains; nothing to do with gcc. But one can understand how anybody can get confused since both gcc and the toolchain were upgraded together.

---

Edit: the crash occurs because the argument that is supposed to be used with %llu is used with %s. So %llu is probably skipped by windows, and the next specifier, which happens to be %s gets paired with the integer argument meant for %llu. The argumentt is treated as an address and very likely causes crash or corruption, depending on the value.
nullplan
Member
Member
Posts: 1760
Joined: Wed Aug 30, 2017 8:24 am

Re: Warning, gcc 10.2.0 incompatible changes!

Post by nullplan »

linuxyne wrote:PRIu64 is "llu" according to c9x standard. But windows doesn't understand "llu". It understands I64u, but that's non-standard.
That is false. PRIu64 is defined as a macro that expands to that printf() format specifier that prints out a uint64_t. If your implementation expands this to "llu", but the printf() used at runtime needs "I64u", then that is a bug. What you have described here is yet another reason to distrust msys. If I'm forced to program on Windows, I use Cygwin.

Note that "llu" prints an unsigned long long, which has at least 64 bits, but could be larger, and also it doesn't have to be the only type that is 64 bits.
Carpe diem!
linuxyne
Member
Member
Posts: 211
Joined: Sat Jul 02, 2016 7:02 am

Re: Warning, gcc 10.2.0 incompatible changes!

Post by linuxyne »

nullplan wrote:That is false.
Then the documentation available with msys/msys2 is incorrect, as that itself claims that I64u is non-standard.
nullplan wrote: PRIu64 is defined as a macro that expands to that printf() format specifier that prints out a uint64_t. If your implementation expands this to "llu", but the printf() used at runtime needs "I64u", then that is a bug.
Right. The msys2 toolchain demonstrates that behaviour - it generates %llu to be used on a system that doesn't understand llu. According to their documentation, %llu is part of c9x standard. So according to your statements, they are blatantly lying.
nullplan wrote: What you have described here is yet another reason to distrust msys. If I'm forced to program on Windows, I use Cygwin.
Sure. It's the toolchain' problem, not the compiler.
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Warning, gcc 10.2.0 incompatible changes!

Post by bzt »

The interesting thing is, there seems to be no problems with printf, only with wsprintfW. However I only use "%lu" in printf, that's true.
nullplan wrote:What you have described here is yet another reason to distrust msys. If I'm forced to program on Windows, I use Cygwin.
The only reason why I prefer mingw over Cygwin is, because I couldn't compile single binaries with Cygwin. There was always the need to ship cygwin.dll along. For mingw, the POSIX-Win32 wrappers are statically linked into the binary if you use them, but you can also use the Win32 API directly. Now I have last used Cygwin many years ago, this could have changed, and Cygwin might be able to compile statically since. I had no reason to check it again, because mingw is working (most of the time :-)) like a charm.

Cheers,
bzt
nullplan
Member
Member
Posts: 1760
Joined: Wed Aug 30, 2017 8:24 am

Re: Warning, gcc 10.2.0 incompatible changes!

Post by nullplan »

linuxyne wrote:Then the documentation available with msys/msys2 is incorrect, as that itself claims that I64u is non-standard.
No, that part is correct. It is however incorrect to claim that PRIu64 is defined by the standard as "llu". "%llu" is defined by the standard to print an unsigned long long, but uint64_t does not have to be unsigned long long, and unsigned long long does not have to be merely 64 bits.
bzt wrote:The interesting thing is, there seems to be no problems with printf, only with wsprintfW.
So on Windows, w*printf() has a different syntax from *printf()? What fresh hell is this? I presume this is because printf() and wprintf() are provided by different libraries, but then that means that whoever wrote the printf() library failed to add wprintf() to its repertoire. Another reason to use Cygwin (if you can stomach newlib).
bzt wrote:The only reason why I prefer mingw over Cygwin is, because I couldn't compile single binaries with Cygwin. There was always the need to ship cygwin.dll along.
Meh. I'd rather ship two files instead of one, than having to deal with a C implementation where parts of the library disagree with other parts. And no, this hasn't changed, as all Cygwin programs need to communicate with each other, and having a DLL allows them to switch out the protocol if need be.
Carpe diem!
reapersms
Member
Member
Posts: 48
Joined: Fri Oct 04, 2019 10:10 am

Re: Warning, gcc 10.2.0 incompatible changes!

Post by reapersms »

Time again to relay some (hopefully not too outdated) domain knowledge.

%I64 is microsoft's format specifier for unsigned long long from Back In The Day. Msys/Mingw can run into some issues if you don't have the cleanest set of headers, as they liked to link against the MSVCRT.DLL hiding in system32. It is fairly ancient, but when linking against it for printf, it's word is law. Hopefully you're using headers that match up nicely with it, but it does make porting unixy things straight to msys a tad inconvenient at times.

Supposedly, that one was supposed to be off limits for most of userland, according to R. Chen, and msys et al ignored that. I'm not sure how accurate that happens to be, but it is certainly plausible.

wprintf didn't exist until C95/C99, which I think had market penetration of effectively 0 until around 2010. MSVCRT.DLL dates from about '95, and MSVC was certainly not known for being up to date or remotely standards compliant at the time (4.2).

wsprintfA/W and wvsprintfA/W come from User32.dll, and were part of the windows API, not the language standard. The A/W comes from their habit of switching between ascii and unicode via #define's to paste the trailing letter on based on UNICODE. This is exceedingly annoying, as it means you can't reliably use the name of any win32 function that takes a string for anything else, regardless of scope. Have fun trying to name something LoadMenu.

As for cygwin, it rather aggressively does not play well with others. I keep an environment around due to inertia, but distributing anything built in it to others is nightmarish. Their approach to dealing with dll hell is for cygwin1.dll to crash out on load if there is more than one instance of it anywhere in PATH. That means you can't reasonably distribute it with your program at all, and have to rely on there being a working cygwin installation already, which is a subtlety that many, many places missed completely.

They also decided not to support \r\n as a line separator in bash or make at some point about 10 years ago, which was a questionable decision.
Octocontrabass
Member
Member
Posts: 5501
Joined: Mon Mar 25, 2013 7:01 pm

Re: Warning, gcc 10.2.0 incompatible changes!

Post by Octocontrabass »

So, to sum up this thread, there are no breaking changes in GCC 10.2.0.

The two issues bzt spotted are undefined behavior and an incompatibility caused by trying to mix the mingw printf functions with Microsoft's printf functions. I didn't see any attempts to print a size_t, so I don't think any changes would be necessary aside from removing this part of the makefile.
nullplan
Member
Member
Posts: 1760
Joined: Wed Aug 30, 2017 8:24 am

Re: Warning, gcc 10.2.0 incompatible changes!

Post by nullplan »

Octocontrabass wrote:So, to sum up this thread, there are no breaking changes in GCC 10.2.0.

The two issues bzt spotted are undefined behavior and an incompatibility caused by trying to mix the mingw printf functions with Microsoft's printf functions. I didn't see any attempts to print a size_t, so I don't think any changes would be necessary aside from removing this part of the makefile.
What about the issue of string pasting not working correctly? Even if the contents of the string end up not being useful to the printf() function in question, it is still defined that L"a" "b" "c" should be equal to L"abc", and not end up missing a zero-terminator. But then, bzt never did end up providing the assembly listing GCC generated, so I still don't know what happened to that point.
Carpe diem!
Octocontrabass
Member
Member
Posts: 5501
Joined: Mon Mar 25, 2013 7:01 pm

Re: Warning, gcc 10.2.0 incompatible changes!

Post by Octocontrabass »

nullplan wrote:What about the issue of string pasting not working correctly?
I built the example code provided by bzt using the same build system and compiler (MSYS2) and was not able to reproduce the issue. I suspect bzt just misread the hexdump.
Post Reply