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

Reply via email to