aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/cases/entry3.ll36
-rw-r--r--tests/cases/entry3.txt2
-rw-r--r--tests/cases/i32_mem.ll23
-rw-r--r--tests/cases/i32_mem.txt2
-rw-r--r--tests/cases/sillyfuncast.ll23
-rw-r--r--tests/cases/sillyfuncast2.ll21
-rw-r--r--tests/cases/zeroembedded.ll23
-rw-r--r--tests/cases/zeroembedded.txt1
-rw-r--r--tests/embind/embind.test.js19
-rw-r--r--tests/embind/embind_test.cpp24
-rw-r--r--tests/glgetattachedshaders.c93
-rwxr-xr-xtests/runner.py548
-rw-r--r--tests/sdl_rotozoom.c3
-rw-r--r--tests/sdl_rotozoom.pngbin437956 -> 431921 bytes
-rw-r--r--tests/stat/output.txt202
-rw-r--r--tests/stat/src.c242
-rw-r--r--tests/stat/test_chmod.c153
-rw-r--r--tests/stat/test_mknod.c96
-rw-r--r--tests/stat/test_stat.c167
-rw-r--r--tests/unistd/unlink.c165
-rw-r--r--tests/unistd/unlink.js7
-rw-r--r--tests/unistd/unlink.out42
22 files changed, 1312 insertions, 580 deletions
diff --git a/tests/cases/entry3.ll b/tests/cases/entry3.ll
new file mode 100644
index 00000000..a20c6843
--- /dev/null
+++ b/tests/cases/entry3.ll
@@ -0,0 +1,36 @@
+; ModuleID = '/tmp/tmpKnA2D3/a.out.bc'
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
+target triple = "i386-pc-linux-gnu"
+
+@.str = private unnamed_addr constant [11 x i8] c"getgid=%d\0A\00", align 1
+@.str1 = private unnamed_addr constant [6 x i8] c"f=%d\0A\00", align 1
+
+define internal i32 @_Z1fii(i32, i32) noinline {
+entry:
+ %3 = tail call i32 @getgid()
+ %4 = icmp eq i32 %3, 0
+ br i1 %4, label %cond.b, label %cond.a
+
+cond.a:
+ %6 = tail call i32 @getgid()
+ br label %cond.end
+
+cond.b:
+ br label %cond.end
+
+cond.end:
+ %.0 = phi i32 [ 0, %cond.b ], [ 1, %1 ]
+ ret i32 %.0
+}
+
+declare i32 @getgid()
+
+define i32 @main() {
+ %1 = tail call i32 @getgid()
+ %2 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([11 x i8]* @.str, i32 0, i32 0), i32 %1)
+ %3 = tail call i32 @_Z1fii(i32 undef, i32 undef)
+ %4 = tail call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str1, i32 0, i32 0), i32 %3)
+ ret i32 0
+}
+
+declare i32 @printf(i8* nocapture, ...) nounwind
diff --git a/tests/cases/entry3.txt b/tests/cases/entry3.txt
new file mode 100644
index 00000000..4060fb06
--- /dev/null
+++ b/tests/cases/entry3.txt
@@ -0,0 +1,2 @@
+getgid=0
+f=0
diff --git a/tests/cases/i32_mem.ll b/tests/cases/i32_mem.ll
new file mode 100644
index 00000000..e50014ca
--- /dev/null
+++ b/tests/cases/i32_mem.ll
@@ -0,0 +1,23 @@
+; ModuleID = 'tests/hello_world.bc'
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
+target triple = "i386-pc-linux-gnu"
+
+@.str = private unnamed_addr constant [15 x i8] c".%x.\0A\00", align 1 ; [#uses=1 type=[5 x i8]*]
+
+define i32 @main() {
+entry:
+ %mem = alloca i32
+ store i32 4279383126, i32* %mem
+ %i24 = bitcast i32* %mem to i24*
+ %load = load i24* %i24, align 4
+ %load32 = zext i24 %load to i32
+ %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), i32 %load32)
+ %val_24 = trunc i32 4041265344 to i24
+ store i24 %val_24, i24* %i24, align 4
+ %load32b = load i32* %mem, align 4
+ %call2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([5 x i8]* @.str, i32 0, i32 0), i32 %load32b)
+ ret i32 1
+}
+
+; [#uses=1]
+declare i32 @printf(i8*, ...)
diff --git a/tests/cases/i32_mem.txt b/tests/cases/i32_mem.txt
new file mode 100644
index 00000000..683e58e2
--- /dev/null
+++ b/tests/cases/i32_mem.txt
@@ -0,0 +1,2 @@
+.123456.
+.ffe0d0c0.
diff --git a/tests/cases/sillyfuncast.ll b/tests/cases/sillyfuncast.ll
new file mode 100644
index 00000000..36c26720
--- /dev/null
+++ b/tests/cases/sillyfuncast.ll
@@ -0,0 +1,23 @@
+; ModuleID = 'tests/hello_world.bc'
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
+target triple = "i386-pc-linux-gnu"
+
+@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1 type=[15 x i8]*]
+
+define void @doit() {
+ %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0 type=i32]
+ ret void
+}
+
+define i32 @main() {
+entry:
+ %retval = alloca i32, align 4 ; [#uses=1 type=i32*]
+ store i32 0, i32* %retval
+ %58 = tail call i32 bitcast (void ()* @doit to i32 ()*)() nounwind
+ ret i32 1
+}
+
+declare i32 @printf(i8*, ...)
+
+
+
diff --git a/tests/cases/sillyfuncast2.ll b/tests/cases/sillyfuncast2.ll
new file mode 100644
index 00000000..f72ebe28
--- /dev/null
+++ b/tests/cases/sillyfuncast2.ll
@@ -0,0 +1,21 @@
+; ModuleID = 'tests/hello_world.bc'
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128"
+target triple = "i386-pc-linux-gnu"
+
+@.str = private unnamed_addr constant [15 x i8] c"hello, world!\0A\00", align 1 ; [#uses=1 type=[15 x i8]*]
+
+define void @doit(i32 %one, i32 %two) {
+ %call = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([15 x i8]* @.str, i32 0, i32 0)) ; [#uses=0 type=i32]
+ ret void
+}
+
+define i32 @main() {
+entry:
+ %retval = alloca i32, align 4 ; [#uses=1 type=i32*]
+ store i32 0, i32* %retval
+ call i32 bitcast (void (i32, i32)* @doit to i32 (i32, i64)*)(i32 0, i64 0) nounwind
+ ret i32 1
+}
+
+declare i32 @printf(i8*, ...)
+
diff --git a/tests/cases/zeroembedded.ll b/tests/cases/zeroembedded.ll
new file mode 100644
index 00000000..6a4f6073
--- /dev/null
+++ b/tests/cases/zeroembedded.ll
@@ -0,0 +1,23 @@
+; a.ll
+%struct.pypy_str = type { i32, [0 x i8] }
+%struct.pypy_strval = type { i32, [13 x i8] }
+
+%union.pypy_array3_len0u = type { %struct.pypy_array3_len0 }
+%struct.pypy_array3_len0 = type { i32, i32, [0 x i8] }
+
+@pypy_g_strval = global %struct.pypy_strval { i32 13, [13 x i8] c"hello world\0A\00" }
+@pypy_g_strval2 = global %struct.pypy_array3_len0 { i32 13, i32 111, [0 x i8] c"" }
+
+declare i32 @printf(i8*, ...)
+
+define i32 @main(i32 %argc, i8** nocapture %argv) {
+ %waka = alloca %struct.pypy_array3_len0
+ %1 = bitcast %struct.pypy_strval* @pypy_g_strval to %struct.pypy_str*
+ %2 = getelementptr inbounds %struct.pypy_str* %1, i32 1
+ %3 = bitcast %struct.pypy_str* %2 to i8*
+ call i32 (i8*, ...)* @printf(i8* %3)
+ %unneeded = bitcast %struct.pypy_str* %2 to %struct.pypy_array3_len0*
+ call i32 (i8*, ...)* @printf(i8* %3, %struct.pypy_array3_len0* %unneeded)
+ ret i32 0
+}
+
diff --git a/tests/cases/zeroembedded.txt b/tests/cases/zeroembedded.txt
new file mode 100644
index 00000000..3b18e512
--- /dev/null
+++ b/tests/cases/zeroembedded.txt
@@ -0,0 +1 @@
+hello world
diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js
index e60e1ab3..da81a81e 100644
--- a/tests/embind/embind.test.js
+++ b/tests/embind/embind.test.js
@@ -898,10 +898,7 @@ module({
test("can clone handles", function() {
var a = cm.emval_test_get_function_ptr();
- assert.equal(1, a.$$.count.value);
var b = a.clone();
- assert.equal(2, a.$$.count.value);
- assert.equal(2, b.$$.count.value);
a.delete();
assert.throws(cm.BindingError, function() {
@@ -1149,7 +1146,7 @@ module({
a.set(b);
var c = a.get();
- assert.equal(b.$$.ptr, c.$$.ptr);
+ assert.true(b.isAliasOf(c));
b.delete();
c.delete();
a.delete();
@@ -1747,8 +1744,8 @@ module({
BaseFixture.extend("constants", function() {
assert.equal(10, cm.INT_CONSTANT);
assert.equal("some string", cm.STRING_CONSTANT);
- assert.deepEqual([1, 2, 3, 4], cm.VALUE_TUPLE_CONSTANT);
- assert.deepEqual({x:1,y:2,z:3,w:4}, cm.VALUE_STRUCT_CONSTANT);
+ assert.deepEqual([1, 2, 3, 4], cm.VALUE_ARRAY_CONSTANT);
+ assert.deepEqual({x:1,y:2,z:3,w:4}, cm.VALUE_OBJECT_CONSTANT);
});
BaseFixture.extend("object handle comparison", function() {
@@ -1881,6 +1878,16 @@ module({
// setTimeout(fn, 0);
// });
});
+
+ BaseFixture.extend("references", function() {
+ test("JS object handles can be passed through to C++ by reference", function() {
+ var sh = new cm.StringHolder("Hello world");
+ assert.equal("Hello world", sh.get());
+ cm.clear_StringHolder(sh);
+ assert.equal("", sh.get());
+ sh.delete();
+ });
+ });
});
/* global run_all_tests */
diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp
index 3561b8a1..d6b27bce 100644
--- a/tests/embind/embind_test.cpp
+++ b/tests/embind/embind_test.cpp
@@ -1445,7 +1445,7 @@ EMSCRIPTEN_BINDINGS(tests) {
//function("emval_test_take_and_return_CustomStruct", &emval_test_take_and_return_CustomStruct);
- value_tuple<TupleVector>("TupleVector")
+ value_array<TupleVector>("TupleVector")
.element(&TupleVector::x)
.element(&Vector::getY, &Vector::setY)
.element(&readVectorZ, &writeVectorZ)
@@ -1455,13 +1455,13 @@ EMSCRIPTEN_BINDINGS(tests) {
function("emval_test_return_TupleVector", &emval_test_return_TupleVector);
function("emval_test_take_and_return_TupleVector", &emval_test_take_and_return_TupleVector);
- value_tuple<TupleVectorTuple>("TupleVectorTuple")
+ value_array<TupleVectorTuple>("TupleVectorTuple")
.element(&TupleVectorTuple::v)
;
function("emval_test_return_TupleVectorTuple", &emval_test_return_TupleVectorTuple);
- value_struct<StructVector>("StructVector")
+ value_object<StructVector>("StructVector")
.field("x", &StructVector::x)
.field("y", &Vector::getY, &Vector::setY)
.field("z", &readVectorZ, &writeVectorZ)
@@ -1471,7 +1471,7 @@ EMSCRIPTEN_BINDINGS(tests) {
function("emval_test_return_StructVector", &emval_test_return_StructVector);
function("emval_test_take_and_return_StructVector", &emval_test_take_and_return_StructVector);
- value_struct<TupleInStruct>("TupleInStruct")
+ value_object<TupleInStruct>("TupleInStruct")
.field("field", &TupleInStruct::field)
;
@@ -2077,12 +2077,12 @@ OrderedStruct getOrderedStruct() {
}
EMSCRIPTEN_BINDINGS(order) {
- value_tuple<OrderedTuple>("OrderedTuple")
+ value_array<OrderedTuple>("OrderedTuple")
.element(&OrderedTuple::first)
.element(&OrderedTuple::second)
;
- value_struct<OrderedStruct>("OrderedStruct")
+ value_object<OrderedStruct>("OrderedStruct")
.field("first", &OrderedStruct::first)
.field("second", &OrderedStruct::second)
;
@@ -2215,10 +2215,10 @@ EMSCRIPTEN_BINDINGS(constants) {
constant("STRING_CONSTANT", std::string("some string"));
TupleVector tv(1, 2, 3, 4);
- constant("VALUE_TUPLE_CONSTANT", tv);
+ constant("VALUE_ARRAY_CONSTANT", tv);
StructVector sv(1, 2, 3, 4);
- constant("VALUE_STRUCT_CONSTANT", sv);
+ constant("VALUE_OBJECT_CONSTANT", sv);
}
class DerivedWithOffset : public DummyDataToTestPointerAdjustment, public Base {
@@ -2235,3 +2235,11 @@ EMSCRIPTEN_BINDINGS(with_adjustment) {
function("return_Base_from_DerivedWithOffset", &return_Base_from_DerivedWithOffset);
}
+
+void clear_StringHolder(StringHolder& sh) {
+ sh.set("");
+}
+
+EMSCRIPTEN_BINDINGS(references) {
+ function("clear_StringHolder", &clear_StringHolder);
+}
diff --git a/tests/glgetattachedshaders.c b/tests/glgetattachedshaders.c
new file mode 100644
index 00000000..303e0f92
--- /dev/null
+++ b/tests/glgetattachedshaders.c
@@ -0,0 +1,93 @@
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static void die(const char *msg)
+{
+ printf("%s\n", msg);
+ abort();
+}
+
+static void create_context(void)
+{
+ EGLint num_config;
+ EGLContext g_egl_ctx;
+ EGLDisplay g_egl_dpy;
+ EGLConfig g_config;
+
+ static const EGLint attribute_list[] =
+ {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE
+ };
+
+ static const EGLint context_attributes[] =
+ {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+
+ g_egl_dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (!g_egl_dpy)
+ die("failed to create display");
+
+ if (!eglInitialize(g_egl_dpy, NULL, NULL))
+ die("failed to initialize egl");
+
+ if (!eglChooseConfig(g_egl_dpy, attribute_list, &g_config, 1, &num_config))
+ die("failed to choose config");
+
+ g_egl_ctx = eglCreateContext(g_egl_dpy, g_config, EGL_NO_CONTEXT, context_attributes);
+ if (!g_egl_ctx)
+ die("failed to create context");
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned i;
+
+ create_context();
+
+ GLuint prog = glCreateProgram();
+ if (glGetError())
+ die("failed to create program");
+
+ GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
+ if (glGetError())
+ die("failed to create vertex shader");
+ glAttachShader(prog, vertex);
+
+ GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
+ if (glGetError())
+ die("failed to create fragment shader");
+ glAttachShader(prog, fragment);
+
+ GLuint shaders[2];
+ GLsizei count;
+
+ glGetAttachedShaders(prog, 2, &count, shaders);
+ if (glGetError())
+ die("failed to get attached shaders");
+ if (count != 2)
+ die("unknown number of shaders returned");
+ if (shaders[0] == shaders[1])
+ die("returned identical shaders");
+
+ for (i = 0; i < count; i++)
+ {
+ if (shaders[i] == 0)
+ die("returned 0");
+ if (shaders[i] != vertex && shaders[i] != fragment)
+ die("unknown shader returned");
+ }
+
+ int result = 1;
+ REPORT_RESULT();
+
+ return 0;
+}
diff --git a/tests/runner.py b/tests/runner.py
index 06d3a190..4a9bf623 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -27,6 +27,7 @@ Running the main part of the test suite. Don't forget to run the other parts!
benchmark - run before and after each set of changes before pushing to
master, verify no regressions
browser - runs pages in a web browser
+ browser audio - runs audio tests in a web browser (requires human verification)
To run one of those parts, do something like
@@ -270,6 +271,8 @@ process(sys.argv[1])
print >> sys.stderr, "[was asm.js'ified]"
elif 'asm.js' in err: # if no asm.js error, then not an odin build
raise Exception("did NOT asm.js'ify")
+ err = '\n'.join(filter(lambda line: 'successfully compiled asm.js code' not in line, err.split('\n')))
+ return err
def run_generated_code(self, engine, filename, args=[], check_timeout=True, output_nicerizer=None):
stdout = os.path.join(self.get_dir(), 'stdout') # use files, as PIPE can get too full and hang us
@@ -285,7 +288,7 @@ process(sys.argv[1])
out = open(stdout, 'r').read()
err = open(stderr, 'r').read()
if engine == SPIDERMONKEY_ENGINE and Settings.ASM_JS:
- self.validate_asmjs(err)
+ err = self.validate_asmjs(err)
if output_nicerizer:
ret = output_nicerizer(out, err)
else:
@@ -1981,6 +1984,18 @@ Succeeded!
self.do_run(src, "1.0 2.0 -1.0 -2.0 2.0 3.0 -2.0 -3.0 "
"1 2 -1 -2 2 2 -2 -2")
+ def test_llrint(self):
+ if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2')
+ src = r'''
+ #include <stdio.h>
+ #include <math.h>
+ int main() {
+ printf("%lld\n%lld\n%lld\n%lld\n", llrint(0.1), llrint(0.6), llrint(1.25), llrint(1099511627776.667));
+ return 0;
+ }
+ '''
+ self.do_run(src, '0\n1\n1\n1099511627777\n')
+
def test_getgep(self):
# Generated code includes getelementptr (getelementptr, 0, 1), i.e., GEP as the first param to GEP
src = '''
@@ -2954,6 +2969,37 @@ back
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_exception_2(self):
+ if self.emcc_args is None: return self.skip('need emcc to add in libcxx properly')
+ Settings.DISABLE_EXCEPTION_CATCHING = 0
+ src = r'''
+ #include <stdexcept>
+ #include <stdio.h>
+
+ typedef void (*FuncPtr)();
+
+ void ThrowException()
+ {
+ throw std::runtime_error("catch me!");
+ }
+
+ FuncPtr ptr = ThrowException;
+
+ int main()
+ {
+ try
+ {
+ ptr();
+ }
+ catch(...)
+ {
+ printf("Exception caught successfully!\n");
+ }
+ return 0;
+ }
+ '''
+ self.do_run(src, 'Exception caught successfully!')
+
def test_white_list_exception(self):
Settings.DISABLE_EXCEPTION_CATCHING = 2
Settings.EXCEPTION_CATCHING_WHITELIST = ["__Z12somefunctionv"]
@@ -4509,6 +4555,22 @@ The current address of a is: 0x12345678
The current type of b is: 9
''')
+ def test_functionpointer_libfunc_varargs(self):
+ src = r'''
+ #include <stdio.h>
+ #include <fcntl.h>
+ typedef int (*fp_t)(int, int, ...);
+ int main(int argc, char **argv) {
+ fp_t fp = &fcntl;
+ if (argc == 1337) fp = (fp_t)&main;
+ (*fp)(0, 10);
+ (*fp)(0, 10, 5);
+ printf("waka\n");
+ return 0;
+ }
+ '''
+ self.do_run(src, '''waka''')
+
def test_structbyval(self):
Settings.INLINING_LIMIT = 50
@@ -4958,6 +5020,286 @@ The current type of b is: 9
'''
self.do_run(src, 'time: ') # compilation check, mainly
+
+ def test_strptime_tm(self):
+ src=r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+
+ int main() {
+ struct tm tm;
+ char *ptr = strptime("17410105012000", "%H%M%S%d%m%Y", &tm);
+
+ printf("%s: %s, %d/%d/%d %d:%d:%d",
+ (ptr != NULL && *ptr=='\0') ? "OK" : "ERR",
+ tm.tm_wday == 0 ? "Sun" : (tm.tm_wday == 1 ? "Mon" : (tm.tm_wday == 2 ? "Tue" : (tm.tm_wday == 3 ? "Wed" : (tm.tm_wday == 4 ? "Thu" : (tm.tm_wday == 5 ? "Fri" : (tm.tm_wday == 6 ? "Sat" : "ERR")))))),
+ tm.tm_mon+1,
+ tm.tm_mday,
+ tm.tm_year+1900,
+ tm.tm_hour,
+ tm.tm_min,
+ tm.tm_sec
+ );
+ }
+ '''
+ self.do_run(src, 'OK: Wed, 1/5/2000 17:41:1')
+
+ def test_strptime_days(self):
+ src = r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+
+ static const struct {
+ const char *input;
+ const char *format;
+ } day_tests[] = {
+ { "2000-01-01", "%Y-%m-%d"},
+ { "03/03/00", "%D"},
+ { "9/9/99", "%x"},
+ { "19990502123412", "%Y%m%d%H%M%S"},
+ { "2001 20 Mon", "%Y %U %a"},
+ { "2006 4 Fri", "%Y %U %a"},
+ { "2001 21 Mon", "%Y %W %a"},
+ { "2013 29 Wed", "%Y %W %a"},
+ { "2000-01-01 08:12:21 AM", "%Y-%m-%d %I:%M:%S %p"},
+ { "2000-01-01 08:12:21 PM", "%Y-%m-%d %I:%M:%S %p"},
+ { "2001 17 Tue", "%Y %U %a"},
+ { "2001 8 Thursday", "%Y %W %a"},
+ };
+
+ int main() {
+ struct tm tm;
+
+ for (int i = 0; i < sizeof (day_tests) / sizeof (day_tests[0]); ++i) {
+ memset (&tm, '\0', sizeof (tm));
+ char *ptr = strptime(day_tests[i].input, day_tests[i].format, &tm);
+
+ printf("%s: %d/%d/%d (%dth DoW, %dth DoY)\n", (ptr != NULL && *ptr=='\0') ? "OK" : "ERR", tm.tm_mon+1, tm.tm_mday, 1900+tm.tm_year, tm.tm_wday, tm.tm_yday);
+ }
+ }
+ '''
+ self.do_run(src, 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
+ 'OK: 3/3/2000 (5th DoW, 62th DoY)\n'\
+ 'OK: 9/9/1999 (4th DoW, 251th DoY)\n'\
+ 'OK: 5/2/1999 (0th DoW, 121th DoY)\n'\
+ 'OK: 5/21/2001 (1th DoW, 140th DoY)\n'\
+ 'OK: 1/27/2006 (5th DoW, 26th DoY)\n'\
+ 'OK: 5/21/2001 (1th DoW, 140th DoY)\n'\
+ 'OK: 7/24/2013 (3th DoW, 204th DoY)\n'\
+ 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
+ 'OK: 1/1/2000 (6th DoW, 0th DoY)\n'\
+ 'OK: 5/1/2001 (2th DoW, 120th DoY)\n'\
+ 'OK: 2/22/2001 (4th DoW, 52th DoY)\n'\
+ )
+
+ def test_strptime_reentrant(self):
+ src=r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+
+ int main () {
+ int result = 0;
+ struct tm tm;
+
+ memset (&tm, 0xaa, sizeof (tm));
+
+ /* Test we don't crash on uninitialized struct tm.
+ Some fields might contain bogus values until everything
+ needed is initialized, but we shouldn't crash. */
+ if (strptime ("2007", "%Y", &tm) == NULL
+ || strptime ("12", "%d", &tm) == NULL
+ || strptime ("Feb", "%b", &tm) == NULL
+ || strptime ("13", "%M", &tm) == NULL
+ || strptime ("21", "%S", &tm) == NULL
+ || strptime ("16", "%H", &tm) == NULL) {
+ printf("ERR: returned NULL");
+ exit(EXIT_FAILURE);
+ }
+
+ if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
+ || tm.tm_mday != 12 || tm.tm_mon != 1 || tm.tm_year != 107
+ || tm.tm_wday != 1 || tm.tm_yday != 42) {
+ printf("ERR: unexpected tm content (1) - %d/%d/%d %d:%d:%d", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ exit(EXIT_FAILURE);
+ }
+
+ if (strptime ("8", "%d", &tm) == NULL) {
+ printf("ERR: strptime failed");
+ exit(EXIT_FAILURE);
+ }
+
+ if (tm.tm_sec != 21 || tm.tm_min != 13 || tm.tm_hour != 16
+ || tm.tm_mday != 8 || tm.tm_mon != 1 || tm.tm_year != 107
+ || tm.tm_wday != 4 || tm.tm_yday != 38) {
+ printf("ERR: unexpected tm content (2) - %d/%d/%d %d:%d:%d", tm.tm_mon+1, tm.tm_mday, tm.tm_year+1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("OK");
+ }
+ '''
+ self.do_run(src, 'OK')
+
+ def test_strftime(self):
+ src=r'''
+ #include <time.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+
+ void test(int result, const char* comment, const char* parsed = "") {
+ printf("%d",result);
+ if (!result) {
+ printf("\nERROR: %s (\"%s\")\n", comment, parsed);
+ }
+ }
+
+ int cmp(const char *s1, const char *s2) {
+ for ( ; *s1 == *s2 ; s1++,s2++ ) {
+ if ( *s1 == '\0' )
+ break;
+ }
+
+ return (*s1 - *s2);
+ }
+
+ int main() {
+ struct tm tm;
+ char s[1000];
+ size_t size;
+
+ tm.tm_sec = 4;
+ tm.tm_min = 23;
+ tm.tm_hour = 20;
+ tm.tm_mday = 21;
+ tm.tm_mon = 1;
+ tm.tm_year = 74;
+ tm.tm_wday = 4;
+ tm.tm_yday = 51;
+ tm.tm_isdst = 0;
+
+ size = strftime(s, 1000, "", &tm);
+ test((size==0) && (*s=='\0'), "strftime test #1", s);
+
+ size = strftime(s, 1000, "%a", &tm);
+ test((size==3) && !cmp(s, "Thu"), "strftime test #2", s);
+
+ size = strftime(s, 1000, "%A", &tm);
+ test((size==8) && !cmp(s, "Thursday"), "strftime test #3", s);
+
+ size = strftime(s, 1000, "%b", &tm);
+ test((size==3) && !cmp(s, "Feb"), "strftime test #4", s);
+
+ size = strftime(s, 1000, "%B", &tm);
+ test((size==8) && !cmp(s, "February"),
+ "strftime test #5", s);
+
+ size = strftime(s, 1000, "%d", &tm);
+ test((size==2) && !cmp(s, "21"),
+ "strftime test #6", s);
+
+ size = strftime(s, 1000, "%H", &tm);
+ test((size==2) && !cmp(s, "20"),
+ "strftime test #7", s);
+
+ size = strftime(s, 1000, "%I", &tm);
+ test((size==2) && !cmp(s, "08"),
+ "strftime test #8", s);
+
+ size = strftime(s, 1000, "%j", &tm);
+ test((size==3) && !cmp(s, "052"),
+ "strftime test #9", s);
+
+ size = strftime(s, 1000, "%m", &tm);
+ test((size==2) && !cmp(s, "02"),
+ "strftime test #10", s);
+
+ size = strftime(s, 1000, "%M", &tm);
+ test((size==2) && !cmp(s, "23"),
+ "strftime test #11", s);
+
+ size = strftime(s, 1000, "%p", &tm);
+ test((size==2) && !cmp(s, "PM"),
+ "strftime test #12", s);
+
+ size = strftime(s, 1000, "%S", &tm);
+ test((size==2) && !cmp(s, "04"),
+ "strftime test #13", s);
+
+ size = strftime(s, 1000, "%U", &tm);
+ test((size==2) && !cmp(s, "07"),
+ "strftime test #14", s);
+
+ size = strftime(s, 1000, "%w", &tm);
+ test((size==1) && !cmp(s, "4"),
+ "strftime test #15", s);
+
+ size = strftime(s, 1000, "%W", &tm);
+ test((size==2) && !cmp(s, "07"),
+ "strftime test #16", s);
+
+ size = strftime(s, 1000, "%y", &tm);
+ test((size==2) && !cmp(s, "74"),
+ "strftime test #17", s);
+
+ size = strftime(s, 1000, "%Y", &tm);
+ test((size==4) && !cmp(s, "1974"),
+ "strftime test #18", s);
+
+ size = strftime(s, 1000, "%%", &tm);
+ test((size==1) && !cmp(s, "%"),
+ "strftime test #19", s);
+
+ size = strftime(s, 5, "%Y", &tm);
+ test((size==4) && !cmp(s, "1974"),
+ "strftime test #20", s);
+
+ size = strftime(s, 4, "%Y", &tm);
+ test((size==0), "strftime test #21", s);
+
+ tm.tm_mon = 0;
+ tm.tm_mday = 1;
+ size = strftime(s, 10, "%U", &tm);
+ test((size==2) && !cmp(s, "00"), "strftime test #22", s);
+
+ size = strftime(s, 10, "%W", &tm);
+ test((size==2) && !cmp(s, "00"), "strftime test #23", s);
+
+ // 1/1/1973 was a Sunday and is in CW 1
+ tm.tm_year = 73;
+ size = strftime(s, 10, "%W", &tm);
+ test((size==2) && !cmp(s, "01"), "strftime test #24", s);
+
+ // 1/1/1978 was a Monday and is in CW 1
+ tm.tm_year = 78;
+ size = strftime(s, 10, "%U", &tm);
+ test((size==2) && !cmp(s, "01"), "strftime test #25", s);
+
+ // 2/1/1999
+ tm.tm_year = 99;
+ tm.tm_yday = 1;
+ size = strftime(s, 10, "%G (%V)", &tm);
+ test((size==9) && !cmp(s, "1998 (53)"), "strftime test #26", s);
+
+ size = strftime(s, 10, "%g", &tm);
+ test((size==2) && !cmp(s, "98"), "strftime test #27", s);
+
+ // 30/12/1997
+ tm.tm_year = 97;
+ tm.tm_yday = 363;
+ size = strftime(s, 10, "%G (%V)", &tm);
+ test((size==9) && !cmp(s, "1998 (01)"), "strftime test #28", s);
+
+ size = strftime(s, 10, "%g", &tm);
+ test((size==2) && !cmp(s, "98"), "strftime test #29", s);
+ }
+ '''
+ self.do_run(src, '11111111111111111111111111111')
+
def test_intentional_fault(self):
# Some programs intentionally segfault themselves, we should compile that into a throw
src = r'''
@@ -5885,6 +6227,50 @@ def process(filename):
self.do_run(src, '100\n200\n13\n42\n',
post_build=add_pre_run_and_checks)
+ def test_dlfcn_self(self):
+ if Settings.USE_TYPED_ARRAYS == 1: return self.skip('Does not work with USE_TYPED_ARRAYS=1')
+ Settings.DLOPEN_SUPPORT = 1
+
+ src = r'''
+#include <stdio.h>
+#include <dlfcn.h>
+
+int global = 123;
+
+extern "C" __attribute__((noinline)) void foo(int x) {
+ printf("%d\n", x);
+}
+
+extern "C" __attribute__((noinline)) void repeatable() {
+ void* self = dlopen(NULL, RTLD_LAZY);
+ int* global_ptr = (int*)dlsym(self, "global");
+ void (*foo_ptr)(int) = (void (*)(int))dlsym(self, "foo");
+ foo_ptr(*global_ptr);
+ dlclose(self);
+}
+
+int main() {
+ repeatable();
+ repeatable();
+ return 0;
+}'''
+ def post(filename):
+ with open(filename) as f:
+ for line in f:
+ if 'var SYMBOL_TABLE' in line:
+ table = line
+ break
+ else:
+ raise Exception('Could not find symbol table!')
+ import json
+ table = json.loads(table[table.find('{'):table.rfind('}')+1])
+ actual = list(sorted(table.keys()))
+ # ensure there aren't too many globals; we don't want unnamed_addr
+ assert actual == ['_foo', '_global', '_main', '_repeatable'], \
+ "Symbol table does not match: %s" % actual
+
+ self.do_run(src, '123\n123', post_build=(None, post))
+
def test_rand(self):
return self.skip('rand() is now random') # FIXME
@@ -6605,6 +6991,26 @@ Pass: 0.000012 0.000012''')
'''
self.do_run(src, '2, , black\n2, ., #001100\n2, X, #111100');