https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102844
Bug ID: 102844 Summary: gcc-9.x miscompiles unsigned char expression in switch Product: gcc Version: 9.3.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: breiten at lexmark dot com Target Milestone: --- The code included below demonstrates a code-generation bug we found in gcc-9.3 (built with poky's dunfell branch) It is present in all of the 9.x releases, but none of the 10.x releases. Anticipating your first question, I found that this problem is NOT present in gcc-10.2, so I went earlier in that branch and was able to see that it was corrected by 744fd446c321f78f9a1ce4ef5f83df8dcfa44a9 (gcc-10 branch, but before gcc-10.1 release) Nothing in the commit messages suggests a bug fix. I've also been able to pinpoint the commit where the problem first appears in the gcc-9 branch: 1a438d160e1dc845882c2ecba99513a09a931623. Here, the commit message describes this commit to be a bug fix. My dilemma is that I'm stuck in the 9 branch for a while. Reverting a bug fix doesn't feel right. But while picking up the commit from gcc-10 does appear to work, it a bit more than a simple bug-fix, and I'd like to hear some opinions regarding its appropriateness. Maybe there it still a bug out there, and the commit from gcc-10 just makes this particular code compile properly. In the C source below, line 58 miscompiles into an unconditional store of 0x80. Notice that I have two switch statements on the same variable and with the same cases. If I remove or alter the other one, the bad code and the warning goes away. It also is only present when "nd - 0x80" is stored to a uchar variable. If its stored to an int or printf'd the code is correct. Also, adding "U" suffix to 0x80 corrects the expression. And I get the warning regardless of what number I subtract from nd, suggesting that it is incorrectly considered a signed char, and subtracting anything would underflow. I see the problem with -Os or -O2, and -fno-strict-overflow is needed. In cleaning up the command line, I found that linux adds -Wno-maybe-uninitialized. Removing that leads to this message: attach3.c:60:22: warning: '({anonymous})' may be used uninitialized in this function [-Wmaybe-uninitialized] 58 | *ic = nd - 0x80; /* compiles into an unconditional store of 0x80 */ | ~~~^~~~~~ Here's my gcc configuration: Target: arm-poky-linux-gnueabi Configured with: ../../../../../../work-shared/gcc-9.3.0-r0/gcc-9.3.0/configure --build=x86_64-linux --host=x86_64-linux --target=arm-poky-linux-gnueabi --prefix=/host-native/usr --exec_prefix=/host-native/usr --bindir=/host-native/usr/bin/arm-poky-linux-gnueabi --sbindir=/host-native/usr/bin/arm-poky-linux-gnueabi --libexecdir=/host-native/usr/libexec/arm-poky-linux-gnueabi --datadir=/host-native/usr/share --sysconfdir=/host-native/etc --sharedstatedir=/host-native/com --localstatedir=/host-native/var --libdir=/host-native/usr/lib/arm-poky-linux-gnueabi --includedir=/host-native/usr/include --oldincludedir=/host-native/usr/include --infodir=/host-native/usr/share/info --mandir=/host-native/usr/share/man --disable-silent-rules --disable-dependency-tracking --with-libtool-sysroot=/host-native --enable-clocale=generic --with-gnu-ld --enable-shared --enable-languages=c,c++ --enable-threads=posix --disable-multilib --enable-default-pie --enable-c99 --enable-long-long --enable-symvers=gnu --enable-libstdcxx-pch --program-prefix=arm-poky-linux-gnueabi- --without-local-prefix --disable-install-libiberty --enable-lto --disable-libssp --enable-libitm --disable-bootstrap --disable-libmudflap --with-system-zlib --with-linker-hash-style=sysv --enable-linker-build-id --with-ppl=no --with-cloog=no --enable-checking=release --enable-cheaders=c_global --without-isl --with-gxx-include-dir=/not/exist/usr/include/c++/9.3.0 --with-sysroot=/not/exist --with-build-sysroot=/host --enable-poison-system-directories --with-system-zlib --disable-static --disable-nls --with-glibc-version=2.28 --enable-initfini-array Thread model: posix gcc version 9.3.0 (GCC) << code to demonstrate problem >> typedef struct { void (*request)(int request, void *arg); } po_t; po_t *po; unsigned char *ambp(void); unsigned char da; unsigned char dic; unsigned char gnda(unsigned char current_address, int sequence); void rnsm(void); int state = 0; static unsigned char *attach_mb_ptr; static unsigned char ta; static unsigned char lda; static unsigned char snod(unsigned char cd, unsigned char *tl, unsigned char *ic) { unsigned char nd; while ((nd = gnda(cd,0)) != 0x21) { int Req; po->request(57, &Req); if (!Req) break; } if (nd != 0x21) { switch (nd) { case 0x95: *tl = 0x01; break; case 0x80: case 0x81: case 0x82: *tl = 0x00; break; default: *tl = 0x05; break; } } if (nd != 0x21) { switch (nd) { case 0x95: *ic = nd - 0x91; break; case 0x80: case 0x81: case 0x82: *ic = nd - 0x80; /* compiles into an unconditional store of 0x80 */ break; default: *ic = 0; break; } } return nd; } void rosm3(unsigned char reason) { switch(state) { case 0: attach_mb_ptr = ambp(); da = snod(0x20, &ta, &dic); break; case 1: lda = da; if ((da = snod(lda, &ta, &dic)) != 0x21) if (reason == 1) rnsm(); break; } }