shithub: jbig2

Download patch

ref: dc2f2769a366d34988472e9a088151a43851cf2f
parent: f5d16095a001e741bc8e570c0e231e65e831ea47
author: Sebastian Rasmussen <sebras@gmail.com>
date: Fri Feb 7 22:18:09 EST 2020

jbig2dec: Sync memento from ghostscript.

--- a/memento.c
+++ b/memento.c
@@ -45,6 +45,7 @@
 #ifndef _MSC_VER
 #include <stdint.h>
 #include <limits.h>
+#include <unistd.h>
 #endif
 
 #include <stdlib.h>
@@ -59,9 +60,11 @@
 #ifdef _MSC_VER
 #define FMTZ "%llu"
 #define FMTZ_CAST _int64
+#define FMTP "0x%p"
 #else
 #define FMTZ "%zu"
 #define FMTZ_CAST size_t
+#define FMTP "%p"
 #endif
 
 #define UB(x) ((intptr_t)((x) & 0xFF))
@@ -251,7 +254,8 @@
     Memento_Flag_BreakOnFree = 4,
     Memento_Flag_BreakOnRealloc = 8,
     Memento_Flag_Freed = 16,
-    Memento_Flag_KnownLeak = 32
+    Memento_Flag_KnownLeak = 32,
+    Memento_Flag_Reported = 64
 };
 
 enum {
@@ -535,8 +539,31 @@
 
 static void print_stack_libbt_failed(void *addr)
 {
-    char **strings = backtrace_symbols(&addr, 1);
+    char **strings;
+#if 0
+    /* Let's use a hack from Julian Smith to call gdb to extract the information */
+    /* Disabled for now, as I can't make this work. */
+    static char command[1024];
+    int e;
+    static int gdb_invocation_failed = 0;
 
+    if (gdb_invocation_failed == 0)
+    {
+        snprintf(command, sizeof(command),
+                 //"gdb -q --batch -p=%i -ex 'info line *%p' -ex quit 2>/dev/null",
+                 "gdb -q --batch -p=%i -ex 'info line *%p' -ex quit 2>/dev/null| egrep -v '(Thread debugging using)|(Using host libthread_db library)|(A debugging session is active)|(will be detached)|(Quit anyway)|(No such file or directory)|(^0x)|(^$)'",
+                 getpid(), addr);
+    printf("%s\n", command);
+        e = system(command);
+        if (e == 0)
+            return; /* That'll do! */
+        gdb_invocation_failed = 1; /* If it's failed once, it'll probably keep failing. */
+    }
+#endif
+
+    /* We couldn't even get gdb! Make do. */
+    strings = backtrace_symbols(&addr, 1);
+
     if (strings == NULL || strings[0] == NULL)
     {
         if (sizeof(void *) == 4)
@@ -553,6 +580,12 @@
 
 static int init_libbt(void)
 {
+    static int libbt_inited = 0;
+
+    if (libbt_inited)
+        return 0;
+    libbt_inited = 1;
+
     libbt = dlopen("libbacktrace.so", RTLD_LAZY);
     if (libbt == NULL)
         libbt = dlopen("/opt/lib/libbacktrace.so", RTLD_LAZY);
@@ -588,6 +621,9 @@
     return 1;
 
  fail:
+    fprintf(stderr,
+            "MEMENTO: libbacktrace.so failed to load; backtraces will be sparse.\n"
+            "MEMENTO: See memento.h for how to rectify this.\n");
     libbt = NULL;
     backtrace_create_state = NULL;
     backtrace_syminfo = NULL;
@@ -602,7 +638,7 @@
 
     if (strings == NULL || strings[0] == NULL)
     {
-        fprintf(stderr, "    [0x%p]\n", addr);
+        fprintf(stderr, "    ["FMTP"]\n", addr);
     }
 #ifdef HAVE_LIBDL
     else if (strchr(strings[0], ':') == NULL)
@@ -614,7 +650,7 @@
         {
             memcpy(backtrace_exe, strings[0], s - strings[0]);
             backtrace_exe[s-strings[0]] = 0;
-            if (init_libbt())
+            init_libbt();
                 print_stack_value(addr);
         }
     }
@@ -846,12 +882,12 @@
             const char *sym = info.dli_sname ? info.dli_sname : "<unknown>";
             char *demangled = __cxa_demangle(sym, NULL, 0, &status);
             int offset = stack[i] - info.dli_saddr;
-            fprintf(stderr, "    [%p]%s(+0x%x)\n", stack[i], demangled && status == 0 ? demangled : sym, offset);
+            fprintf(stderr, "    ["FMTP"]%s(+0x%x)\n", stack[i], demangled && status == 0 ? demangled : sym, offset);
             free(demangled);
         }
         else
         {
-            fprintf(stderr, "    [%p]\n", stack[i]);
+            fprintf(stderr, "    ["FMTP"]\n", stack[i]);
         }
     }
 }
