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 [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]