Bug#813858: gcc-5: [mips] regression: miscompilation caused by -fexpensive-optimizations

Andreas Cadhalpun <[email protected]>
Newsgroups gmane.linux.debian.ports.mips
Message-ID <56B54E8B.2020407__29461.6926381879$1454722958$gmane$org@googlemail.com>
Package: gcc-5
Version: 5.3.1-7
Severity: serious
Justification: causes ffmpeg to FTBFS
Control: affects -1 ffmpeg
X-Debbugs-Cc: [email protected]

Dear Maintainer,

ffmpeg 7:2.8.6-1 failed to build on mips due to test failures.

I investigated the problem and it turns out to be caused by a compiler bug
that can be avoided by using '-fno-expensive-optimizations'.
(Somehow this feels like Déjà vu... #800318)

Attached is a reduced test case:
$ ls
Makefile  main.c  test.c
$  make
cc -fPIC -g -O2 -fno-expensive-optimizations -c -o working.o test.c
cc -shared -o libworking.so working.o
cc -fPIC -g -o working main.c -L. -lworking
cc -fPIC -g -O2 -c -o broken.o test.c
cc -shared -o libbroken.so broken.o
cc -fPIC -g -o broken main.c -L. -lbroken
LD_LIBRARY_PATH=. ./working || true
chunk_size: 11760
working
LD_LIBRARY_PATH=. ./broken || true
chunk_size: 0
broken

This works correctly with gcc-5 5.3.1-6, so it is a regression in 5.3.1-7.
The difference between broken.o compiled by 5.3.1-6 and 5.3.1-7 is shown
by diffoscope as:
├── objdump --line-numbers --disassemble --section=.text {}
│ @@ -17,23 +17,23 @@
│    18:	24420001 	addiu	v0,v0,1
│    1c:	24630001 	addiu	v1,v1,1
│    20:	aca2000c 	sw	v0,12(a1)
│  ./test.c:28 (discriminator 3)
│    24:	1446fffb 	bne	v0,a2,14 <roq_read_packet+0x14>
│    28:	a064ffff 	sb	a0,-1(v1)
│  ./test.c:32
│ -  2c:	8ba4000a 	lwl	a0,10(sp)
│ -  30:	97a2000c 	lhu	v0,12(sp)
│ -  34:	9ba4000d 	lwr	a0,13(sp)
│ -  38:	7c0210a0 	wsbh	v0,v0
│ +  2c:	8ba3000a 	lwl	v1,10(sp)
│ +  30:	97a4000c 	lhu	a0,12(sp)
│ +  34:	9ba3000d 	lwr	v1,13(sp)
│ +  38:	7c0420a0 	wsbh	a0,a0
│  ./test.c:33
│    3c:	27bd0010 	addiu	sp,sp,16
│  ./test.c:32
│ -  40:	00021c00 	sll	v1,v0,0x10
│ -  44:	00041202 	srl	v0,a0,0x8
│ -  48:	00042602 	srl	a0,a0,0x18
│ -  4c:	3042ff00 	andi	v0,v0,0xff00
│ -  50:	00621025 	or	v0,v1,v0
│ +  40:	3084ffff 	andi	a0,a0,0xffff
│ +  44:	00031200 	sll	v0,v1,0x8
│ +  48:	7c633a00 	ext	v1,v1,0x8,0x8
│ +  4c:	00431825 	or	v1,v0,v1
│ +  50:	00031400 	sll	v0,v1,0x10
│  ./test.c:33
│    54:	03e00008 	jr	ra
│    58:	00441025 	or	v0,v0,a0
│    5c:	00000000 	nop
├── readelf --wide --decompress --string-dump=.comment {}
│ @@ -1,4 +1,4 @@
│  
│  String dump of section '.comment':
│ -  [     1]  GCC: (Debian 5.3.1-6) 5.3.1 20160114
│ +  [     1]  GCC: (Debian 5.3.1-7) 5.3.1 20160121
│  
╵

I hope that helps to fix this bug soon.

Best regards,
Andreas


-- System Information:
Debian Release: stretch/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: mips

Kernel: Linux 4.3.0-1-amd64 (SMP w/4 CPU cores)
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968) (ignored: LC_ALL set to C)
Shell: /bin/sh linked to /bin/dash
Init: unable to detect

