Bug 733493 - Improve JS shell OOM testing code, r=jorendorff
☠☠ backed out by 499b56d4809e ☠ ☠
authorChristian Holler <choller@mozilla.com>
Sat, 10 Mar 2012 11:50:26 -0800
changeset 91605 6169d8aa7a9d6db521d5e9d0cfb4e57590f46a7f
parent 91604 5bb28e57574930f35d3c56b06956fd85f1d1fd9e
child 91606 248590650201b5eb660e2d526682ef2f86718f06
push idunknown
push userunknown
push dateunknown
reviewersjorendorff
bugs733493
milestone13.0a1
Bug 733493 - Improve JS shell OOM testing code, r=jorendorff
js/public/Utility.h
js/src/configure.in
js/src/ds/LifoAlloc.h
js/src/jsgcinlines.h
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -40,16 +40,21 @@
 #ifndef js_utility_h__
 #define js_utility_h__
 
 #include "mozilla/Assertions.h"
 
 #include <stdlib.h>
 #include <string.h>
 
+#ifdef JS_OOM_DO_BACKTRACES
+#include <stdio.h>
+#include <execinfo.h>
+#endif
+
 #include "jstypes.h"
 
 #ifdef __cplusplus
 
 /* The public JS engine namespace. */
 namespace JS {}
 
 /* The mozilla-shared reusable template/utility namespace. */
@@ -107,20 +112,53 @@ extern JS_PUBLIC_API(void) JS_Abort(void
 #else
 # ifdef DEBUG
 /*
  * In order to test OOM conditions, when the shell command-line option
  * |-A NUM| is passed, we fail continuously after the NUM'th allocation.
  */
 extern JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations; /* set from shell/js.cpp */
 extern JS_PUBLIC_DATA(uint32_t) OOM_counter; /* data race, who cares. */
+
+#define JS_OOM_BACKTRACE_SIZE 32
+static JS_ALWAYS_INLINE void
+PrintBacktrace()
+{
+    void* OOM_trace[JS_OOM_BACKTRACE_SIZE];
+    char** OOM_traceSymbols = NULL;
+    int32_t OOM_traceSize = 0;
+    int32_t OOM_traceIdx = 0;
+    OOM_traceSize = backtrace(OOM_trace, JS_OOM_BACKTRACE_SIZE);
+    OOM_traceSymbols = backtrace_symbols(OOM_trace, OOM_traceSize);
+    
+    if (!OOM_traceSymbols)
+        return;
+
+    for (OOM_traceIdx = 0; OOM_traceIdx < OOM_traceSize; ++OOM_traceIdx) {
+        fprintf(stderr, "#%d %s\n", OOM_traceIdx, OOM_traceSymbols[OOM_traceIdx]);
+    }
+
+    free(OOM_traceSymbols);
+}
+
+#ifdef JS_OOM_DO_BACKTRACES
+#define JS_OOM_EMIT_BACKTRACE() \
+    do {\
+        fprintf(stderr, "Forcing artificial memory allocation function failure:\n");\
+	PrintBacktrace();\
+    } while (0)
+# else
+#  define JS_OOM_EMIT_BACKTRACE() do {} while(0)
+#endif /* JS_OOM_DO_BACKTRACES */
+
 #  define JS_OOM_POSSIBLY_FAIL() \
     do \
     { \
         if (++OOM_counter > OOM_maxAllocations) { \
+            JS_OOM_EMIT_BACKTRACE();\
             return NULL; \
         } \
     } while (0)
 
 # else
 #  define JS_OOM_POSSIBLY_FAIL() do {} while(0)
 # endif
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4522,16 +4522,28 @@ MOZ_ARG_ENABLE_BOOL(more-deterministic,
 [  --enable-more-deterministic
                           Enable changes that make the shell more deterministic],
     JS_MORE_DETERMINISTIC=1,
     JS_MORE_DETERMINISTIC= )
 if test -n "$JS_MORE_DETERMINISTIC"; then
     AC_DEFINE(JS_MORE_DETERMINISTIC)
 fi
 
+dnl ========================================================
+dnl Enable output of backtraces on artificial OOMs
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(oom-backtrace,
+[  --enable-oom-backtrace
+                          Enable output of backtraces on artificial OOMs (-A)],
+    JS_OOM_DO_BACKTRACES=1,
+    JS_OOM_DO_BACKTRACES= )
+if test -n "$JS_OOM_DO_BACKTRACES"; then
+    AC_DEFINE(JS_OOM_DO_BACKTRACES)
+fi
+
 dnl ======================================================
 dnl = Enable compiling with ccache
 dnl ======================================================
 MOZ_ARG_WITH_STRING(ccache,
 [  --with-ccache[=path/to/ccache]
                           Enable compiling with ccache],
     CCACHE=$withval, CCACHE="no")
 
--- a/js/src/ds/LifoAlloc.h
+++ b/js/src/ds/LifoAlloc.h
@@ -216,16 +216,18 @@ class LifoAlloc
     /* Frees all held memory. */
     void freeAll();
 
     /* Should be called on GC in order to release any held chunks. */
     void freeUnused();
 
     JS_ALWAYS_INLINE
     void *alloc(size_t n) {
+        JS_OOM_POSSIBLY_FAIL();
+
         void *result;
         if (latest && (result = latest->tryAlloc(n)))
             return result;
 
         if (!getOrCreateChunk(n))
             return NULL;
 
         return latest->allocInfallible(n);
--- a/js/src/jsgcinlines.h
+++ b/js/src/jsgcinlines.h
@@ -402,16 +402,19 @@ NewGCThing(JSContext *cx, js::gc::AllocK
     JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
 #ifdef JS_THREADSAFE
     JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
                  kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
 #endif
     JS_ASSERT(!cx->runtime->gcRunning);
     JS_ASSERT(!cx->runtime->noGCOrAllocationCheck);
 
+    /* For testing out of memory conditions */
+    JS_OOM_POSSIBLY_FAIL();
+
 #ifdef JS_GC_ZEAL
     if (cx->runtime->needZealousGC())
         js::gc::RunDebugGC(cx);
 #endif
 
     js::gc::MaybeCheckStackRoots(cx);
 
     JSCompartment *comp = cx->compartment;