Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/external/cddl/osnet/dist/tools/ctf/cvt Fix a segfault in ctf...



details:   https://anonhg.NetBSD.org/src/rev/08df9ed23e29
branches:  trunk
changeset: 772637:08df9ed23e29
user:      darran <darran%NetBSD.org@localhost>
date:      Tue Jan 10 08:42:22 2012 +0000

description:
Fix a segfault in ctfmerge.

GCC can generate bogus dwarf attributes with DW_AT_byte_size set to 0xFFFFFFFF.
See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=35998 .

GCC is currently doing this for external/bsd/tmux/dist/compat/imsg-buffer.c:
    readelf -a --debug-dump imsg-buffer.o
        ...
         <2><6e3>: Abbrev Number: 32 (DW_TAG_union_type)
            <6e4>   DW_AT_byte_size   : 0xffffffff
            <6e8>   DW_AT_decl_file   : 1
            <6e9>   DW_AT_decl_line   : 229
            <6ea>   DW_AT_sibling     : <0x705>

This resulted in ctfconvert generating a faulty CTF entry which then caused the
segfault in ctfmerge.

The fix has ctfconvert check for the bogus 0xFFFFFFFF value and works around it.
It also adds some protection to ctfmerge to avoid the segfault and fail
more gracefully if the error should occur in the future.

diffstat:

 external/cddl/osnet/dist/tools/ctf/cvt/ctf.c   |  13 ++++++++-
 external/cddl/osnet/dist/tools/ctf/cvt/dwarf.c |  36 ++++++++++++++++++++++++-
 2 files changed, 46 insertions(+), 3 deletions(-)

diffs (136 lines):

diff -r ed9fd63c2db9 -r 08df9ed23e29 external/cddl/osnet/dist/tools/ctf/cvt/ctf.c
--- a/external/cddl/osnet/dist/tools/ctf/cvt/ctf.c      Tue Jan 10 01:57:27 2012 +0000
+++ b/external/cddl/osnet/dist/tools/ctf/cvt/ctf.c      Tue Jan 10 08:42:22 2012 +0000
@@ -53,6 +53,10 @@
  */
 char *curfile;
 
+
+/* The number of types. */
+static int ntypes=0;
+
 #define        CTF_BUF_CHUNK_SIZE      (64 * 1024)
 #define        RES_BUF_CHUNK_SIZE      (64 * 1024)
 
@@ -1048,6 +1052,9 @@
                                        (*mpp)->ml_type = tdarr[ctm->ctm_type];
                                        (*mpp)->ml_offset = ctm->ctm_offset;
                                        (*mpp)->ml_size = 0;
+                                       if (ctm->ctm_type > ntypes) {
+                                           parseterminate("Invalid member type ctm_type=%d", ctm->ctm_type);
+                                       }
                                }
                        } else {
                                for (i = 0, mpp = &tdp->t_members; i < vlen;
@@ -1064,6 +1071,9 @@
                                        (*mpp)->ml_offset =
                                            (int)CTF_LMEM_OFFSET(ctlm);
                                        (*mpp)->ml_size = 0;
+                                       if (ctlm->ctlm_type > ntypes) {
+                                           parseterminate("Invalid lmember type ctlm_type=%d", ctlm->ctlm_type);
+                                       }
                                }
                        }
 