Versions of packages gcc-5 depends on:
ii  binutils      2.26-3
ii  cpp-5         5.3.1-7
ii  gcc-5-base    5.3.1-7
ii  libc6         2.21-7
ii  libcc1-0      5.3.1-7
ii  libgcc-5-dev  5.3.1-7
ii  libgcc1       1:5.3.1-7
ii  libgmp10      2:6.1.0+dfsg-2
ii  libisl15      0.16.1-1
ii  libmpc3       1.0.3-1
ii  libmpfr4      3.1.3-2
ii  libstdc++6    5.3.1-7
ii  zlib1g        1:1.2.8.dfsg-2+b1

Versions of packages gcc-5 recommends:
ii  libc6-dev  2.21-7

Versions of packages gcc-5 suggests:
pn  gcc-5-doc         <none>
pn  gcc-5-locales     <none>
pn  gcc-5-multilib    <none>
pn  libasan2-dbg      <none>
pn  libatomic1-dbg    <none>
pn  libcilkrts5-dbg   <none>
pn  libgcc1-dbg       <none>
pn  libgomp1-dbg      <none>
pn  libitm1-dbg       <none>
pn  liblsan0-dbg      <none>
pn  libmpx0-dbg       <none>
pn  libquadmath0-dbg  <none>
pn  libtsan0-dbg      <none>
pn  libubsan0-dbg     <none>

-- no debconf information
main.c (text/x-csrc, 1005 B)
#include <inttypes.h>
#include <stdio.h>

typedef struct AVIOContext {
    uint8_t a[4];
    uint8_t *buffer;
    int32_t buffer_size;
    uint8_t *buf_ptr;
} AVIOContext;

typedef struct AVFormatContext {
    uint8_t a[15];
    AVIOContext* pb;
} AVFormatContext;

typedef struct AVPacket {
    void *a;
} AVPacket;

int roq_read_packet(AVFormatContext *s, AVPacket *pkt);

int main()
{
    AVPacket pkt = { 0 };
    AVFormatContext s = { 0 };
    AVIOContext pb = { 0 };
    uint8_t buffer[32768] = { 0x84, 0x10, 0xff, 0xff, 0xff, 0xff, 0x1e, 0x00,
                              0x21, 0x10, 0xf0, 0x2d, 0x00, 0x00, 0x00, 0x00,
                              0 };

    pb.buffer = buffer;
    pb.buffer_size = 32768;
    pb.buf_ptr = &buffer[8];
    s.pb = &pb;

    int chunk_size = roq_read_packet(&s, &pkt);
    printf("chunk_size: %u\n", chunk_size);
    if (chunk_size == 0x2df0) {
        printf("working\n");
        return 0;
    }
    else {
        printf("broken\n");
        return 1;
    }
}
Makefile (text/plain, 627 B)
CFLAGS += -fPIC -g
LDFLAGS += -shared

all: working broken
	LD_LIBRARY_PATH=. ./working || true
	LD_LIBRARY_PATH=. ./broken || true

working.o:
	$(CC) $(CFLAGS) -O2 -fno-expensive-optimizations -c -o working.o test.c

broken.o:
	$(CC) $(CFLAGS) -O2 -c -o broken.o test.c

libworking.so: working.o
	$(CC) $(LDFLAGS) -o libworking.so working.o

libbroken.so: broken.o
	$(CC) $(LDFLAGS) -o libbroken.so broken.o

working: libworking.so
	$(CC) $(CFLAGS) -o working main.c -L. -lworking

broken: libbroken.so
	$(CC) $(CFLAGS) -o broken main.c -L. -lbroken

clean:
	rm -f working.o libworking.so working broken.o libbroken.so broken
test.c (text/x-csrc, 734 B)
#include <inttypes.h>

typedef struct AVIOContext {
    uint8_t a[4];
    uint8_t *buffer;
    int32_t buffer_size;
    uint8_t *buf_ptr;
} AVIOContext;

typedef struct AVFormatContext {
    uint8_t a[15];
    AVIOContext* pb;
} AVFormatContext;

typedef struct AVPacket {
    void *a;
} AVPacket;

static uint32_t av_bswap32(uint32_t x)
{
    return ((((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) << 16 | ((((x) >> 16) << 8 & 0xff00) | (((x) >> 16) >> 8 & 0x00ff)));
}

int roq_read_packet(AVFormatContext *s, AVPacket *pkt)
{
    unsigned char preamble[8];
    int i;
    for (i = 0; i < 8; i += 1) {
        preamble[i] = s->pb->buf_ptr[0];
        s->pb->buf_ptr += 1;
    }
    return av_bswap32(*((uint32_t *) (&preamble[2])));
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.