aboutsummaryrefslogtreecommitdiff
path: root/src/corruptionCheck.js
blob: d676c290fb5a7acda84b690f06be72d2b79b27d5 (plain)
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
// See settings.js, CORRUPTION_CHECK

var CorruptionChecker = {
  BUFFER_FACTOR: Math.round({{{ CORRUPTION_CHECK }}}),

  ptrs: {},
  checks: 0,

  init: function() {
    this.realMalloc = _malloc;
    _malloc = Module['_malloc'] = this.malloc;

    this.realFree = _free;
    _free = Module['_free'] = this.free;

    __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.print('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.print('free ' + ptr + ' of size ' + size);
    assert(size);
    var allocation = ptr - size*CorruptionChecker.BUFFER_FACTOR;
    //Module.print('free ' + ptr + ' of size ' + size + ' and allocation ' + allocation);
    delete CorruptionChecker.ptrs[ptr];
    CorruptionChecker.realFree(allocation);
  },
  canary: function(x) {
    return (x&127) + 10;
  },
  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!');
    }
    CorruptionChecker.checks++;
  },
  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() {
    for (var ptr in CorruptionChecker.ptrs) {
      CorruptionChecker.checkPtr(ptr, false);
    }
  },
};

CorruptionChecker.init();