This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c/61236] GCC 4.9 generates incorrect object code
- From: "muks at banu dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Mon, 19 May 2014 17:53:32 +0000
- Subject: [Bug c/61236] GCC 4.9 generates incorrect object code
- Auto-submitted: auto-generated
- References: <bug-61236-4 at http dot gcc dot gnu dot org/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61236
--- Comment #3 from Mukund Sivaraman <muks at banu dot com> ---
The following is _incorrect_ generated x86_64 code for
dns_rdataslab_fromrdataset() as compiled with:
gcc version 4.9.1 20140507 (prerelease) (GCC).
(the current version of GCC on Arch Linux).
NOTE that there are two copies of generated code for this
function. Either the first or second copy of code is called based on
whether (nalloc == 0) implying (nitems == 0) too.
In the (nitems == 0) case, the entire free_rdatas block is deleted by
GCC as x is inferred to be NULL.
In the (nitems != 0) case, the "if (x != NULL)" check is deleted as x is
inferred to NOT be NULL, and isc_mem_put() is always called.
The failed assertion obviously happens when (x == NULL), i.e.,
(nitems == 0). And the fact that the "if (x != NULL)" check was deleted
is an obvious sign that code flow is through that path to cause the
assertion failure.
Because the code is like noodles, I've added STEP# comments in the code
to take you through the (nitems == 0) case. Go from STEP #0 to STEP #13.
The bug happens because the (nitems == 0) case branches into code for
(nitems != 0) where checks have been removed.
; STEP #0
000000000051fc10 <dns_rdataslab_fromrdataset>:
51fc10: 41 57 push %r15
51fc12: 41 56 push %r14
51fc14: 49 89 f7 mov %rsi,%r15
51fc17: 41 55 push %r13
51fc19: 41 54 push %r12
51fc1b: 49 89 fc mov %rdi,%r12
51fc1e: 55 push %rbp
51fc1f: 53 push %rbx
51fc20: 48 83 ec 38 sub $0x38,%rsp
51fc24: 48 89 54 24 08 mov %rdx,0x8(%rsp)
51fc29: 89 4c 24 20 mov %ecx,0x20(%rsp)
51fc2d: e8 9e e7 ff ff callq 51e3d0 <dns_rdataset_count>
51fc32: 41 89 c5 mov %eax,%r13d
;; STEP #1
;; Is (nitems == 0)? If not, go to 51fc60. It is 0 in our case.
51fc35: 45 85 ed test %r13d,%r13d
51fc38: 75 26 jne 51fc60
<dns_rdataslab_fromrdataset+0x50>
;; STEP #2
;; if (nitems == 0 && rdataset->type != 0)
;; return (ISC_R_FAILURE);
;;
;; Here, let's take it that (rdataset->type != 0) so that we can
;; continue execution. Jump to 51fd20 (STEP #3).
51fc3a: 66 41 83 7c 24 22 00 cmpw $0x0,0x22(%r12)
51fc41: ba 19 00 00 00 mov $0x19,%edx
51fc46: 0f 84 d4 00 00 00 je 51fd20
<dns_rdataslab_fromrdataset+0x110>
; out:
;
; control comes back here as part of a "return;" statement's code from
; below.
51fc4c: 48 83 c4 38 add $0x38,%rsp
51fc50: 89 d0 mov %edx,%eax
51fc52: 5b pop %rbx
51fc53: 5d pop %rbp
51fc54: 41 5c pop %r12
51fc56: 41 5d pop %r13
51fc58: 41 5e pop %r14
51fc5a: 41 5f pop %r15
51fc5c: c3 retq
51fc5d: 0f 1f 00 nopl (%rax)
; (nitems != 0) case.
51fc60: 41 81 fd ff ff 00 00 cmp $0xffff,%r13d
51fc67: ba 13 00 00 00 mov $0x13,%edx
51fc6c: 77 de ja 51fc4c
<dns_rdataslab_fromrdataset+0x3c>
51fc6e: 44 89 e8 mov %r13d,%eax
51fc71: b9 a1 00 00 00 mov $0xa1,%ecx
51fc76: ba 6b e1 63 00 mov $0x63e16b,%edx
51fc7b: 48 8d 1c 40 lea (%rax,%rax,2),%rbx
51fc7f: 4c 89 ff mov %r15,%rdi
51fc82: 48 c1 e3 04 shl $0x4,%rbx
51fc86: 48 89 de mov %rbx,%rsi
51fc89: e8 d2 a9 0a 00 callq 5ca660 <isc__mem_get>
51fc8e: 48 85 c0 test %rax,%rax
51fc91: 49 89 c6 mov %rax,%r14
51fc94: 0f 84 7d 01 00 00 je 51fe17
<dns_rdataslab_fromrdataset+0x207>
51fc9a: 4c 89 e7 mov %r12,%rdi
; /* FIRST COPY OF GENERATED CODE (nalloc > 0) */
;
; result = dns_rdataset_first(rdataset);
51fc9d: e8 0e e8 ff ff callq 51e4b0 <dns_rdataset_first>
; if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
; goto free_rdatas;
; 0x1d (ISC_R_NOMORE)
51fca2: 83 f8 1d cmp $0x1d,%eax
51fca5: 74 08 je 51fcaf
<dns_rdataslab_fromrdataset+0x9f>
; 0x0 (ISC_R_SUCCESS). if (result != ISC_R_SUCCESS && result !=
; ISC_R_NOMORE), jmp to 51fd53 (free_rdatas) below.
51fca7: 85 c0 test %eax,%eax
51fca9: 0f 85 a4 00 00 00 jne 51fd53
<dns_rdataslab_fromrdataset+0x143>
; go below to free_rdatas.
; ignore: for loop
51fcaf: 31 ed xor %ebp,%ebp
51fcb1: 85 c0 test %eax,%eax
51fcb3: 74 1f je 51fcd4
<dns_rdataslab_fromrdataset+0xc4>
51fcb5: e9 82 00 00 00 jmpq 51fd3c
<dns_rdataslab_fromrdataset+0x12c>
51fcba: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
; ignore: for loop iterate (continue;)
51fcc0: 4c 89 e7 mov %r12,%rdi
51fcc3: 83 c5 01 add $0x1,%ebp
51fcc6: e8 35 e8 ff ff callq 51e500 <dns_rdataset_next>
51fccb: 85 c0 test %eax,%eax
51fccd: 75 6d jne 51fd3c
<dns_rdataslab_fromrdataset+0x12c>
51fccf: 41 39 ed cmp %ebp,%r13d
51fcd2: 76 68 jbe 51fd3c
<dns_rdataslab_fromrdataset+0x12c>
51fcd4: 89 e8 mov %ebp,%eax
51fcd6: 48 8d 1c 40 lea (%rax,%rax,2),%rbx
51fcda: 48 c1 e3 04 shl $0x4,%rbx
51fcde: 4c 01 f3 add %r14,%rbx
51fce1: 48 89 df mov %rbx,%rdi
51fce4: e8 37 ad fd ff callq 4faa20 <dns_rdata_init>
51fce9: 48 89 de mov %rbx,%rsi
51fcec: 4c 89 e7 mov %r12,%rdi
51fcef: e8 5c e8 ff ff callq 51e550 <dns_rdataset_current>
; Second INSIST() inside for loop. First INSIST() is redundant. In this
; compiler's output, the assertion call is inlined here.
51fcf4: 48 81 3b 28 f2 8b 00 cmpq $0x8bf228,(%rbx)
51fcfb: 75 c3 jne 51fcc0
<dns_rdataslab_fromrdataset+0xb0>
51fcfd: b9 77 e1 63 00 mov $0x63e177,%ecx
51fd02: ba 02 00 00 00 mov $0x2,%edx
51fd07: be b1 00 00 00 mov $0xb1,%esi
51fd0c: bf 6b e1 63 00 mov $0x63e16b,%edi
51fd11: e8 1a 81 09 00 callq 5b7e30 <isc_assertion_failed>
51fd16: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
51fd1d: 00 00 00
; STEP #3
51fd20: 4c 89 e7 mov %r12,%rdi
; /* SECOND COPY OF GENERATED CODE (nalloc == 0) */
;
; result = dns_rdataset_first(rdataset);
51fd23: e8 88 e7 ff ff callq 51e4b0 <dns_rdataset_first>
; if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
; goto free_rdatas;
; 0x1d (ISC_R_NOMORE)
;; Let's assume result is ISC_R_NOMORE here. So jump to 51fd37 (STEP #4).
51fd28: 83 f8 1d cmp $0x1d,%eax
51fd2b: 74 0a je 51fd37
<dns_rdataslab_fromrdataset+0x127>
; 0x0 (ISC_R_SUCCESS). if (result != ISC_R_SUCCESS && result !=
; ISC_R_NOMORE), jmp to 51fc4c (out) at the start of the function.
; If this jump is taken, isc__mem_put() is not called before return, but
; x is NULL here in this copy of call to dns_rdataset_first()
; (nalloc = dns_rdataset_count(rdataset) returned 0).
;; The mov between test and jne below won't affect ZF.
51fd2d: 85 c0 test %eax,%eax
51fd2f: 89 c2 mov %eax,%edx
51fd31: 0f 85 15 ff ff ff jne 51fc4c
<dns_rdataslab_fromrdataset+0x3c>
; STEP #4
;
; This just zeros some more variables and because %eax is still
; ISC_R_NOMORE, jumps to 51fd7b (STEP #5).
51fd37: 31 ed xor %ebp,%ebp
51fd39: 45 31 f6 xor %r14d,%r14d
51fd3c: 83 f8 1d cmp $0x1d,%eax
51fd3f: 74 3a je 51fd7b
<dns_rdataslab_fromrdataset+0x16b>
; before_free_rdatas:
; if (x == NULL), skip calling isc_mem_put()
51fd41: 4d 85 f6 test %r14,%r14
51fd44: 0f 84 12 02 00 00 je 51ff5c
<dns_rdataslab_fromrdataset+0x34c>
51fd4a: 4b 8d 5c 6d 00 lea 0x0(%r13,%r13,2),%rbx
51fd4f: 48 c1 e3 04 shl $0x4,%rbx
; STEP #13:
;
; free_rdatas: (nitems != 0) variant
;
; /* When a jmp is made to this location directly, this check is
missing,
; causing the assertion! */
;
; /* if (x != NULL) */
; isc_mem_put(mctx, x, nalloc * sizeof(struct xrdata));
; return (result);
;
;
51fd53: 48 89 da mov %rbx,%rdx
51fd56: 41 b8 4e 01 00 00 mov $0x14e,%r8d
51fd5c: b9 6b e1 63 00 mov $0x63e16b,%ecx
51fd61: 4c 89 f6 mov %r14,%rsi
51fd64: 4c 89 ff mov %r15,%rdi
51fd67: 89 44 24 20 mov %eax,0x20(%rsp)
51fd6b: e8 d0 ba 0a 00 callq 5cb840 <isc__mem_put>
51fd70: 8b 44 24 20 mov 0x20(%rsp),%eax
51fd74: 89 c2 mov %eax,%edx
51fd76: e9 d1 fe ff ff jmpq 51fc4c
<dns_rdataslab_fromrdataset+0x3c>
; the jmpq instruction above jumps above to "out:" label at the start of
; this function.
; STEP #5
;
; nalloc is 0 here, so the for (i = 0; i < nalloc... is skipped.
;
; if (i != nalloc) {
; /*
; * Somehow we iterated over fewer rdatas than
; * dns_rdataset_count() said there were!
; */
; result = ISC_R_FAILURE;
; goto free_rdatas;
; }
; In the following, the jne jumps to before_free_rdatas (above) where x
; is checked for NULL before calling isc_mem_put(). But (i == nalloc)
; here as the for loop was not entered. So keep going below to STEP #6.
51fd7b: 44 39 ed cmp %r13d,%ebp
51fd7e: b0 19 mov $0x19,%al
51fd80: 75 bf jne 51fd41
<dns_rdataslab_fromrdataset+0x131>
; STEP #6
;
; qsort(x, nalloc, sizeof(struct xrdata), compare_rdata);
51fd82: 8b 44 24 20 mov 0x20(%rsp),%eax
51fd86: b9 80 fb 51 00 mov $0x51fb80,%ecx
51fd8b: ba 30 00 00 00 mov $0x30,%edx
51fd90: 4c 89 f7 mov %r14,%rdi
51fd93: 8d 58 02 lea 0x2(%rax),%ebx
51fd96: 89 e8 mov %ebp,%eax
51fd98: 48 89 c6 mov %rax,%rsi
51fd9b: 48 89 44 24 28 mov %rax,0x28(%rsp)
51fda0: e8 8b 6f ee ff callq 406d30 <qsort@plt>
; for (i = 1; i < nalloc; i++) {
; Here, nalloc is 0, so we jump to 51ff3c (STEP #7).
51fda5: 83 fd 01 cmp $0x1,%ebp
51fda8: 0f 86 8e 01 00 00 jbe 51ff3c
<dns_rdataslab_fromrdataset+0x32c>
51fdae: 8d 45 fe lea -0x2(%rbp),%eax
51fdb1: 4d 89 f5 mov %r14,%r13
51fdb4: 89 6c 24 24 mov %ebp,0x24(%rsp)
51fdb8: 48 8d 44 40 03 lea 0x3(%rax,%rax,2),%rax
51fdbd: 48 c1 e0 04 shl $0x4,%rax
51fdc1: 4c 01 f0 add %r14,%rax
51fdc4: 48 89 44 24 18 mov %rax,0x18(%rsp)
51fdc9: eb 17 jmp 51fde2
<dns_rdataslab_fromrdataset+0x1d2>
51fdcb: 83 6c 24 24 01 subl $0x1,0x24(%rsp)
51fdd0: 49 c7 45 00 28 f2 8b movq $0x8bf228,0x0(%r13)
51fdd7: 00
51fdd8: 48 3b 4c 24 18 cmp 0x18(%rsp),%rcx
51fddd: 49 89 cd mov %rcx,%r13
51fde0: 74 3f je 51fe21
<dns_rdataslab_fromrdataset+0x211>
51fde2: 49 8d 4d 30 lea 0x30(%r13),%rcx
51fde6: 4c 89 ef mov %r13,%rdi
51fde9: 48 89 ce mov %rcx,%rsi
51fdec: 48 89 4c 24 10 mov %rcx,0x10(%rsp)
51fdf1: e8 2a e2 fd ff callq 4fe020 <dns_rdata_compare>
51fdf6: 85 c0 test %eax,%eax
51fdf8: 48 8b 4c 24 10 mov 0x10(%rsp),%rcx
51fdfd: 74 cc je 51fdcb
<dns_rdataslab_fromrdataset+0x1bb>
51fdff: 41 8b 45 08 mov 0x8(%r13),%eax
51fe03: 01 d8 add %ebx,%eax
51fe05: 8d 58 02 lea 0x2(%rax),%ebx
51fe08: 83 c0 03 add $0x3,%eax
51fe0b: 66 41 83 7c 24 22 2e cmpw $0x2e,0x22(%r12)
51fe12: 0f 44 d8 cmove %eax,%ebx
51fe15: eb c1 jmp 51fdd8
<dns_rdataslab_fromrdataset+0x1c8>
51fe17: ba 01 00 00 00 mov $0x1,%edx
51fe1c: e9 2b fe ff ff jmpq 51fc4c
<dns_rdataslab_fromrdataset+0x3c>
51fe21: 89 e8 mov %ebp,%eax
51fe23: 83 e8 01 sub $0x1,%eax
51fe26: 48 8d 04 40 lea (%rax,%rax,2),%rax
51fe2a: 48 c1 e0 04 shl $0x4,%rax
51fe2e: 41 8b 44 06 08 mov 0x8(%r14,%rax,1),%eax
51fe33: 8d 5c 03 02 lea 0x2(%rbx,%rax,1),%ebx
; STEP #8
51fe37: 41 0f b7 44 24 22 movzwl 0x22(%r12),%eax
51fe3d: 31 d2 xor %edx,%edx
51fe3f: 66 83 f8 2e cmp $0x2e,%ax
51fe43: 0f 94 c2 sete %dl
51fe46: 01 d3 add %edx,%ebx
; if (nitems > 1 && dns_rdatatype_issingleton(rdataset->type)) {
;
; here, nitems = 0. so jmp to 51fe72 (STEP #9)
51fe48: 83 7c 24 24 01 cmpl $0x1,0x24(%rsp)
51fe4d: 76 23 jbe 51fe72
<dns_rdataslab_fromrdataset+0x262>
51fe4f: 0f b7 f8 movzwl %ax,%edi
51fe52: e8 c9 d6 ff ff callq 51d520
<dns_rdatatype_issingleton>
51fe57: 85 c0 test %eax,%eax
51fe59: 74 17 je 51fe72
<dns_rdataslab_fromrdataset+0x262>
51fe5b: b8 48 00 01 00 mov $0x10048,%eax
; STEP #12
;
; Jump to 51fd53 (STEP #13)
51fe60: 48 8b 4c 24 28 mov 0x28(%rsp),%rcx
51fe65: 48 8d 1c 49 lea (%rcx,%rcx,2),%rbx
51fe69: 48 c1 e3 04 shl $0x4,%rbx
51fe6d: e9 e1 fe ff ff jmpq 51fd53
<dns_rdataslab_fromrdataset+0x143>
; STEP #9
;
; rawbuf = isc_mem_get(mctx, buflen);
51fe72: 89 de mov %ebx,%esi
51fe74: b9 0a 01 00 00 mov $0x10a,%ecx
51fe79: ba 6b e1 63 00 mov $0x63e16b,%edx
51fe7e: 4c 89 ff mov %r15,%rdi
51fe81: e8 da a7 0a 00 callq 5ca660 <isc__mem_get>
; if (rawbuf == NULL) {
; result = ISC_R_NOMEMORY;
; goto free_rdatas;
; }
;
;
; Here, things are already falling apart. if rawbuf is NULL, jump to 51ff52
which is the
; free_rdatas variant for (nalloc != 0) where the (x != NULL) check is
; deleted. But let's assume that rawbuf is not NULL here (likely case).
51fe86: 48 85 c0 test %rax,%rax
51fe89: 0f 84 c3 00 00 00 je 51ff52
<dns_rdataslab_fromrdataset+0x342>
; STEP #10
;
; for (i = 0; i < nalloc; i++) {
; if (x[i].rdata.data == &removed)
; continue;
;
;
; Here we test first that nalloc (%ebp) is 0. If it is (true in our
; case), jmp to 51ff35 (STEP #11). This also takes us to the free_rdatas
; variant for (nalloc != 0) where the (x != NULL) is deleted.
51fe8f: 48 8b 4c 24 08 mov 0x8(%rsp),%rcx
51fe94: 8b 54 24 20 mov 0x20(%rsp),%edx
51fe98: 48 89 01 mov %rax,(%rcx)
51fe9b: 89 59 08 mov %ebx,0x8(%rcx)
51fe9e: 8b 4c 24 24 mov 0x24(%rsp),%ecx
51fea2: 48 01 c2 add %rax,%rdx
51fea5: 85 ed test %ebp,%ebp
51fea7: 48 89 c8 mov %rcx,%rax
51feaa: 88 4a 01 mov %cl,0x1(%rdx)
51fead: 0f b6 c4 movzbl %ah,%eax
51feb0: 88 02 mov %al,(%rdx)
51feb2: 48 8d 42 02 lea 0x2(%rdx),%rax
51feb6: 74 7d je 51ff35
<dns_rdataslab_fromrdataset+0x325>
51feb8: 83 ed 01 sub $0x1,%ebp
51febb: 49 8d 5e 08 lea 0x8(%r14),%rbx
51febf: 48 8d 54 6d 00 lea 0x0(%rbp,%rbp,2),%rdx
51fec4: 48 c1 e2 04 shl $0x4,%rdx
51fec8: 49 8d 6c 16 38 lea 0x38(%r14,%rdx,1),%rbp
51fecd: eb 20 jmp 51feef
<dns_rdataslab_fromrdataset+0x2df>
51fecf: 90 nop
51fed0: 8b 13 mov (%rbx),%edx
51fed2: 48 8b 73 f8 mov -0x8(%rbx),%rsi
51fed6: 48 89 cf mov %rcx,%rdi
51fed9: e8 02 6c ee ff callq 406ae0 <memmove@plt>
51fede: 48 89 c1 mov %rax,%rcx
51fee1: 8b 03 mov (%rbx),%eax
51fee3: 48 01 c8 add %rcx,%rax
51fee6: 48 83 c3 30 add $0x30,%rbx
51feea: 48 39 eb cmp %rbp,%rbx
51feed: 74 46 je 51ff35
<dns_rdataslab_fromrdataset+0x325>
51feef: 48 81 7b f8 28 f2 8b cmpq $0x8bf228,-0x8(%rbx)
51fef6: 00
51fef7: 74 ed je 51fee6
<dns_rdataslab_fromrdataset+0x2d6>
51fef9: 31 d2 xor %edx,%edx
51fefb: 66 41 83 7c 24 22 2e cmpw $0x2e,0x22(%r12)
51ff02: 0f 94 c2 sete %dl
51ff05: 03 13 add (%rbx),%edx
51ff07: 81 fa ff ff 00 00 cmp $0xffff,%edx
51ff0d: 77 54 ja 51ff63
<dns_rdataslab_fromrdataset+0x353>
51ff0f: 0f b6 ce movzbl %dh,%ecx
51ff12: 88 50 01 mov %dl,0x1(%rax)
51ff15: 88 08 mov %cl,(%rax)
51ff17: 66 41 83 7c 24 22 2e cmpw $0x2e,0x22(%r12)
51ff1e: 48 8d 48 02 lea 0x2(%rax),%rcx
51ff22: 75 ac jne 51fed0
<dns_rdataslab_fromrdataset+0x2c0>
51ff24: 8b 53 08 mov 0x8(%rbx),%edx
51ff27: 48 8d 48 03 lea 0x3(%rax),%rcx
51ff2b: d1 ea shr %edx
51ff2d: 83 e2 01 and $0x1,%edx
51ff30: 08 50 02 or %dl,0x2(%rax)
51ff33: eb 9b jmp 51fed0
<dns_rdataslab_fromrdataset+0x2c0>
; STEP #11
;
; Jump to 51fe60 (STEP #12)
51ff35: 31 c0 xor %eax,%eax
51ff37: e9 24 ff ff ff jmpq 51fe60
<dns_rdataslab_fromrdataset+0x250>
; STEP #7
;
; check if nalloc is 0 (it is). jmp to 51fe37 (STEP #8).
51ff3c: 85 ed test %ebp,%ebp
51ff3e: 89 6c 24 24 mov %ebp,0x24(%rsp)
51ff42: b8 01 00 00 00 mov $0x1,%eax
51ff47: 0f 84 ea fe ff ff je 51fe37
<dns_rdataslab_fromrdataset+0x227>
51ff4d: e9 d1 fe ff ff jmpq 51fe23
<dns_rdataslab_fromrdataset+0x213>
51ff52: b8 01 00 00 00 mov $0x1,%eax
51ff57: e9 04 ff ff ff jmpq 51fe60
<dns_rdataslab_fromrdataset+0x250>
51ff5c: 89 c2 mov %eax,%edx
51ff5e: e9 e9 fc ff ff jmpq 51fc4c
<dns_rdataslab_fromrdataset+0x3c>
51ff63: b9 33 2c 5f 00 mov $0x5f2c33,%ecx
51ff68: ba 02 00 00 00 mov $0x2,%edx
51ff6d: be 34 01 00 00 mov $0x134,%esi
51ff72: bf 6b e1 63 00 mov $0x63e16b,%edi
51ff77: e8 b4 7e 09 00 callq 5b7e30 <isc_assertion_failed>
51ff7c: 0f 1f 40 00 nopl 0x0(%rax)