aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/corruptionCheck.js61
-rw-r--r--src/jsifier.js4
-rw-r--r--src/settings.js10
-rwxr-xr-xtests/runner.py26
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):