aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-02-17 17:49:19 +0100
committerAlon Zakai <alonzakai@gmail.com>2013-02-17 17:49:19 +0100
commitb3e9426b9775daf99210f337659a37876013d623 (patch)
tree0a3245a0e3b3c55c2097e0c9de56f953f17b3a7d /src
parentd9d2876b0b7370ff99c37483a5f6e97515499e81 (diff)
memory corruption checker
Diffstat (limited to 'src')
-rw-r--r--src/corruptionCheck.js61
-rw-r--r--src/jsifier.js4
-rw-r--r--src/settings.js10
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.