aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemscripten.py2
-rw-r--r--src/preamble.js8
-rw-r--r--tests/test_other.py32
-rw-r--r--tools/js-optimizer.js66
4 files changed, 78 insertions, 30 deletions
diff --git a/emscripten.py b/emscripten.py
index c8122cb9..c8fab3be 100755
--- a/emscripten.py
+++ b/emscripten.py
@@ -1003,7 +1003,7 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None,
basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in math_envs]
if settings['RESERVED_FUNCTION_POINTERS'] > 0: basic_funcs.append('jsCall')
- if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE']
+ if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_FT_MASK']
if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8']
if settings['ASSERTIONS']:
if settings['ASSERTIONS'] >= 2: import difflib
diff --git a/src/preamble.js b/src/preamble.js
index 89ab5026..5dd8ada1 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -207,6 +207,14 @@ function SAFE_HEAP_LOAD(dest, bytes, isFloat, unsigned) {
return ret;
}
+function SAFE_FT_MASK(value, mask) {
+ var ret = value & mask;
+ if (ret !== value) {
+ abort('Function table mask error: function pointer is ' + value + ' which is masked by ' + mask + ', the likely cause of this is that the function pointer is being called by the wrong type.');
+ }
+ return ret;
+}
+
#endif
#endif
diff --git a/tests/test_other.py b/tests/test_other.py
index cdea493a..e4d91ba6 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -2710,3 +2710,35 @@ int main()
assert os.path.exists('hello_world.o')
assert os.path.exists('hello_world.bc')
+ def test_bad_function_pointer_cast(self):
+ open('src.cpp', 'w').write(r'''
+#include <stdio.h>
+
+typedef int (*callback) (int, ...);
+
+int impl(int foo) {
+ printf("Hello, world.\n");
+ return 0;
+}
+
+int main() {
+ volatile callback f = (callback) impl;
+ f(0); /* This fails with or without additional arguments. */
+ return 0;
+}
+''')
+
+ for opts in [0, 1, 2]:
+ for safe in [0, 1]:
+ cmd = [PYTHON, EMCC, 'src.cpp', '-O' + str(opts), '-s', 'SAFE_HEAP=' + str(safe)]
+ print cmd
+ Popen(cmd).communicate()
+ output = run_js('a.out.js', stderr=PIPE, full_output=True)
+ if safe:
+ assert 'Function table mask error' in output, output
+ else:
+ if opts == 0:
+ assert 'Invalid function pointer called' in output, output
+ else:
+ assert 'abort()' in output, output
+
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 32c26c51..db85965d 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -4926,36 +4926,44 @@ function safeHeap(ast) {
}
}
} else if (type === 'sub') {
- var heap = node[1][1];
- if (heap[0] !== 'H') return;
- var ptr = fixPtr(node[2], heap);
- // SAFE_HEAP_LOAD(ptr, bytes, isFloat)
- switch (heap) {
- case 'HEAP8': {
- return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '0']]], ASM_INT);
- }
- case 'HEAPU8': {
- return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '1']]], ASM_INT);
- }
- case 'HEAP16': {
- return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '0']]], ASM_INT);
- }
- case 'HEAPU16': {
- return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '1']]], ASM_INT);
- }
- case 'HEAP32': {
- return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '0']]], ASM_INT);
- }
- case 'HEAPU32': {
- return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '1']]], ASM_INT);
- }
- case 'HEAPF32': {
- return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '1'], ['num', '0']]], ASM_DOUBLE);
- }
- case 'HEAPF64': {
- return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 8], ['num', '1'], ['num', '0']]], ASM_DOUBLE);
+ var target = node[1][1];
+ if (target[0] === 'H') {
+ // heap access
+ var heap = target;
+ var ptr = fixPtr(node[2], heap);
+ // SAFE_HEAP_LOAD(ptr, bytes, isFloat)
+ switch (heap) {
+ case 'HEAP8': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '0']]], ASM_INT);
+ }
+ case 'HEAPU8': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '1']]], ASM_INT);
+ }
+ case 'HEAP16': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '0']]], ASM_INT);
+ }
+ case 'HEAPU16': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '1']]], ASM_INT);
+ }
+ case 'HEAP32': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '0']]], ASM_INT);
+ }
+ case 'HEAPU32': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '1']]], ASM_INT);
+ }
+ case 'HEAPF32': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '1'], ['num', '0']]], ASM_DOUBLE);
+ }
+ case 'HEAPF64': {
+ return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 8], ['num', '1'], ['num', '0']]], ASM_DOUBLE);
+ }
+ default: throw 'bad heap ' + heap;
}
- default: throw 'bad heap ' + heap;
+ } else {
+ assert(target[0] == 'F');
+ // function table indexing mask
+ assert(node[2][0] === 'binary' && node[2][1] === '&');
+ node[2][2] = makeAsmCoercion(['call', ['name', 'SAFE_FT_MASK'], [makeAsmCoercion(node[2][2], ASM_INT), makeAsmCoercion(node[2][3], ASM_INT)]], ASM_INT);
}
}
});