aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/jsifier.js19
-rw-r--r--src/library.js37
-rw-r--r--src/modules.js16
-rw-r--r--tests/cases/sillyfuncast.ll23
-rw-r--r--tests/cases/sillyfuncast2.ll21
-rwxr-xr-xtests/runner.py16
-rw-r--r--tests/unistd/unlink.c165
-rw-r--r--tests/unistd/unlink.js7
-rw-r--r--tests/unistd/unlink.out42
9 files changed, 232 insertions, 114 deletions
diff --git a/src/jsifier.js b/src/jsifier.js
index 38581ce4..30cea99b 100644
--- a/src/jsifier.js
+++ b/src/jsifier.js
@@ -1474,7 +1474,6 @@ function JSify(data, functionsOnly, givenFunctions) {
}
args = args.concat(varargs);
- var argsText = args.join(', ');
// Inline if either we inline whenever we can (and we can), or if there is no noninlined version
var inline = LibraryManager.library[simpleIdent + '__inline'];
@@ -1496,9 +1495,27 @@ function JSify(data, functionsOnly, givenFunctions) {
}
}
+ if (callIdent in Functions.implementedFunctions) {
+ // LLVM sometimes bitcasts for no reason. We must call using the exact same type as the actual function is generated as.
+ var numArgs = Functions.implementedFunctions[callIdent].length - 1;
+ if (numArgs !== args.length) {
+ if (VERBOSE) warnOnce('Fixing function call arguments based on signature, on ' + [callIdent, args.length, numArgs]);
+ while (args.length > numArgs) { args.pop(); argsTypes.pop() }
+ while (args.length < numArgs) { args.push('0'); argsTypes.push('i32') }
+ }
+ }
+
var returnType = 'void';
if ((byPointer || ASM_JS) && hasReturn) {
returnType = getReturnType(type);
+ if (callIdent in Functions.implementedFunctions) {
+ // LLVM sometimes bitcasts for no reason. We must call using the exact same type as the actual function is generated as
+ var trueType = Functions.getSignatureReturnType(Functions.implementedFunctions[callIdent]);
+ if (trueType !== returnType && !isIdenticallyImplemented(trueType, returnType)) {
+ if (VERBOSE) warnOnce('Fixing function call based on return type from signature, on ' + [callIdent, returnType, trueType]);
+ returnType = trueType;
+ }
+ }
}
if (byPointer) {
diff --git a/src/library.js b/src/library.js
index 0ea9c135..5aa370a7 100644
--- a/src/library.js
+++ b/src/library.js
@@ -1867,42 +1867,42 @@ LibraryManager.library = {
rmdir: function(path) {
// int rmdir(const char *path);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/rmdir.html
- path = FS.analyzePath(Pointer_stringify(path));
+ path = Pointer_stringify(path);
+ path = FS.analyzePath(path, true);
if (!path.parentExists || !path.exists) {
___setErrNo(path.error);
return -1;
- } else if (!path.object.write || path.isRoot) {
+ } else if (!path.parentObject.write) {
___setErrNo(ERRNO_CODES.EACCES);
return -1;
} else if (!path.object.isFolder) {
___setErrNo(ERRNO_CODES.ENOTDIR);
return -1;
+ } else if (path.isRoot || path.path == FS.currentPath) {
+ ___setErrNo(ERRNO_CODES.EBUSY);
+ return -1;
} else {
for (var i in path.object.contents) {
___setErrNo(ERRNO_CODES.ENOTEMPTY);
return -1;
}
- if (path.path == FS.currentPath) {
- ___setErrNo(ERRNO_CODES.EBUSY);
- return -1;
- } else {
- delete path.parentObject.contents[path.name];
- return 0;
- }
+ delete path.parentObject.contents[path.name];
+ return 0;
}
},
unlink__deps: ['$FS', '__setErrNo', '$ERRNO_CODES'],
unlink: function(path) {
// int unlink(const char *path);
// http://pubs.opengroup.org/onlinepubs/000095399/functions/unlink.html
- path = FS.analyzePath(Pointer_stringify(path));
+ path = Pointer_stringify(path);
+ path = FS.analyzePath(path, true);
if (!path.parentExists || !path.exists) {
___setErrNo(path.error);
return -1;
} else if (path.object.isFolder) {
- ___setErrNo(ERRNO_CODES.EISDIR);
+ ___setErrNo(ERRNO_CODES.EPERM);
return -1;
- } else if (!path.object.write) {
+ } else if (!path.parentObject.write) {
___setErrNo(ERRNO_CODES.EACCES);
return -1;
} else {
@@ -6345,14 +6345,13 @@ LibraryManager.library = {
var fixup = function(value, min, max) {
return (typeof value !== 'number' || isNaN(value)) ? min : (value>=min ? (value<=max ? value: max): min);
};
-
return {
- year: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_year', 'i32') }}} + 1900 , 1970, 9999),
- month: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_mon', 'i32') }}}, 0, 11),
- day: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_mday', 'i32') }}}, 1, 31),
- hour: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_hour', 'i32') }}}, 0, 23),
- min: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_min', 'i32') }}}, 0, 59),
- sec: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_sec', 'i32') }}}, 0, 59)
+ year: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_year', 'i32', 0, 0, 1) }}} + 1900 , 1970, 9999),
+ month: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_mon', 'i32', 0, 0, 1) }}}, 0, 11),
+ day: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_mday', 'i32', 0, 0, 1) }}}, 1, 31),
+ hour: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_hour', 'i32', 0, 0, 1) }}}, 0, 23),
+ min: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_min', 'i32', 0, 0, 1) }}}, 0, 59),
+ sec: fixup({{{ makeGetValue('tm', '___tm_struct_layout.tm_sec', 'i32', 0, 0, 1) }}}, 0, 59)
};
};
diff --git a/src/modules.js b/src/modules.js
index 53d97817..9f419234 100644
--- a/src/modules.js
+++ b/src/modules.js
@@ -252,12 +252,26 @@ var Functions = {
for (var i = 0; i < argTypes.length; i++) {
var type = argTypes[i];
if (!type) break; // varargs
- sig += isIntImplemented(type) ? (getBits(type) == 64 ? 'ii' : 'i') : 'f'; // legalized i64s will be i32s
+ if (type in Runtime.FLOAT_TYPES) {
+ sig += 'f';
+ } else {
+ var chunks = getNumIntChunks(type);
+ for (var j = 0; j < chunks; j++) sig += 'i';
+ }
}
if (hasVarArgs) sig += 'i';
return sig;
},
+ getSignatureReturnType: function(sig) {
+ switch(sig[0]) {
+ case 'v': return 'void';
+ case 'i': return 'i32';
+ case 'f': return 'double';
+ default: throw 'what is this sig? ' + sig;
+ }
+ },
+
// Mark a function as needing indexing. Python will coordinate them all
getIndex: function(ident, doNotCreate, sig) {
if (doNotCreate && !(ident in this.indexedFunctions)) {
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/runner.py b/tests/runner.py
index c08434f5..339ce68c 100755
--- a/tests/runner.py
+++ b/tests/runner.py
@@ -7377,18 +7377,8 @@ def process(filename):
self.do_run(src, expected)
def test_unistd_unlink(self):
- add_pre_run = '''
-def process(filename):
- import tools.shared as shared
- src = open(filename, 'r').read().replace(
- '// {{PRE_RUN_ADDITIONS}}',
- open(shared.path_from_root('tests', 'unistd', 'unlink.js'), 'r').read()
- )
- open(filename, 'w').write(src)
-'''
src = open(path_from_root('tests', 'unistd', 'unlink.c'), 'r').read()
- expected = open(path_from_root('tests', 'unistd', 'unlink.out'), 'r').read()
- self.do_run(src, expected, post_build=add_pre_run)
+ self.do_run(src, 'success', force_c=True)
def test_unistd_links(self):
add_pre_run = '''
@@ -9844,7 +9834,7 @@ def process(filename):
Settings.CORRECT_ROUNDINGS = 0
self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-6**5*') # JS floor operations, always to the negative. This is an undetected error here!
self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # We get these right, since they are 32-bit and we can shortcut using the |0 trick
- self.do_run(src.replace('TYPE', 'unsigned int'), '*-3**2**-6**5*') # We fail, since no fast shortcut for 32-bit unsigneds
+ self.do_run(src.replace('TYPE', 'unsigned int'), '*-2**2**-6**5*')
Settings.CORRECT_ROUNDINGS = 1
Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well
@@ -9858,7 +9848,7 @@ def process(filename):
Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:13"] # Fix just the last mistake
self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-5**5*')
self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Here we are lucky and also get the first one right
- self.do_run(src.replace('TYPE', 'unsigned int'), '*-3**2**-5**5*') # No such luck here
+ self.do_run(src.replace('TYPE', 'unsigned int'), '*-2**2**-5**5*')
# And reverse the check with = 2
if Settings.USE_TYPED_ARRAYS != 2: # the errors here are very specific to non-i64 mode 1
diff --git a/tests/unistd/unlink.c b/tests/unistd/unlink.c
index 3f7d84b6..87252da2 100644
--- a/tests/unistd/unlink.c
+++ b/tests/unistd/unlink.c
@@ -1,35 +1,138 @@
-#include <stdio.h>
+#include <assert.h>
#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
+#include <sys/stat.h>
-int main() {
- char* files[] = {"/device", "/file", "/file-forbidden", "/noexist"};
- char* folders[] = {"/empty", "/empty-forbidden", "/full"};
- int i;
-
- for (i = 0; i < sizeof files / sizeof files[0]; i++) {
- printf("access(%s) before: %d\n", files[i], access(files[i], F_OK));
- rmdir(files[i]);
- printf("errno: %d\n", errno);
- errno = 0;
- printf("access(%s) after rmdir: %d\n", files[i], access(files[i], F_OK));
- unlink(files[i]);
- printf("errno: %d\n", errno);
- errno = 0;
- printf("access(%s) after unlink: %d\n\n", files[i], access(files[i], F_OK));
- }
-
- for (i = 0; i < sizeof folders / sizeof folders[0]; i++) {
- printf("access(%s) before: %d\n", folders[i], access(folders[i], F_OK));
- unlink(folders[i]);
- printf("errno: %d\n", errno);
- errno = 0;
- printf("access(%s) after unlink: %d\n", folders[i], access(folders[i], F_OK));
- rmdir(folders[i]);
- printf("errno: %d\n", errno);
- errno = 0;
- printf("access(%s) after rmdir: %d\n\n", folders[i], access(folders[i], F_OK));
- }
-
- return 0;
+static void create_file(const char *path, const char *buffer, int mode) {
+ int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
+ assert(fd >= 0);
+
+ int err = write(fd, buffer, sizeof(char) * strlen(buffer));
+ assert(err == (sizeof(char) * strlen(buffer)));
+
+ close(fd);
+}
+
+void setup() {
+ create_file("file", "test", 0777);
+ create_file("file1", "test", 0777);
+ symlink("file1", "file1-link");
+ mkdir("dir-empty", 0777);
+ symlink("dir-empty", "dir-empty-link");
+ mkdir("dir-readonly", 0777);
+ create_file("dir-readonly/anotherfile", "test", 0777);
+ mkdir("dir-readonly/anotherdir", 0777);
+ chmod("dir-readonly", 0555);
+ mkdir("dir-full", 0777);
+ create_file("dir-full/anotherfile", "test", 0777);
+}
+
+void cleanup() {
+ unlink("file");
+ unlink("file1");
+ unlink("file1-link");
+ rmdir("dir-empty");
+ unlink("dir-empty-link");
+ chmod("dir-readonly", 0777);
+ unlink("dir-readonly/anotherfile");
+ rmdir("dir-readonly/anotherdir");
+ rmdir("dir-readonly");
+ unlink("dir-full/anotherfile");
+ rmdir("dir-full");
+}
+
+void test() {
+ int err;
+ char buffer[512];
+
+ //
+ // test unlink
+ //
+ err = unlink("noexist");
+ assert(err == -1);
+ assert(errno == ENOENT);
+
+ err = unlink("dir-readonly");
+ assert(err == -1);
+#ifdef __linux__
+ assert(errno == EISDIR);
+#else
+ assert(errno == EPERM);
+#endif
+
+ err = unlink("dir-readonly/anotherfile");
+ assert(err == -1);
+ assert(errno == EACCES);
+
+ // try unlinking the symlink first to make sure
+ // we don't follow the link
+ err = unlink("file1-link");
+ assert(!err);
+ err = access("file1", F_OK);
+ assert(!err);
+ err = access("file1-link", F_OK);
+ assert(err == -1);
+
+ err = unlink("file");
+ assert(!err);
+ err = access("file", F_OK);
+ assert(err == -1);
+
+ //
+ // test rmdir
+ //
+ err = rmdir("noexist");
+ assert(err == -1);
+ assert(errno == ENOENT);
+
+ err = rmdir("file1");
+ assert(err == -1);
+ assert(errno == ENOTDIR);
+
+ err = rmdir("dir-readonly/anotherdir");
+ assert(err == -1);
+ assert(errno == EACCES);
+
+ err = rmdir("dir-full");
+ assert(err == -1);
+ assert(errno == ENOTEMPTY);
+
+ // test removing the cwd / root. The result isn't specified by
+ // POSIX, but Linux seems to set EBUSY in both cases.
+#ifndef __APPLE__
+ getcwd(buffer, sizeof(buffer));
+ err = rmdir(buffer);
+ assert(err == -1);
+ assert(errno == EBUSY);
+#endif
+ err = rmdir("/");
+ assert(err == -1);
+#ifdef __APPLE__
+ assert(errno == EISDIR);
+#else
+ assert(errno == EBUSY);
+#endif
+
+ err = rmdir("dir-empty-link");
+ assert(err == -1);
+ assert(errno == ENOTDIR);
+
+ err = rmdir("dir-empty");
+ assert(!err);
+ err = access("dir-empty", F_OK);
+ assert(err == -1);
+
+ puts("success");
}
+
+int main() {
+ atexit(cleanup);
+ signal(SIGABRT, cleanup);
+ setup();
+ test();
+ return EXIT_SUCCESS;
+} \ No newline at end of file
diff --git a/tests/unistd/unlink.js b/tests/unistd/unlink.js
deleted file mode 100644
index c2366080..00000000
--- a/tests/unistd/unlink.js
+++ /dev/null
@@ -1,7 +0,0 @@
-FS.createDevice('/', 'device', function() {}, function() {});
-FS.createDataFile('/', 'file', 'test', true, true);
-FS.createDataFile('/', 'file-forbidden', 'test', true, false);
-FS.createFolder('/', 'empty', true, true);
-FS.createFolder('/', 'empty-forbidden', true, false);
-FS.createFolder('/', 'full', true, true);
-FS.createFolder('/full', 'junk', true, true);
diff --git a/tests/unistd/unlink.out b/tests/unistd/unlink.out
deleted file mode 100644
index f7a894cb..00000000
--- a/tests/unistd/unlink.out
+++ /dev/null
@@ -1,42 +0,0 @@
-access(/device) before: 0
-errno: 20
-access(/device) after rmdir: 0
-errno: 0
-access(/device) after unlink: -1
-
-access(/file) before: 0
-errno: 20
-access(/file) after rmdir: 0
-errno: 0
-access(/file) after unlink: -1
-
-access(/file-forbidden) before: 0
-errno: 13
-access(/file-forbidden) after rmdir: 0
-errno: 13
-access(/file-forbidden) after unlink: 0
-
-access(/noexist) before: -1
-errno: 2
-access(/noexist) after rmdir: -1
-errno: 2
-access(/noexist) after unlink: -1
-
-access(/empty) before: 0
-errno: 21
-access(/empty) after unlink: 0
-errno: 0
-access(/empty) after rmdir: -1
-
-access(/empty-forbidden) before: 0
-errno: 21
-access(/empty-forbidden) after unlink: 0
-errno: 13
-access(/empty-forbidden) after rmdir: 0
-
-access(/full) before: 0
-errno: 21
-access(/full) after unlink: 0
-errno: 90
-access(/full) after rmdir: 0
-