@@ -1255,14 +1291,19 @@
 }
 #endif /* MEMENTO_LEAKONLY */
 
-static void showBlock(Memento_BlkHeader *b, int space)
+static int showBlock(Memento_BlkHeader *b, int space)
 {
-    fprintf(stderr, "0x%p:(size=" FMTZ ",num=%d)",
+    int seq;
+    VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader));
+    fprintf(stderr, FMTP":(size=" FMTZ ",num=%d)",
             MEMBLK_TOBLK(b), (FMTZ_CAST)b->rawsize, b->sequence);
     if (b->label)
         fprintf(stderr, "%c(%s)", space, b->label);
     if (b->flags & Memento_Flag_KnownLeak)
         fprintf(stderr, "(Known Leak)");
+    seq = b->sequence;
+    VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
+    return seq;
 }
 
 static void blockDisplay(Memento_BlkHeader *b, int n)
@@ -1291,7 +1332,9 @@
     size_t *counts = (size_t *)arg;
     blockDisplay(b, 0);
     counts[0]++;
+    VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader));
     counts[1]+= b->rawsize;
+    VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
     return 0;
 }
 
@@ -1300,15 +1343,19 @@
 {
     /* Try and avoid recursion if we can help it */
     do {
+        Memento_BlkHeader *c = NULL;
         blockDisplay(b, depth);
+        VALGRIND_MAKE_MEM_DEFINED(b, sizeof(Memento_BlkHeader));
         if (b->sibling) {
-            if (b->child)
-                doNestedDisplay(b->child, depth+1);
+            c = b->child;
             b = b->sibling;
         } else {
             b = b->child;
             depth++;
         }
+        VALGRIND_MAKE_MEM_NOACCESS(b, sizeof(Memento_BlkHeader));
+        if (c)
+            doNestedDisplay(c, depth+1);
     } while (b);
 }
 
@@ -1494,7 +1541,7 @@
 {
     Memento_BlkDetails *details;
 
-    fprintf(stderr, "0x%p:(size="FMTZ",num=%d)",
+    fprintf(stderr, FMTP":(size="FMTZ",num=%d)",
             MEMBLK_TOBLK(b), (FMTZ_CAST)b->rawsize, b->sequence);
     if (b->label)
         fprintf(stderr, " (%s)", b->label);
@@ -1526,9 +1573,15 @@
     Memento_BlkHeader *blk = memento.used.head;
     while (blk)
     {
-        if ((blk->flags & Memento_Flag_KnownLeak) == 0)
+        Memento_BlkHeader *next;
+        int leaked;
+        VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(*blk));
+        leaked = ((blk->flags & Memento_Flag_KnownLeak) == 0);
+        next = blk->next;
+        VALGRIND_MAKE_MEM_DEFINED(blk, sizeof(*blk));
+        if (leaked)
             return 1;
-        blk = blk->next;
+        blk = next;
     }
     return 0;
 }
