diff options
author | Alon Zakai <alonzakai@gmail.com> | 2013-02-17 17:49:19 +0100 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2013-02-17 17:49:19 +0100 |
commit | b3e9426b9775daf99210f337659a37876013d623 (patch) | |
tree | 0a3245a0e3b3c55c2097e0c9de56f953f17b3a7d /src | |
parent | d9d2876b0b7370ff99c37483a5f6e97515499e81 (diff) |
memory corruption checker
Diffstat (limited to 'src')
-rw-r--r-- | src/corruptionCheck.js | 61 | ||||
-rw-r--r-- | src/jsifier.js | 4 | ||||
-rw-r--r-- | src/settings.js | 10 |
3 files changed, 75 insertions, 0 deletions
diff --git a/src/corruptionCheck.js b/src/corruptionCheck.js new file mode 100644 index 00000000..0616337b --- /dev/null +++ b/src/corruptionCheck.js @@ -0,0 +1,61 @@ + +// See settings.js, CORRUPTION_CHECK + +var CorruptionChecker = { + BUFFER_FACTOR: {{{ CORRUPTION_CHECK }}}, + + ptrs: {}, + + init: function() { + this.realMalloc = _malloc; + _malloc = Module['_malloc'] = this.malloc; + + this.realFree = _free; + _free = Module['_free'] = this.free; + }, + malloc: function(size) { + assert(size > 0); // some mallocs accept zero - fix your code if you want to use this tool + var allocation = CorruptionChecker.realMalloc(size*(1+2*CorruptionChecker.BUFFER_FACTOR)); + var ptr = allocation + size*CorruptionChecker.BUFFER_FACTOR; + assert(!CorruptionChecker.ptrs[ptr]); + CorruptionChecker.ptrs[ptr] = size; + CorruptionChecker.fillBuffer(allocation, size*CorruptionChecker.BUFFER_FACTOR); + CorruptionChecker.fillBuffer(allocation + size*(1+CorruptionChecker.BUFFER_FACTOR), size*CorruptionChecker.BUFFER_FACTOR); + return ptr; + }, + free: function(ptr) { + CorruptionChecker.checkPtr(ptr, true); + }, + canary: function(x) { + return (x + (x << 3) + (x&75) - (x&47))&255; + }, + fillBuffer: function(allocation, size) { + for (var x = allocation; x < allocation + size; x++) { + {{{ makeSetValue('x', 0, 'CorruptionChecker.canary(x)', 'i8') }}}; + } + }, + checkBuffer: function(allocation, size) { + for (var x = allocation; x < allocation + size; x++) { + assert(({{{ makeGetValue('x', 0, 'i8') }}}&255) == CorruptionChecker.canary(x), 'Heap corruption detected!'); + } + }, + checkPtr: function(ptr, free) { + var size = CorruptionChecker.ptrs[ptr]; + assert(size); + var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR; + CorruptionChecker.checkBuffer(allocation, size*CorruptionChecker.BUFFER_FACTOR); + CorruptionChecker.checkBuffer(allocation + size*(1+CorruptionChecker.BUFFER_FACTOR), size*CorruptionChecker.BUFFER_FACTOR); + if (free) { + delete CorruptionChecker.ptrs[ptr]; + CorruptionChecker.realFree(allocation); + } + }, + checkAll: function() { + for (var ptr in CorruptionChecker.ptrs) { + CorruptionChecker.checkPtr(ptr, false); + } + }, +}; + +CorruptionChecker.init(); + diff --git a/src/jsifier.js b/src/jsifier.js index 9fbcf5a8..21d34b67 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -1532,6 +1532,10 @@ function JSify(data, functionsOnly, givenFunctions) { // This is the main 'post' pass. Print out the generated code that we have here, together with the // rest of the output that we started to print out earlier (see comment on the // "Final shape that will be created"). + if (CORRUPTION_CHECK) { + assert(!ASM_JS); // cannot monkeypatch asm! + print(processMacros(read('corruptionCheck.js'))); + } if (PRECISE_I64_MATH && Types.preciseI64MathUsed) { print(read('long.js')); } else { diff --git a/src/settings.js b/src/settings.js index 002e66d4..74176914 100644 --- a/src/settings.js +++ b/src/settings.js @@ -134,6 +134,16 @@ var SAFE_HEAP_LOG = 0; // Log out all SAFE_HEAP operations var ASM_HEAP_LOG = 0; // Simple heap logging, like SAFE_HEAP_LOG but cheaper, and in asm.js +var CORRUPTION_CHECK = 0; // When enabled, will emit a buffer area at the beginning and + // end of each allocation on the heap, filled with canary + // values that can be checked later. Corruption is checked for + // at the end of each at each free() (see jsifier to add more, and you + // can add more manual checks by calling CorruptionChecker.checkAll). + // 0 means not enabled, higher values mean the size of the + // buffer areas as a multiple of the allocated area (so + // 1 means 100%, or buffer areas equal to allocated area, + // both before and after). + var LABEL_DEBUG = 0; // 1: Print out functions as we enter them // 2: Also print out each label as we enter it var LABEL_FUNCTION_FILTERS = []; // Filters for function label debug. |