1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
// See settings.js, CORRUPTION_CHECK
var CorruptionChecker = {
BUFFER_FACTOR: Math.round({{{ CORRUPTION_CHECK }}}),
ptrs: {},
checks: 0,
checkFrequency: 1,
init: function() {
this.realMalloc = _malloc;
_malloc = Module['_malloc'] = this.malloc;
this.realFree = _free;
_free = Module['_free'] = this.free;
if (typeof _realloc != 'undefined') {
this.realRealloc = _realloc;
_realloc = Module['_realloc'] = this.realloc;
}
__ATEXIT__.push({ func: function() {
Module.printErr('No corruption detected, ran ' + CorruptionChecker.checks + ' checks.');
} });
},
malloc: function(size) {
if (size <= 0) size = 1; // malloc(0) sometimes happens - just allocate a larger area, no harm
CorruptionChecker.checkAll();
size = (size+7)&(~7);
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);
//Module.printErr('malloc ' + size + ' ==> ' + [ptr, allocation]);
return ptr;
},
free: function(ptr) {
if (!ptr) return; // ok to free(NULL), does nothing
CorruptionChecker.checkAll();
var size = CorruptionChecker.ptrs[ptr];
//Module.printErr('free ' + ptr + ' of size ' + size);
assert(size);
var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR;
//Module.printErr('free ' + ptr + ' of size ' + size + ' and allocation ' + allocation);
delete CorruptionChecker.ptrs[ptr];
CorruptionChecker.realFree(allocation);
},
realloc: function(ptr, newSize) {
//Module.printErr('realloc ' + ptr + ' to size ' + newSize);
if (newSize <= 0) newSize = 1; // like in malloc
if (!ptr) return CorruptionChecker.malloc(newSize); // realloc(NULL, size) forwards to malloc according to the spec
var size = CorruptionChecker.ptrs[ptr];
assert(size);
var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR;
var newPtr = CorruptionChecker.malloc(newSize);
//Module.printErr('realloc ' + ptr + ' to size ' + newSize + ' is now ' + newPtr);
var newAllocation = newPtr + newSize*CorruptionChecker.BUFFER_FACTOR;
HEAPU8.set(HEAPU8.subarray(ptr, ptr + Math.min(size, newSize)), newPtr);
CorruptionChecker.free(ptr);
return newPtr;
},
canary: function(x) {
return (x&127) + 10;
},
fillBuffer: function(buffer, size) {
for (var x = buffer; x < buffer + size; x++) {
{{{ makeSetValue('x', 0, 'CorruptionChecker.canary(x)', 'i8') }}};
}
},
checkBuffer: function(buffer, size) {
for (var x = buffer; x < buffer + size; x++) {
if (({{{ makeGetValue('x', 0, 'i8') }}}&255) != CorruptionChecker.canary(x)) {
assert(0, 'Heap corruption detected!' + [x, buffer, size, {{{ makeGetValue('x', 0, 'i8') }}}&255, CorruptionChecker.canary(x)]);
}
}
},
checkPtr: function(ptr) {
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);
},
checkAll: function(force) {
CorruptionChecker.checks++;
if (!force && CorruptionChecker.checks % CorruptionChecker.checkFrequency != 0) return;
//Module.printErr('checking for corruption ' + (CorruptionChecker.checks/CorruptionChecker.checkFrequency));
for (var ptr in CorruptionChecker.ptrs) {
CorruptionChecker.checkPtr(ptr, false);
}
},
};
CorruptionChecker.init();
|