@@ -1583,6 +1636,9 @@
     env = getenv("MEMENTO_FAILAT");
     memento.failAt = (env ? atoi(env) : 0);
 
+    env = getenv("MEMENTO_BREAKAT");
+    memento.breakAt = (env ? atoi(env) : 0);
+
     env = getenv("MEMENTO_PARANOIA");
     memento.paranoia = (env ? atoi(env) : 0);
     if (memento.paranoia == 0)
@@ -2347,7 +2403,11 @@
         }
         fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n",
                 memblk->lastCheckedOK, memento.sequence);
+        if ((memblk->flags & Memento_Flag_Reported) == 0)
+        {
+            memblk->flags |= Memento_Flag_Reported;
         Memento_breakpointLocked();
+        }
         return 1;
     }
 #endif
@@ -2394,7 +2454,11 @@
         }
         fprintf(stderr, "Block last checked OK at allocation %d. Now %d.\n",
                 memblk->lastCheckedOK, memento.sequence);
+        if ((memblk->flags & Memento_Flag_Reported) == 0)
+        {
+            memblk->flags |= Memento_Flag_Reported;
         Memento_breakpointLocked();
+        }
         return 1;
     }
 #endif
@@ -2585,6 +2649,11 @@
         data->preCorrupt  = 0;
         data->postCorrupt = 0;
         data->freeCorrupt = 0;
+        if ((memblk->flags & Memento_Flag_Reported) == 0)
+        {
+            memblk->flags |= Memento_Flag_Reported;
+            Memento_breakpointLocked();
+        }
     }
     else
         memblk->lastCheckedOK = memento.sequence;
@@ -2604,7 +2673,7 @@
         fprintf(stderr, "  ");
         showBlock(memblk, ' ');
         if (data->freeCorrupt) {
-            fprintf(stderr, " index %d (address 0x%p) onwards", (int)data->index,
+            fprintf(stderr, " index %d (address "FMTP") onwards", (int)data->index,
                     &((char *)MEMBLK_TOBLK(memblk))[data->index]);
             if (data->preCorrupt) {
                 fprintf(stderr, "+ preguard");
@@ -2621,9 +2690,16 @@
                         (data->preCorrupt ? "+" : ""));
             }
         }
+        VALGRIND_MAKE_MEM_DEFINED(memblk, sizeof(Memento_BlkHeader));
         fprintf(stderr, " corrupted.\n"
                 "    Block last checked OK at allocation %d. Now %d.\n",
                 memblk->lastCheckedOK, memento.sequence);
+        if ((memblk->flags & Memento_Flag_Reported) == 0)
+        {
+            memblk->flags |= Memento_Flag_Reported;
+            Memento_breakpointLocked();
+        }
+        VALGRIND_MAKE_MEM_NOACCESS(memblk, sizeof(Memento_BlkHeader));
         data->preCorrupt  = 0;
         data->postCorrupt = 0;
         data->freeCorrupt = 0;
