Re: gcc 4.6.3 miscompile on ppc32 (was Re: Regression in kernel 4.12-rc1 for Powerpc 32 - bisected to commit 3448890c32c3)
Al Viro writes: > On Sun, Jun 25, 2017 at 04:44:09PM -0500, Segher Boessenkool wrote: > >> Do you have a short stand-alone testcase? 4.6 is ancient, of course, but >> the actual problem may still exist in more recent compilers (if it _is_ >> a compiler problem; if it's not, you *really* want to know :-) ) > > Enjoy. At least 6.3 doesn't step into that. Look for mtctr in the resulting > asm... > > cat <<'EOF' >a.c ... I pointed creduce at that and got the version below, which I'm pretty sure still exhibits the weird mtctr behaviour. cheers # cat input.c struct { void *iov_base; unsigned iov_len; } * c; long v; void *a; int b; unsigned bar(); foo(unsigned p1) { unsigned d, e = p1; if (p1 == 0) goto out; if (p1 > 4) goto out; if (__builtin_expect(!!(0, v && a), 1)) e = bar(); if (e) barf(e); if (e) goto out; d = 0; for (; d < p1; d++) { int f = c[d].iov_len; if (__builtin_expect(c[d].iov_base && f, 0)) b = 4; } out:; } $ cat output.s .file "input.c" # rs6000/powerpc options: -mcpu=powerpc -msdata=data -G 8 # GNU C (GCC) version 4.6.3 (powerpc64-linux) # compiled by GNU C version 4.3.2, GMP version 4.3.2, MPFR version 2.4.2, MPC version 0.8.2 # ... # Compiler executable checksum: 4b51a6b899110d06c9e3310ac66ad26c .section".text" .align 2 .globl foo .type foo, @function foo: cmpwi 0,3,0 # tmp169, p1 stwu 1,-16(1)#,, mflr 0 #, stw 0,20(1) #, beq- 0,.L9 # cmplwi 7,3,4 #, tmp170, p1 bgt- 7,.L9 # lis 9,v@ha # tmp172, lwz 0,v@l(9) # v, v cmpwi 7,0,0 #, tmp174, v beq- 7,.L3 # lis 9,a@ha # tmp176, lwz 0,a@l(9) # a, a cmpwi 7,0,0 #, tmp178, a beq- 7,.L3 # bl bar # cmpwi 0,3,0 # tmp179, e beq+ 0,.L4 # .L3: bl barf # b .L9# .L4: lis 8,0x2000 #, lis 9,c@ha # tmp181, mtctr 8 # tmp192, lwz 11,c@l(9)# c, c.3 lis 10,b@ha # tmp190, li 9,0 # ivtmp.12, li 0,4 # tmp191, .L6: lwzx 7,11,9 # MEM[base: c.3_14, index: ivtmp.12_25, offset: 0B], MEM[base: c.3_14, index: ivtmp.12_25, offset: 0B] add 8,11,9 # tmp182, c.3, ivtmp.12 lwz 8,4(8) # MEM[base: D.1310_21, offset: 4B], D.1287 cmpwi 7,7,0 #, tmp184, MEM[base: c.3_14, index: ivtmp.12_25, offset: 0B] beq+ 7,.L5 # cmpwi 7,8,0 #, tmp185, D.1287 beq+ 7,.L5 # stw 0,b@l(10)# b, tmp191 .L5: addi 9,9,8 # ivtmp.12, ivtmp.12, bdnz .L6 # .L2: .L9: lwz 0,20(1) #, addi 1,1,16 #,, mtlr 0 #, blr # .size foo,.-foo .globl b .globl a .globl v .globl c .section.sbss,"aw",@nobits .align 2 .type b, @object .size b, 4 b: .zero 4 .type a, @object .size a, 4 a: .zero 4 .type v, @object .size v, 4 v: .zero 4 .type c, @object .size c, 4 c: .zero 4 .ident "GCC: (GNU) 4.6.3" .section.note.GNU-stack,"",@progbits
Re: gcc 4.6.3 miscompile on ppc32 (was Re: Regression in kernel 4.12-rc1 for Powerpc 32 - bisected to commit 3448890c32c3)
On Sun, Jun 25, 2017 at 04:44:09PM -0500, Segher Boessenkool wrote: > Do you have a short stand-alone testcase? 4.6 is ancient, of course, but > the actual problem may still exist in more recent compilers (if it _is_ > a compiler problem; if it's not, you *really* want to know :-) ) Enjoy. At least 6.3 doesn't step into that. Look for mtctr in the resulting asm... cat <<'EOF' >a.c struct iovec { void *iov_base; unsigned iov_len; }; unsigned long v; extern void * barf(void *,int,unsigned); extern unsigned long bar(void *to, const void *from, unsigned long size); static inline unsigned long __bar(void *to, const void *from, unsigned long n) { unsigned long res = n; if (__builtin_expect(!!(((void)0, unsigned long)(from)) <= v) && n)) == 0) || n)) - 1) <= (v - (( unsigned long)(from, 1)) res = bar(to, from, n); if (res) barf(to + (n - res), 0, res); return res; } int foo(int type, const struct iovec * uvector, unsigned long nr_segs, unsigned long fast_segs, struct iovec *iov, struct iovec **ret_pointer) { unsigned long seg; int ret; if (nr_segs == 0) { ret = 0; goto out; } if (nr_segs > 1024) { ret = -22; goto out; } if (__bar(iov, uvector, nr_segs*sizeof(*uvector))) { ret = -14; goto out; } ret = 0; for (seg = 0; seg < nr_segs; seg++) { void *buf = iov[seg].iov_base; int len = (int)iov[seg].iov_len; if (len < 0) { ret = -22; goto out; } if (type >= 0 && __builtin_expect(!!(!((void)0, unsigned long)(buf)) <= v) && len)) == 0) || len)) - 1) <= (v - (( unsigned long)(buf, 0)) { ret = -14; goto out; } ret += len; } out: *ret_pointer = iov; return ret; } EOF powerpc-linux-gcc -m32 -fno-strict-aliasing -fno-common -std=gnu89 -fno-PIE -msoft-float -pipe -ffixed-r2 -mmultiple -mno-altivec -mno-vsx -mno-spe -mspe=no -funit-at-a-time -fno-dwarf2-cfi-asm -mno-string -mcpu=powerpc -Wa,-maltivec -mbig-endian -fno-delete-null-pointer-checks -Os -fno-stack-protector -Wno-unused-but-set-variable -fomit-frame-pointer -fno-var-tracking-assignments -femit-struct-debug-baseonly -fno-var-tracking -fno-strict-overflow -fconserve-stack -fverbose-asm -S a.c
Re: gcc 4.6.3 miscompile on ppc32 (was Re: Regression in kernel 4.12-rc1 for Powerpc 32 - bisected to commit 3448890c32c3)
On Sun, Jun 25, 2017 at 09:53:24PM +0100, Al Viro wrote: > Confirmed. It manages to bugger the loop immediately after the (successful) > copying of iovec array in rw_copy_check_uvector(); both with and without > INLINE_COPY_FROM_USER it has (just before the call of copy_from_user()) r27 > set to nr_segs * sizeof(struct iovec). The call is made, we check that it > has succeeded and that's when it hits the fan: without INLINE_COPY_FROM_USER > we have (interleaved with unrelated insns) > addi 27,27,-8 > srwi 27,27,3 > addi 27,27,1 > mtctr 27 > Weird, but manages to pass nr_segs to mtctr. This weirdosity is https://gcc.gnu.org/PR67288 . Those three instructions are not the same as just srwi 27,27,3 in case r27 is 0; GCC does not figure out this cannot happen here. > _With_ INLINE_COPY_FROM_USER we > get this: > lis 9,0x2000 > mtctr 9 > In other words, the loop will try to go through 8192 iterations. No idea > where > that number has come from, but it sure as hell is wrong. 8192*65535, even. This is as if r27 was 0 always. Do you have a short stand-alone testcase? 4.6 is ancient, of course, but the actual problem may still exist in more recent compilers (if it _is_ a compiler problem; if it's not, you *really* want to know :-) ) Segher