Colin Watson writes ("Bug#772718: adns: test failure on Ubuntu ppc64el, with -O3"): > To reproduce this it appears to be sufficient to build with -O3. Feel > free to use the "cjwatson-adns" session on pastel.debian.net to > reproduce this; "DEB_CFLAGS_APPEND=-O3 debian/rules build" in an > unpacked copy of the latest adns source package does the job.
Thanks. I have repro'd this and traced the root cause. The problem is a malicious optimisation of the following function in the test suite: void *Hrealloc(void *op, size_t nsz) { struct malloced *oldnode; void *np; size_t osz; if (op) { oldnode= (void*)((char*)op - MALLOCHSZ); osz= oldnode->sz; } else { osz= 0; } np= Hmalloc(nsz); memcpy(np,op, osz>nsz ? nsz : osz); Hfree(op); return np; } The standards bodies have decided that (contrary to traditional practice) memcpy(0,0,0) is UB. Hence, GCC reasons as follows: If !op, we still call memcpy(np,op,0). Which is UB. Therefore !!op. Therefore I don't need to actually compile the !op branches. I suspect that this only shows up with -O3 because in that case a copy of Hfree is inlined into Hrealloc. (gcc evidently fails to remove the also wrongfully-provably-unnecessary osz=0 branch, since osz=oldnode->sz would crash.) With the debugging printf patch below, and building upstream adns 1.5.0 with gcc 4.9.1-19 on i386 and with XCFLAGS='-O3 -fno-builtin-cpp', I see this output: Hmalloc 8 -> 0x8299018 (node=0x8299008 next=(nil) back=(nil) count=1) Hmalloc 16 -> 0x8299038 (node=0x8299028 next=(nil) back=0x8299008 count=2) Hmalloc 1452 -> 0x8299060 (node=0x8299050 next=(nil) back=0x8299028 count=3) Hmalloc 8 -> 0x8299620 (node=0x8299610 next=(nil) back=0x8299050 count=4) Hmalloc 41 -> 0x8299640 (node=0x8299630 next=(nil) back=0x8299610 count=5) Hfree((nil)) Hmalloc 40 -> 0x8299b98 (node=0x8299b88 next=(nil) back=0x8299630 count=6) Hrealloc((nil), 40) -> 0x8299b98 Hfree((nil)) Hfree((nil)) (node=0xfffffff0) Segmentation fault (core dumped) Notice that in Hfree, which looks like this: void Hfree(void *ptr) { struct malloced *oldnode; fprintf(stderr,"Hfree(%p)\n",ptr); if (!ptr) return; oldnode= (void*)((char*)ptr - MALLOCHSZ); fprintf(stderr,"Hfree(%p) (node=%p)\n",ptr, oldnode); fprintf(stderr,"Hfree(%p) (node=%p next=%p back=%p count=%lu)\n",ptr, oldnode, oldnode->next, oldnode->back, The if (!ptr) check is removed. gdb shows this stack trace: #0 0x0804e129 in Hrealloc () at hcommon.c:278 #1 0x080595c9 in adns__vbuf_appendstr () #2 0x0804d1c6 in Qsocket () at hcommon.c:209 #3 0x0804b0c4 in Hsocket () #4 0x0805c21e in init_finish () at ../src/setup.c:670 #5 0x0805cbba in adns_init_strcfg () at ../src/setup.c:761 #6 0x0804909a in main () at ../client/adnstest.c:244 The fix is obvious and will follow in my next email. Ian. diff --git a/regress/hcommon.c b/regress/hcommon.c index ebbef94..d59104b 100644 --- a/regress/hcommon.c +++ b/regress/hcommon.c @@ -265,12 +265,20 @@ void *Hmalloc(size_t sz) { } assert(newnode->count != mallocfailat); memset(&newnode->data,0xc7,sz); +fprintf(stderr,"Hmalloc %lu -> %p (node=%p next=%p back=%p count=%lu)\n", + (unsigned long)sz,&newnode->data, + newnode, newnode->next, newnode->back, newnode->count); return &newnode->data; } void Hfree(void *ptr) { struct malloced *oldnode; +fprintf(stderr,"Hfree(%p)\n",ptr); if (!ptr) return; oldnode= (void*)((char*)ptr - MALLOCHSZ); +fprintf(stderr,"Hfree(%p) (node=%p)\n",ptr, oldnode); +fprintf(stderr,"Hfree(%p) (node=%p next=%p back=%p count=%lu)\n",ptr, + oldnode, + oldnode->next, oldnode->back, oldnode->count); LIST_UNLINK(mallocedlist,oldnode); memset(&oldnode->data,0x38,oldnode->sz); free(oldnode); @@ -281,6 +289,7 @@ void *Hrealloc(void *op, size_t nsz) { size_t osz; if (op) { oldnode= (void*)((char*)op - MALLOCHSZ); osz= oldnode->sz; } else { osz= 0; } np= Hmalloc(nsz); +fprintf(stderr,"Hrealloc(%p, %lu) -> %p\n", op, (unsigned long)nsz, np); memcpy(np,op, osz>nsz ? nsz : osz); Hfree(op); return np; diff --git a/regress/hcommon.c.m4 b/regress/hcommon.c.m4 index c5069ee..3290596 100644 --- a/regress/hcommon.c.m4 +++ b/regress/hcommon.c.m4 @@ -280,15 +280,28 @@ void *Hmalloc(size_t sz) { } assert(newnode->count != mallocfailat); memset(&newnode->data,0xc7,sz); + +fprintf(stderr,"Hmalloc %lu -> %p (node=%p next=%p back=%p count=%lu)\n", + (unsigned long)sz,&newnode->data, + newnode, newnode->next, newnode->back, newnode->count); + return &newnode->data; } void Hfree(void *ptr) { struct malloced *oldnode; +fprintf(stderr,"Hfree(%p)\n",ptr); + if (!ptr) return; oldnode= (void*)((char*)ptr - MALLOCHSZ); + +fprintf(stderr,"Hfree(%p) (node=%p)\n",ptr, oldnode); +fprintf(stderr,"Hfree(%p) (node=%p next=%p back=%p count=%lu)\n",ptr, + oldnode, + oldnode->next, oldnode->back, oldnode->count); + LIST_UNLINK(mallocedlist,oldnode); memset(&oldnode->data,0x38,oldnode->sz); free(oldnode); @@ -301,6 +314,7 @@ void *Hrealloc(void *op, size_t nsz) { if (op) { oldnode= (void*)((char*)op - MALLOCHSZ); osz= oldnode->sz; } else { osz= 0; } np= Hmalloc(nsz); +fprintf(stderr,"Hrealloc(%p, %lu) -> %p\n", op, (unsigned long)nsz, np); memcpy(np,op, osz>nsz ? nsz : osz); Hfree(op); return np; -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org