@@ -2702,6 +2778,7 @@
 int Memento_find(void *a)
 {
     findBlkData data;
+    int s;
 
     MEMENTO_LOCK();
     data.addr  = a;
@@ -2709,27 +2786,27 @@
     data.flags = 0;
     Memento_appBlocks(&memento.used, Memento_containsAddr, &data);
     if (data.blk != NULL) {
-        fprintf(stderr, "Address 0x%p is in %sallocated block ",
+        fprintf(stderr, "Address "FMTP" is in %sallocated block ",
                 data.addr,
                 (data.flags == 1 ? "" : (data.flags == 2 ?
                                          "preguard of " : "postguard of ")));
-        showBlock(data.blk, ' ');
+        s = showBlock(data.blk, ' ');
         fprintf(stderr, "\n");
         MEMENTO_UNLOCK();
-        return data.blk->sequence;
+        return s;
     }
     data.blk   = NULL;
     data.flags = 0;
     Memento_appBlocks(&memento.free, Memento_containsAddr, &data);
     if (data.blk != NULL) {
-        fprintf(stderr, "Address 0x%p is in %sfreed block ",
+        fprintf(stderr, "Address "FMTP" is in %sfreed block ",
                 data.addr,
                 (data.flags == 1 ? "" : (data.flags == 2 ?
                                          "preguard of " : "postguard of ")));
-        showBlock(data.blk, ' ');
+        s = showBlock(data.blk, ' ');
         fprintf(stderr, "\n");
         MEMENTO_UNLOCK();
-        return data.blk->sequence;
+        return s;
     }
     MEMENTO_UNLOCK();
     return 0;
@@ -2745,13 +2822,15 @@
     data.flags = 0;
     Memento_appBlocks(&memento.used, Memento_containsAddr, &data);
     if (data.blk != NULL) {
-        fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ",
+        fprintf(stderr, "Will stop when address "FMTP" (in %sallocated block ",
                 data.addr,
                 (data.flags == 1 ? "" : (data.flags == 2 ?
                                          "preguard of " : "postguard of ")));
         showBlock(data.blk, ' ');
         fprintf(stderr, ") is freed\n");
+        VALGRIND_MAKE_MEM_DEFINED(data.blk, sizeof(Memento_BlkHeader));
         data.blk->flags |= Memento_Flag_BreakOnFree;
+        VALGRIND_MAKE_MEM_NOACCESS(data.blk, sizeof(Memento_BlkHeader));
         MEMENTO_UNLOCK();
         return;
     }
@@ -2759,7 +2838,7 @@
     data.flags = 0;
     Memento_appBlocks(&memento.free, Memento_containsAddr, &data);
     if (data.blk != NULL) {
-        fprintf(stderr, "Can't stop on free; address 0x%p is in %sfreed block ",
+        fprintf(stderr, "Can't stop on free; address "FMTP" is in %sfreed block ",
                 data.addr,
                 (data.flags == 1 ? "" : (data.flags == 2 ?
                                          "preguard of " : "postguard of ")));
@@ -2768,7 +2847,7 @@
         MEMENTO_UNLOCK();
         return;
     }
-    fprintf(stderr, "Can't stop on free; address 0x%p is not in a known block.\n", a);
+    fprintf(stderr, "Can't stop on free; address "FMTP" is not in a known block.\n", a);
     MEMENTO_UNLOCK();
 }
 
@@ -2782,13 +2861,15 @@
     data.flags = 0;
     Memento_appBlocks(&memento.used, Memento_containsAddr, &data);
     if (data.blk != NULL) {
-        fprintf(stderr, "Will stop when address 0x%p (in %sallocated block ",
+        fprintf(stderr, "Will stop when address "FMTP" (in %sallocated block ",
                 data.addr,
                 (data.flags == 1 ? "" : (data.flags == 2 ?
                                          "preguard of " : "postguard of ")));
         showBlock(data.blk, ' ');
         fprintf(stderr, ") is freed (or realloced)\n");
+        VALGRIND_MAKE_MEM_DEFINED(data.blk, sizeof(Memento_BlkHeader));
         data.blk->flags |= Memento_Flag_BreakOnFree | Memento_Flag_BreakOnRealloc;
+        VALGRIND_MAKE_MEM_NOACCESS(data.blk, sizeof(Memento_BlkHeader));
         MEMENTO_UNLOCK();
         return;
     }
@@ -2796,7 +2877,7 @@
     data.flags = 0;
     Memento_appBlocks(&memento.free, Memento_containsAddr, &data);
     if (data.blk != NULL) {
-        fprintf(stderr, "Can't stop on free/realloc; address 0x%p is in %sfreed block ",
+        fprintf(stderr, "Can't stop on free/realloc; address "FMTP" is in %sfreed block ",
                 data.addr,
                 (data.flags == 1 ? "" : (data.flags == 2 ?
                                          "preguard of " : "postguard of ")));
@@ -2805,7 +2886,7 @@
         MEMENTO_UNLOCK();
         return;
     }
-    fprintf(stderr, "Can't stop on free/realloc; address 0x%p is not in a known block.\n", a);
+    fprintf(stderr, "Can't stop on free/realloc; address "FMTP" is not in a known block.\n", a);
     MEMENTO_UNLOCK();
 }
 
@@ -2834,6 +2915,11 @@
     memento.leaking--;
 }
 
+int Memento_squeezing(void)
+{
+    return memento.squeezing;
+}
+
 #endif /* MEMENTO_CPP_EXTRAS_ONLY */
 
 #ifdef __cplusplus
@@ -3031,6 +3117,11 @@
 
 void (Memento_stopLeaking)(void)
 {
+}
+
+int (Memento_squeezing)(void)
+{
+    return 0;
 }
 
 #endif
--- a/memento.h
+++ b/memento.h
@@ -75,8 +75,7 @@
  * An example:
  *    Suppose we have a gs invocation that crashes with memory corruption.
  *     * Build with -DMEMENTO.
- *     * In your debugger put breakpoints on Memento_inited and
- *       Memento_Breakpoint.
+ *     * In your debugger put a breakpoint on Memento_breakpoint.
  *     * Run the program. It will stop in Memento_inited.
  *     * Execute Memento_setParanoia(1);  (In VS use Ctrl-Alt-Q). (Note #1)
  *     * Continue execution.
@@ -92,9 +91,9 @@
  *       and 1458 - so if we rerun and stop the program at 1457, we can then
  *       step through, possibly with a data breakpoint at 0x172e710 and see
  *       when it occurs.
- *     * So restart the program from the beginning. When we hit Memento_inited
- *       execute Memento_breakAt(1457); (and maybe Memento_setParanoia(1), or
- *       Memento_setParanoidAt(1457))
+ *     * So restart the program from the beginning. When we stop after
+ *       initialisation execute Memento_breakAt(1457); (and maybe
+ *       Memento_setParanoia(1), or Memento_setParanoidAt(1457))
  *     * Continue execution until we hit Memento_breakpoint.
  *     * Now you can step through and watch the memory corruption happen.
  *
@@ -157,6 +156,30 @@
  *    Both Windows and GCC provide separate new[] and delete[] operators
  *    for arrays. Apparently some systems do not. If this is the case for
  *    your system, define MEMENTO_CPP_NO_ARRAY_CONSTRUCTORS.
+ *
+ * "libbacktrace.so failed to load"
+ *
+ *    In order to give nice backtraces on unix, Memento will try to use
+ *    a libbacktrace dynamic library. If it can't find it, you'll see
+ *    that warning, and your backtraces won't include file/line information.
+ *
+ *    To fix this you'll need to build your own libbacktrace. Don't worry
+ *    it's really easy:
+ *       git clone git://github.com/ianlancetaylor/libbacktrace
+ *       cd libbacktrace
+ *       ./configure
+ *       make
+ *
+ *    This leaves the build .so as .libs/libbacktrace.so
+ *
+ *    Memento will look for this on LD_LIBRARY_PATH, or in /opt/lib/,
+ *    or in /lib/, or  in /usr/lib/, or in /usr/local/lib/. I recommend
+ *    using /opt/lib/ as this won't conflict with anything that you
+ *    get via a package manager like apt.
+ *
+ *       sudo mkdir /opt
+ *       sudo mkdir /opt/lib
+ *       sudo cp .libs/libbacktrace.so /opt/lib/
  */
 
 #ifndef MEMENTO_H
@@ -238,6 +261,8 @@
 
 int Memento_sequence(void);
 
+int Memento_squeezing(void);
+
 void Memento_fin(void);
 
 void Memento_bt(void);
@@ -299,6 +324,7 @@
 #define Memento_fin()                      do {} while (0)
 #define Memento_bt()                       do {} while (0)
 #define Memento_sequence()                 (0)
+#define Memento_squeezing()                (0)
 
 #endif /* MEMENTO */