diff options
-rw-r--r-- | src/corruptionCheck.js | 61 | ||||
-rw-r--r-- | src/jsifier.js | 4 | ||||
-rw-r--r-- | src/settings.js | 10 | ||||
-rwxr-xr-x | tests/runner.py | 26 |
4 files changed, 101 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. diff --git a/tests/runner.py b/tests/runner.py index 0d44541e..aad97db9 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -7185,6 +7185,32 @@ def process(filename): ''' self.do_run(src, '''AD:-1,1''', build_ll_hook=self.do_autodebug) + def test_corruption(self): + Settings.CORRUPTION_CHECK = 1 + + src = r''' + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + int main(int argc, char **argv) { + int size = 1024*argc; + char *buffer = (char*)malloc(size); + #if CORRUPT + memset(buffer, argc, size+15); + #else + memset(buffer, argc, size); + #endif + for (int x = 0; x < size; x += argc*3) buffer[x] = x/3; + int ret = 0; + for (int x = 0; x < size; x++) ret += buffer[x]; + free(buffer); + printf("All ok, %d\n", ret); + } + ''' + + for corrupt in [1]: + self.do_run(src.replace('CORRUPT', str(corrupt)), 'Heap corruption detected!' if corrupt else 'All ok, 4209') + ### Integration tests def test_ccall(self): |