@@ -1177,9 +1187,10 @@
 {
        tdata_t *td = tdata_new();
        tdesc_t **tdarr;
-       int ntypes = count_types(h, buf);
        int idx, i;
 
+       ntypes = count_types(h, buf);
+
        /* shudder */
        tdarr = xcalloc(sizeof (tdesc_t *) * (ntypes + 1));
        tdarr[0] = NULL;
diff -r ed9fd63c2db9 -r 08df9ed23e29 external/cddl/osnet/dist/tools/ctf/cvt/dwarf.c
--- a/external/cddl/osnet/dist/tools/ctf/cvt/dwarf.c    Tue Jan 10 01:57:27 2012 +0000
+++ b/external/cddl/osnet/dist/tools/ctf/cvt/dwarf.c    Tue Jan 10 08:42:22 2012 +0000
@@ -678,6 +678,12 @@
                tdesc_t *dimtdp;
                int flags;
 
+               /* Check for bogus gcc DW_AT_byte_size attribute */
+               if (uval == 0xffffffff) {
+                   printf("dwarf.c:%s() working around bogus DW_AT_byte_size = 0xffffffff\n", __func__);
+                   uval = 0;
+               }
+
                tdp->t_size = uval;
 
                /*
@@ -764,6 +770,11 @@
        tdp->t_type = ENUM;
 
        (void) die_unsigned(dw, die, DW_AT_byte_size, &uval, DW_ATTR_REQ);
+       /* Check for bogus gcc DW_AT_byte_size attribute */
+       if (uval == 0xffffffff) {
+           printf("dwarf.c:%s() working around bogus DW_AT_byte_size = 0xffffffff\n", __func__);
+           uval = 0;
+       }
        tdp->t_size = uval;
 
        if ((mem = die_child(dw, die)) != NULL) {
@@ -877,7 +888,7 @@
 die_sou_create(dwarf_t *dw, Dwarf_Die str, Dwarf_Off off, tdesc_t *tdp,
     int type, const char *typename)
 {
-       Dwarf_Unsigned sz, bitsz, bitoff;
+       Dwarf_Unsigned sz, bitsz, bitoff, maxsz=0;
        Dwarf_Die mem;
        mlist_t *ml, **mlastp;
        iidesc_t *ii;
@@ -933,6 +944,8 @@
                        ml->ml_name = NULL;
 
                ml->ml_type = die_lookup_pass1(dw, mem, DW_AT_type);
+               debug(3, "die_sou_create(): ml_type = %p t_id = %d\n", ml->ml_type,
+                       ml->ml_type->t_id);
 
                if (die_mem_offset(dw, mem, DW_AT_data_member_location,
                    &mloff, 0)) {
@@ -960,8 +973,21 @@
 
                *mlastp = ml;
                mlastp = &ml->ml_next;
+
+               /* work out the size of the largest member to work around a gcc bug */
+               if (maxsz < ml->ml_size) {
+                   maxsz = ml->ml_size;
+               }
        } while ((mem = die_sibling(dw, mem)) != NULL);
 
+       /* See if we got a bogus DW_AT_byte_size.  GCC will sometimes
+        * emit this.
+        */
+       if (sz == 0xffffffff) {
+           printf("dwarf.c:%s() working around bogus DW_AT_byte_size = 0xffffffff\n", __func__);
+           tdp->t_size = maxsz / 8;    /* maxsz is in bits, t_size is bytes */
+       }
+
        /*
         * GCC will attempt to eliminate unused types, thus decreasing the
         * size of the emitted dwarf.  That is, if you declare a foo_t in your
@@ -1030,7 +1056,7 @@
        if (tdp->t_flags & TDESC_F_RESOLVED)
                return (1);
 
-       debug(3, "resolving sou %s\n", tdesc_name(tdp));
+       debug(3, "resolving sou %s [%d]\n", tdesc_name(tdp), tdp->t_id);
 
        for (ml = tdp->t_members; ml != NULL; ml = ml->ml_next) {
                if (ml->ml_size == 0) {
@@ -1383,6 +1409,12 @@
         */
        (void) die_unsigned(dw, base, DW_AT_byte_size, &sz, DW_ATTR_REQ);
 
+       /* Check for bogus gcc DW_AT_byte_size attribute */
+       if (sz == 0xffffffff) {
+           printf("dwarf.c:%s() working around bogus DW_AT_byte_size = 0xffffffff\n", __func__);
+           sz = 0;
+       }
+
        if (tdp->t_name == NULL)
                terminate("die %llu: base type without name\n", off);
 



Home | Main Index | Thread Index | Old Index