aboutsummaryrefslogtreecommitdiff
path: root/tests/runner.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/runner.py')
-rwxr-xr-xtests/runner.py935
1 files changed, 788 insertions, 147 deletions
diff --git a/tests/runner.py b/tests/runner.py
index b6980933..1f40d69c 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -100,14 +100,8 @@ class RunnerCore(unittest.TestCase):
for temp_file in os.listdir(TEMP_DIR):
if temp_file.endswith('.ll'):
self.has_prev_ll = True
-
+
def tearDown(self):
- if self.save_JS:
- for name in os.listdir(self.get_dir()):
- if name.endswith(('.o.js', '.cc.js')):
- suff = '.'.join(name.split('.')[-2:])
- shutil.copy(os.path.join(self.get_dir(), name),
- os.path.join(TEMP_DIR, self.id().replace('__main__.', '').replace('.test_', '.')+'.'+suff))
if not self.save_dir:
# rmtree() fails on Windows if the current working directory is inside the tree.
os.chdir(os.path.join(self.get_dir(), '..'))
@@ -140,6 +134,12 @@ class RunnerCore(unittest.TestCase):
def get_stdout_path(self):
return os.path.join(self.get_dir(), 'stdout')
+ def hardcode_arguments(self, filename, args):
+ # Hardcode in the arguments, so js is portable without manual commandlinearguments
+ if not args: return
+ js = open(filename).read()
+ open(filename, 'w').write(js.replace('var ret = run();', 'var ret = run(%s);' % str(args)))
+
def prep_ll_run(self, filename, ll_file, force_recompile=False, build_ll_hook=None):
if ll_file.endswith(('.bc', '.o')):
if ll_file != filename + '.o':
@@ -435,6 +435,8 @@ process(sys.argv[1])
sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv)
+test_index = 0
+
if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'browser' not in str(sys.argv):
# Tests
@@ -448,29 +450,35 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows
class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline
## Does a complete test - builds, runs, checks output, etc.
def do_run(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]):
- if force_c or (main_file is not None and main_file[-2:]) == '.c':
- basename = 'src.c'
- Building.COMPILER = to_cc(Building.COMPILER)
-
- dirname = self.get_dir()
- filename = os.path.join(dirname, basename)
- if not no_build:
- self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes,
- build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args, post_build=post_build)
-
- # Run in both JavaScript engines, if optimizing - significant differences there (typed arrays)
- if js_engines is None:
- js_engines = JS_ENGINES
- if Settings.USE_TYPED_ARRAYS:
- js_engines = filter(lambda engine: engine != V8_ENGINE, js_engines) # V8 issue 1822
- js_engines = filter(lambda engine: engine not in self.banned_js_engines, js_engines)
- if len(js_engines) == 0: return self.skip('No JS engine present to run this test with. Check %s and the paths therein.' % EM_CONFIG)
- for engine in js_engines:
- js_output = self.run_generated_code(engine, filename + '.o.js', args, output_nicerizer=output_nicerizer)
- self.assertContained(expected_output, js_output.replace('\r\n', '\n'))
- self.assertNotContained('ERROR', js_output)
-
- #shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging
+ if force_c or (main_file is not None and main_file[-2:]) == '.c':
+ basename = 'src.c'
+ Building.COMPILER = to_cc(Building.COMPILER)
+
+ dirname = self.get_dir()
+ filename = os.path.join(dirname, basename)
+ if not no_build:
+ self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes,
+ build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args, post_build=post_build)
+
+ # Run in both JavaScript engines, if optimizing - significant differences there (typed arrays)
+ if js_engines is None:
+ js_engines = JS_ENGINES
+ if Settings.USE_TYPED_ARRAYS:
+ js_engines = filter(lambda engine: engine != V8_ENGINE, js_engines) # V8 issue 1822
+ js_engines = filter(lambda engine: engine not in self.banned_js_engines, js_engines)
+ if len(js_engines) == 0: return self.skip('No JS engine present to run this test with. Check %s and the paths therein.' % EM_CONFIG)
+ for engine in js_engines:
+ js_output = self.run_generated_code(engine, filename + '.o.js', args, output_nicerizer=output_nicerizer)
+ self.assertContained(expected_output, js_output.replace('\r\n', '\n'))
+ self.assertNotContained('ERROR', js_output)
+
+ #shutil.rmtree(dirname) # TODO: leave no trace in memory. But for now nice for debugging
+
+ if self.save_JS:
+ global test_index
+ self.hardcode_arguments(filename + '.o.js', args)
+ shutil.copyfile(filename + '.o.js', os.path.join(TEMP_DIR, str(test_index) + '.js'))
+ test_index += 1
# No building - just process an existing .ll file (or .bc, which we turn into .ll)
def do_ll_run(self, ll_file, expected_output=None, args=[], js_engines=None, output_nicerizer=None, post_build=None, force_recompile=False, build_ll_hook=None, extra_emscripten_args=[]):
@@ -499,6 +507,8 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv) and 'brows
'''
self.do_run(src, 'hello, world!')
+ assert 'EMSCRIPTEN_GENERATED_FUNCTIONS' not in open(self.in_dir('src.cpp.o.js')).read(), 'must not emit this unneeded internal thing'
+
def test_intvars(self):
if self.emcc_args == None: return self.skip('needs ta2')
@@ -1044,6 +1054,19 @@ m_divisor is 1091269979
}
''', 'c = 4ca38a6bd2973f97')
+ def test_i64_llabs(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
+ Settings.PRECISE_I64_MATH = 2
+ self.do_run(r'''
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int main(int argc, char ** argv) {
+ printf("%lld,%lld\n", llabs(-576460752303423489), llabs(576460752303423489));
+ return 0;
+ }
+ ''', '576460752303423489,576460752303423489')
+
def test_i64_zextneg(self):
if Settings.USE_TYPED_ARRAYS != 2: return self.skip('full i64 stuff only in ta2')
@@ -1131,7 +1154,6 @@ m_divisor is 1091269979
def test_i32_mul_precise(self):
if self.emcc_args == None: return self.skip('needs ta2')
- self.emcc_args += ['-s', 'PRECISE_I32_MUL=1']
src = r'''
#include <stdio.h>
@@ -1146,6 +1168,10 @@ m_divisor is 1091269979
self.do_run(src, '3217489085')
def test_i32_mul_semiprecise(self):
+ if Settings.ASM_JS: return self.skip('asm is always fully precise')
+
+ Settings.PRECISE_I32_MUL = 0 # we want semiprecise here
+
src = r'''
#include <stdio.h>
@@ -1227,6 +1253,8 @@ m_divisor is 1091269979
extern int64_t llvm_ctlz_i64(int64_t x);
extern int32_t llvm_cttz_i32(int32_t x);
extern int64_t llvm_cttz_i64(int64_t x);
+ extern int32_t llvm_ctpop_i32(int32_t x);
+ extern int64_t llvm_ctpop_i64(int64_t x);
extern int llvm_expect_i32(int x, int y);
}
@@ -1243,6 +1271,7 @@ m_divisor is 1091269979
printf("%d,%d\n", (int)llvm_ctlz_i64(((int64_t)1) << 40), llvm_ctlz_i32(1<<10));
printf("%d,%d\n", (int)llvm_cttz_i64(((int64_t)1) << 40), llvm_cttz_i32(1<<10));
+ printf("%d,%d\n", (int)llvm_ctpop_i64((0x3101ULL << 32) | 1), llvm_ctpop_i32(0x3101));
printf("%d\n", llvm_expect_i32(x % 27, 3));
@@ -1259,6 +1288,7 @@ c8,ef
c5,de,15,8a
23,21
40,10
+5,4
13
72057594037927936
''')
@@ -1807,6 +1837,8 @@ Succeeded!
generated = open('src.cpp.o.js', 'r').read()
def test_stack(self):
+ Settings.INLINING_LIMIT = 50
+
src = '''
#include <stdio.h>
int test(int i) {
@@ -2457,12 +2489,15 @@ Exception execution path of first function! 1
'''
Settings.DISABLE_EXCEPTION_CATCHING = 0
+ if '-O2' in self.emcc_args:
+ self.emcc_args.pop() ; self.emcc_args.pop() # disable closure to work around a closure bug
self.do_run(src, 'Throw...Construct...Catched...Destruct...Throw...Construct...Copy...Catched...Destruct...Destruct...')
def test_white_list_exception(self):
if Settings.ASM_JS: return self.skip('no exceptions support in asm')
Settings.DISABLE_EXCEPTION_CATCHING = 2
Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"]
+ Settings.INLINING_LIMIT = 50 # otherwise it is inlined and not identified
src = '''
#include <stdio.h>
@@ -2495,8 +2530,6 @@ Exception execution path of first function! 1
def test_uncaught_exception(self):
if Settings.ASM_JS: return self.skip('no exceptions support in asm')
if self.emcc_args is None: return self.skip('no libcxx inclusion without emcc')
- if '-O2' in self.emcc_args:
- self.emcc_args += ['--closure', '1'] # Use closure here for some additional coverage
Settings.DISABLE_EXCEPTION_CATCHING = 0
@@ -2609,6 +2642,7 @@ Exiting setjmp function, level: 0, prev_jmp: -1
if self.emcc_args is None: return self.skip('requires emcc')
if Settings.ASM_JS: return self.skip('uses report_stack without exporting')
+ Settings.INLINING_LIMIT = 50
Settings.CATCH_EXIT_CODE = 1
src = r'''
@@ -2793,6 +2827,37 @@ Exiting setjmp function, level: 0, prev_jmp: -1
''' % addr
self.do_run(src, 'segmentation fault' if addr.isdigit() else 'marfoosh')
+ def test_safe_dyncalls(self):
+ if Settings.ASM_JS: return self.skip('asm does not support missing function stack traces')
+ if Settings.SAFE_HEAP: return self.skip('safe heap warning will appear instead')
+ if self.emcc_args is None: return self.skip('need libc')
+
+ Settings.SAFE_DYNCALLS = 1
+
+ for cond, body, work in [(True, True, False), (True, False, False), (False, True, True), (False, False, False)]:
+ print cond, body, work
+ src = r'''
+ #include <stdio.h>
+
+ struct Classey {
+ virtual void doIt() = 0;
+ };
+
+ struct D1 : Classey {
+ virtual void doIt() BODY;
+ };
+
+ int main(int argc, char **argv)
+ {
+ Classey *p = argc COND 100 ? new D1() : NULL;
+ printf("%p\n", p);
+ p->doIt();
+
+ return 0;
+ }
+ '''.replace('COND', '==' if cond else '!=').replace('BODY', r'{ printf("all good\n"); }' if body else '')
+ self.do_run(src, 'dyncall error: vi' if not work else 'all good')
+
def test_dynamic_cast(self):
if self.emcc_args is None: return self.skip('need libcxxabi')
@@ -2845,6 +2910,23 @@ Exiting setjmp function, level: 0, prev_jmp: -1
'''
self.do_run(src, 'a1: 0\na2: 0\na3: 1\nb1: 0\nb2: 1\nb3: 1\nc1: 1\nc2: 1\nc3: 1\n')
+ def test_dynamic_cast_2(self):
+ if self.emcc_args is None: return self.skip('need libcxxabi')
+
+ src = r'''
+ #include <stdio.h>
+ #include <typeinfo>
+
+ class Class {};
+
+ int main() {
+ const Class* dp = dynamic_cast<const Class*>(&typeid(Class));
+ // should return dp == NULL,
+ printf("pointer: %p\n", dp);
+ }
+ '''
+ self.do_run(src, "pointer: (nil)")
+
def test_funcptr(self):
src = '''
#include <stdio.h>
@@ -3008,6 +3090,8 @@ Exiting setjmp function, level: 0, prev_jmp: -1
def test_stack_varargs(self):
if self.emcc_args is None: return # too slow in other modes
+ Settings.INLINING_LIMIT = 50
+
# We should not blow up the stack with numerous varargs
src = r'''
#include <stdio.h>
@@ -3028,6 +3112,8 @@ Exiting setjmp function, level: 0, prev_jmp: -1
self.do_run(src, 'ok!')
def test_stack_void(self):
+ Settings.INLINING_LIMIT = 50
+
src = r'''
#include <stdio.h>
@@ -3742,6 +3828,8 @@ The current type of b is: 9
''')
def test_structbyval(self):
+ Settings.INLINING_LIMIT = 50
+
# part 1: make sure that normally, passing structs by value works
src = r'''
@@ -3966,8 +4054,19 @@ The current type of b is: 9
'''
self.do_run(src, '*0\n')
+ def test_time_c(self):
+ src = r'''
+ #include <time.h>
+ #include <stdio.h>
+
+ int main() {
+ time_t t = time(0);
+ printf("time: %s\n", ctime(&t));
+ }
+ '''
+ self.do_run(src, 'time: ') # compilation check, mainly
+
def test_intentional_fault(self):
- if Settings.ASM_JS: return self.skip('no throw support in asm')
# Some programs intentionally segfault themselves, we should compile that into a throw
src = r'''
int main () {
@@ -3975,7 +4074,7 @@ The current type of b is: 9
return 0;
}
'''
- self.do_run(src, 'fault on write to 0')
+ self.do_run(src, 'fault on write to 0' if not Settings.ASM_JS else 'Assertion: 0')
def test_trickystring(self):
src = r'''
@@ -4095,10 +4194,12 @@ The current type of b is: 9
'''
self.do_run(src, '*0.00,0.00,0.00*\n*0,77,0*\n*0,77,0*\n*0,77,0*')
- def test_memcpy(self):
+ def test_memcpy_memcmp(self):
src = '''
#include <stdio.h>
#include <string.h>
+ #include <assert.h>
+
#define MAXX 48
void reset(unsigned char *buffer) {
for (int i = 0; i < MAXX; i++) buffer[i] = i+1;
@@ -4119,6 +4220,20 @@ The current type of b is: 9
reset(buffer);
memcpy(buffer+i, buffer+j, k);
dump(buffer);
+ assert(memcmp(buffer+i, buffer+j, k) == 0);
+ buffer[i + k/2]++;
+ if (buffer[i + k/2] != 0) {
+ assert(memcmp(buffer+i, buffer+j, k) > 0);
+ } else {
+ assert(memcmp(buffer+i, buffer+j, k) < 0);
+ }
+ buffer[i + k/2]--;
+ buffer[j + k/2]++;
+ if (buffer[j + k/2] != 0) {
+ assert(memcmp(buffer+i, buffer+j, k) < 0);
+ } else {
+ assert(memcmp(buffer+i, buffer+j, k) > 0);
+ }
}
}
}
@@ -4155,6 +4270,139 @@ The current type of b is: 9
'''
self.do_run(src, 'ok.');
+ def test_getopt(self):
+ src = '''
+ #pragma clang diagnostic ignored "-Winvalid-pp-token"
+ #include <unistd.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ int
+ main(int argc, char *argv[])
+ {
+ int flags, opt;
+ int nsecs, tfnd;
+
+ nsecs = 0;
+ tfnd = 0;
+ flags = 0;
+ while ((opt = getopt(argc, argv, "nt:")) != -1) {
+ switch (opt) {
+ case 'n':
+ flags = 1;
+ break;
+ case 't':
+ nsecs = atoi(optarg);
+ tfnd = 1;
+ break;
+ default: /* '?' */
+ fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf("flags=%d; tfnd=%d; optind=%d\\n", flags, tfnd, optind);
+
+ if (optind >= argc) {
+ fprintf(stderr, "Expected argument after options\\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("name argument = %s\\n", argv[optind]);
+
+ /* Other code omitted */
+
+ exit(EXIT_SUCCESS);
+ }
+ '''
+ self.do_run(src, 'flags=1; tfnd=1; optind=4\nname argument = foobar', args=['-t', '12', '-n', 'foobar'])
+
+ def test_getopt_long(self):
+ src = '''
+ #pragma clang diagnostic ignored "-Winvalid-pp-token"
+ #pragma clang diagnostic ignored "-Wdeprecated-writable-strings"
+ #include <stdio.h> /* for printf */
+ #include <stdlib.h> /* for exit */
+ #include <getopt.h>
+
+ int
+ main(int argc, char **argv)
+ {
+ int c;
+ int digit_optind = 0;
+
+ while (1) {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"add", required_argument, 0, 0 },
+ {"append", no_argument, 0, 0 },
+ {"delete", required_argument, 0, 0 },
+ {"verbose", no_argument, 0, 0 },
+ {"create", required_argument, 0, 'c'},
+ {"file", required_argument, 0, 0 },
+ {0, 0, 0, 0 }
+ };
+
+ c = getopt_long(argc, argv, "abc:d:012",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ printf("option %s", long_options[option_index].name);
+ if (optarg)
+ printf(" with arg %s", optarg);
+ printf("\\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf("digits occur in two different argv-elements.\\n");
+ digit_optind = this_option_optind;
+ printf("option %c\\n", c);
+ break;
+
+ case 'a':
+ printf("option a\\n");
+ break;
+
+ case 'b':
+ printf("option b\\n");
+ break;
+
+ case 'c':
+ printf("option c with value '%s'\\n", optarg);
+ break;
+
+ case 'd':
+ printf("option d with value '%s'\\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf("?? getopt returned character code 0%o ??\\n", c);
+ }
+ }
+
+ if (optind < argc) {
+ printf("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf("%s ", argv[optind++]);
+ printf("\\n");
+ }
+
+ exit(EXIT_SUCCESS);
+ }
+ '''
+ self.do_run(src, 'option file with arg foobar\noption b', args=['--file', 'foobar', '-b'])
+
def test_memmove(self):
src = '''
#include <stdio.h>
@@ -4197,6 +4445,19 @@ The current type of b is: 9
'''
self.do_run(src, 'final: -403200.');
+ def test_memmove3(self):
+ src = '''
+ #include <stdio.h>
+ #include <string.h>
+ int main() {
+ char str[] = "memmove can be vvery useful....!";
+ memmove(str+15, str+16, 17);
+ puts(str);
+ return 0;
+ }
+ '''
+ self.do_run(src, 'memmove can be very useful....!')
+
def test_bsearch(self):
if Settings.QUANTUM_SIZE == 1: return self.skip('Test cannot work with q1')
@@ -4797,6 +5058,9 @@ def process(filename):
printf("%g\n", strtod(str, &endptr));
printf("%d\n", endptr - str);
printf("%g\n", strtod("84e+420", &endptr));
+
+ printf("%.12f\n", strtod("1.2345678900000000e+08", NULL));
+
return 0;
}
'''
@@ -4824,6 +5088,7 @@ def process(filename):
1.234e+57
10
inf
+ 123456789.000000000000
'''
self.do_run(src, re.sub(r'\n\s+', '\n', expected))
@@ -4976,6 +5241,22 @@ at function.:blag
}
'''
self.do_run(src, '22 : me and myself 25 1.34\n21 waka 95\n')
+
+ def test_perrar(self):
+ src = r'''
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <stdio.h>
+
+ int main( int argc, char** argv ){
+ int retval = open( "NonExistingFile", O_RDONLY );
+ if( retval == -1 )
+ perror( "Cannot open NonExistingFile" );
+ return 0;
+ }
+ '''
+ self.do_run(src, 'Cannot open NonExistingFile: No such file or directory\n')
def test_atoX(self):
if self.emcc_args is None: return self.skip('requires ta2')
@@ -5299,9 +5580,30 @@ Pass: 0.000012 0.000012''')
return(0);
}
'''
-
self.do_run(src, '3\nday 19, month Nov, year 2012');
+ def test_sscanf_5(self):
+ src = r'''
+ #include "stdio.h"
+
+ static const char *colors[] = {
+ " c black",
+ ". c #001100",
+ "X c #111100"
+ };
+
+ int main(){
+ unsigned char code;
+ char color[32];
+ int rcode;
+ for(int i = 0; i < 3; i++) {
+ rcode = sscanf(colors[i], "%c c %s", &code, color);
+ printf("%i, %c, %s\n", rcode, code, color);
+ }
+ }
+ '''
+ self.do_run(src, '2, , black\n2, ., #001100\n2, X, #111100');
+
def test_langinfo(self):
src = open(path_from_root('tests', 'langinfo', 'test.c'), 'r').read()
expected = open(path_from_root('tests', 'langinfo', 'output.txt'), 'r').read()
@@ -6283,6 +6585,53 @@ int main(int argc, char **argv) {
self.do_run(src, '789:123.46\n0:100.1')
+ def test_reinterpreted_ptrs(self):
+ if self.emcc_args is None: return self.skip('needs emcc and libc')
+
+ src = r'''
+#include <stdio.h>
+
+class Foo {
+private:
+ float bar;
+public:
+ int baz;
+
+ Foo(): bar(0), baz(4711) {};
+
+ int getBar() const;
+};
+
+int Foo::getBar() const {
+ return this->bar;
+};
+
+const Foo *magic1 = reinterpret_cast<Foo*>(0xDEAD111F);
+const Foo *magic2 = reinterpret_cast<Foo*>(0xDEAD888F);
+
+static void runTest() {
+
+ const Foo *a = new Foo();
+ const Foo *b = a;
+
+ if (a->getBar() == 0) {
+ if (a->baz == 4712)
+ b = magic1;
+ else
+ b = magic2;
+ }
+
+ printf("%s\n", (b == magic1 ? "magic1" : (b == magic2 ? "magic2" : "neither")));
+};
+
+extern "C" {
+ int main(int argc, char **argv) {
+ runTest();
+ }
+}
+'''
+ self.do_run(src, 'magic2')
+
def test_jansson(self):
return self.skip('currently broken')
@@ -6719,7 +7068,6 @@ void*:16
extra_emscripten_args=['-H', 'libc/fcntl.h,libc/sys/unistd.h,poll.h,libc/math.h,libc/langinfo.h,libc/time.h'])
def get_freetype(self):
- Settings.INIT_STACK = 1 # TODO: Investigate why this is necessary
return self.get_library('freetype',
os.path.join('objs', '.libs', 'libfreetype.a'))
@@ -6782,8 +7130,9 @@ def process(filename):
# gcc -O3 -I/home/alon/Dev/emscripten/tests/sqlite -ldl src.c
if self.emcc_args is None: return self.skip('Very slow without ta2, and we would also need to include dlmalloc manually without emcc')
if Settings.QUANTUM_SIZE == 1: return self.skip('TODO FIXME')
+ self.banned_js_engines = [NODE_JS] # OOM in older node
- Settings.CORRECT_SIGNS = 1 # XXX: in default, we fail with 2 here, even though the pgo_data should be correct (and works in s_0_0). Investigate this.
+ Settings.CORRECT_SIGNS = 1
Settings.CORRECT_OVERFLOWS = 0
Settings.CORRECT_ROUNDINGS = 0
if self.emcc_args is None: Settings.SAFE_HEAP = 0 # uses time.h to set random bytes, other stuff
@@ -6827,7 +7176,8 @@ def process(filename):
self.do_run(open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(),
[open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings
- open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read()],
+ open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read(),
+ open(path_from_root('tests', 'bullet', 'output3.txt'), 'r').read()],
libraries=self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletDynamics.a'),
os.path.join('src', '.libs', 'libBulletCollision.a'),
os.path.join('src', '.libs', 'libLinearMath.a')],
@@ -6918,7 +7268,6 @@ def process(filename):
[os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/index.c.o'.split('/')),
os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/convert.c.o'.split('/')),
os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/color.c.o'.split('/')),
- os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/getopt.c.o'.split('/')),
os.path.join('bin', self.get_shared_library_name('libopenjpeg.so.1.4.0'))],
configure=['cmake', '.'],
#configure_args=['--enable-tiff=no', '--enable-jp3d=no', '--enable-png=no'],
@@ -6995,6 +7344,14 @@ def process(filename):
self.assertIdentical(clean(open('release.js').read()), clean(open('debug%d.js' % debug).read())) # EMCC_DEBUG=1 mode must not generate different code!
print >> sys.stderr, 'debug check %d passed too' % debug
+ try:
+ os.environ['EMCC_FORCE_STDLIBS'] = '1'
+ print 'EMCC_FORCE_STDLIBS'
+ do_test()
+ finally:
+ del os.environ['EMCC_FORCE_STDLIBS']
+ print >> sys.stderr, 'EMCC_FORCE_STDLIBS ok'
+
try_delete(CANONICAL_TEMP_DIR)
else:
print >> sys.stderr, 'not doing debug check'
@@ -7062,6 +7419,24 @@ def process(filename):
finally:
del os.environ['EMCC_LEAVE_INPUTS_RAW']
+ def test_fuzz(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2')
+
+ Building.COMPILER_TEST_OPTS += ['-I' + path_from_root('tests', 'fuzz')]
+
+ def run_all(x):
+ print x
+ for name in glob.glob(path_from_root('tests', 'fuzz', '*.c')):
+ print name
+ self.do_run(open(path_from_root('tests', 'fuzz', name)).read(),
+ open(path_from_root('tests', 'fuzz', name + '.txt')).read(), force_c=True)
+
+ run_all('normal')
+
+ self.emcc_args += ['--llvm-lto', '1']
+
+ run_all('lto')
+
# Autodebug the code
def do_autodebug(self, filename):
output = Popen([PYTHON, AUTODEBUGGER, filename+'.o.ll', filename+'.o.ll.ll'], stdout=PIPE, stderr=self.stderr_redirect).communicate()[0]
@@ -7113,40 +7488,101 @@ def process(filename):
'''
self.do_run(src, '''AD:-1,1''', build_ll_hook=self.do_autodebug)
- def test_profiling(self):
- if Settings.ASM_JS: return self.skip('asm does not support profiling')
+ def test_corruption(self):
+ if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
- src = '''
- #include <emscripten.h>
- #include <unistd.h>
+ Settings.CORRUPTION_CHECK = 1
- int main()
+ 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')
+
+ def test_corruption_2(self):
+ if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
+
+ Settings.SAFE_HEAP = 1
+ Settings.CORRUPTION_CHECK = 1
+
+ # test for free(0), malloc(0), etc.
+ src = r'''
+ #include <iostream>
+ #include <fstream>
+ #include <stdlib.h>
+ #include <stdio.h>
+
+ void bye() {
+ printf("all ok\n");
+ }
+
+ int main() {
+ atexit(bye);
+
+ std::string testPath = "/Script/WA-KA.txt";
+ std::fstream str(testPath.c_str(), std::ios::in | std::ios::binary);
+
+ if (str.is_open())
{
- EMSCRIPTEN_PROFILE_INIT(3);
- EMSCRIPTEN_PROFILE_BEGIN(0);
- usleep(10 * 1000);
- EMSCRIPTEN_PROFILE_END(0);
- EMSCRIPTEN_PROFILE_BEGIN(1);
- usleep(50 * 1000);
- EMSCRIPTEN_PROFILE_END(1);
- EMSCRIPTEN_PROFILE_BEGIN(2);
- usleep(250 * 1000);
- EMSCRIPTEN_PROFILE_END(2);
- return 0;
+ std::cout << "open!" << std::endl;
+ } else {
+ std::cout << "missing!" << std::endl;
}
+
+ return 1;
+ }
'''
+ self.do_run(src, 'missing!\nall ok\n')
- post1 = '''
-def process(filename):
- src = open(filename, 'a')
- src.write(\'\'\'
- Profiling.dump();
- \'\'\')
- src.close()
-'''
+ def test_corruption_3(self):
+ if Settings.ASM_JS: return self.skip('cannot use corruption checks in asm')
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('needs ta2 for actual test')
- self.do_run(src, '''Profiling data:
-Block 0: ''', post_build=post1)
+ Settings.CORRUPTION_CHECK = 1
+
+ # realloc
+ src = r'''
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <assert.h>
+
+ void bye() {
+ printf("all ok\n");
+ }
+
+ int main(int argc, char **argv) {
+ atexit(bye);
+
+ char *buffer = (char*)malloc(100);
+ for (int i = 0; i < 100; i++) buffer[i] = (i*i)%256;
+ buffer = (char*)realloc(buffer, argc + 50);
+ for (int i = 0; i < argc + 50; i++) {
+ //printf("%d : %d : %d : %d\n", i, (int)(buffer + i), buffer[i], (char)((i*i)%256));
+ assert(buffer[i] == (char)((i*i)%256));
+ }
+ return 1;
+ }
+ '''
+ self.do_run(src, 'all ok\n')
### Integration tests
@@ -7676,6 +8112,8 @@ def process(filename):
def test_debug(self):
if '-g' not in Building.COMPILER_TEST_OPTS: Building.COMPILER_TEST_OPTS.append('-g')
+ if self.emcc_args is not None:
+ if '-O1' in self.emcc_args or '-O2' in self.emcc_args: return self.skip('optimizations remove LLVM debug info')
src = '''
#include <stdio.h>
@@ -8051,17 +8489,14 @@ class %s(T):
Settings.ASSERTIONS = 1-embetter
Settings.SAFE_HEAP = 1-(embetter and llvm_opts)
Building.LLVM_OPTS = llvm_opts
- Settings.PGO = 0
Settings.CHECK_OVERFLOWS = 1-(embetter or llvm_opts)
Settings.CORRECT_OVERFLOWS = 1-(embetter and llvm_opts)
Settings.CORRECT_SIGNS = 0
Settings.CORRECT_ROUNDINGS = 0
Settings.CORRECT_OVERFLOWS_LINES = CORRECT_SIGNS_LINES = CORRECT_ROUNDINGS_LINES = SAFE_HEAP_LINES = []
Settings.CHECK_SIGNS = 0 #1-(embetter or llvm_opts)
- Settings.INIT_STACK = 0
Settings.RUNTIME_TYPE_INFO = 0
Settings.DISABLE_EXCEPTION_CATCHING = 0
- Settings.PROFILE = 0
Settings.INCLUDE_FULL_LIBRARY = 0
Settings.BUILD_AS_SHARED_LIB = 0
Settings.RUNTIME_LINKED_LIBS = []
@@ -8084,11 +8519,11 @@ TT = %s
exec('o1 = make_run("o1", compiler=CLANG, emcc_args=["-O1", "-s", "SAFE_HEAP=1"])')
# Make one run with -O2, but without closure (we enable closure in specific tests, otherwise on everything it is too slow)
- exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2", "--closure", "0"])')
+ exec('o2 = make_run("o2", compiler=CLANG, emcc_args=["-O2"])')
# asm.js
- #exec('asm = make_run("asm", compiler=CLANG, emcc_args=["-O0", "--closure", "0", "-s", "ASM_JS=1"])')
- exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "--closure", "0", "-s", "ASM_JS=1"])')
+ #exec('asm = make_run("asm", compiler=CLANG, emcc_args=["-O0", "-s", "ASM_JS=1"])')
+ exec('asm2 = make_run("asm2", compiler=CLANG, emcc_args=["-O2", "-s", "ASM_JS=1"])')
# Make custom runs with various options
for compiler, quantum, embetter, typed_arrays, llvm_opts in [
@@ -8114,11 +8549,12 @@ TT = %s
# --version
output = Popen([PYTHON, compiler, '--version'], stdout=PIPE, stderr=PIPE).communicate()
- self.assertContained('''emcc (Emscripten GCC-like replacement) 2.0
-Copyright (C) 2012 the Emscripten authors.
+ output = output[0].replace('\r', '')
+ self.assertContained('''emcc (Emscripten GCC-like replacement)''', output)
+ self.assertContained('''Copyright (C) 2013 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-''', output[0].replace('\r', ''), output[1].replace('\r', ''))
+''', output)
# -v, without input files
output = Popen([PYTHON, compiler, '-v'], stdout=PIPE, stderr=PIPE).communicate()
@@ -8224,20 +8660,23 @@ Options that are modified or new in %s include:
(['-o', 'something.js', '-O0'], 0, None, 0, 0),
(['-o', 'something.js', '-O1'], 1, None, 0, 0),
(['-o', 'something.js', '-O1', '--closure', '1'], 1, None, 1, 0),
- (['-o', 'something.js', '-O2'], 2, None, 1, 1),
+ (['-o', 'something.js', '-O2'], 2, None, 0, 1),
(['-o', 'something.js', '-O2', '--closure', '0'], 2, None, 0, 0),
+ (['-o', 'something.js', '-O2', '-g'], 2, None, 0, 0),
+ (['-o', 'something.js', '-Os'], 2, None, 0, 1),
(['-o', 'something.js', '-O3'], 3, None, 1, 1),
(['-o', 'something.js', '-O3', '--closure', '0'], 3, None, 0, 0),
# and, test compiling to bitcode first
(['-o', 'something.bc'], 0, [], 0, 0),
(['-o', 'something.bc'], 0, ['-O0'], 0, 0),
(['-o', 'something.bc'], 1, ['-O1'], 0, 0),
- (['-o', 'something.bc'], 2, ['-O2'], 1, 0),
+ (['-o', 'something.bc'], 2, ['-O2'], 0, 0),
(['-o', 'something.bc'], 3, ['-O3'], 1, 0),
(['-O1', '-o', 'something.bc'], 0, [], 0, 0), # -Ox is ignored and warned about
]:
- #print params, opt_level, bc_params, closure
+ print params, opt_level, bc_params, closure, has_malloc
self.clear()
+ keep_debug = '-g' in params
output = Popen([PYTHON, compiler, path_from_root('tests', 'hello_world_loop' + ('_malloc' if has_malloc else '') + '.cpp')] + params,
stdout=PIPE, stderr=PIPE).communicate()
assert len(output[0]) == 0, output[0]
@@ -8261,21 +8700,22 @@ Options that are modified or new in %s include:
else:
# closure has not been run, we can do some additional checks. TODO: figure out how to do these even with closure
assert 'Module._main = ' not in generated, 'closure compiler should not have been run'
- # XXX find a way to test this: assert ('& 255' in generated or '&255' in generated) == (opt_level <= 2), 'corrections should be in opt <= 2'
- assert ('(label)' in generated) == (opt_level <= 1), 'relooping should be in opt >= 2'
- assert ('assert(STACKTOP < STACK_MAX' in generated) == (opt_level == 0), 'assertions should be in opt == 0'
- assert 'var $i;' in generated or 'var $i_0' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated, 'micro opts should always be on'
+ if keep_debug:
+ assert ('(label)' in generated) == (opt_level <= 1), 'relooping should be in opt >= 2'
+ assert ('assert(STACKTOP < STACK_MAX' in generated) == (opt_level == 0), 'assertions should be in opt == 0'
+ assert 'var $i;' in generated or 'var $i_0' in generated or 'var $storemerge3;' in generated or 'var $storemerge4;' in generated or 'var $i_04;' in generated, 'micro opts should always be on'
if opt_level >= 2:
- assert re.search('HEAP8\[\$