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;
}
}