diff options
-rw-r--r-- | src/jsifier.js | 19 | ||||
-rw-r--r-- | src/library.js | 37 | ||||
-rw-r--r-- | src/modules.js | 16 | ||||
-rw-r--r-- | tests/cases/sillyfuncast.ll | 23 | ||||
-rw-r--r-- | tests/cases/sillyfuncast2.ll | 21 | ||||
-rwxr-xr-x | tests/runner.py | 16 | ||||
-rw-r--r-- | tests/unistd/unlink.c | 165 | ||||
-rw-r--r-- | tests/unistd/unlink.js | 7 | ||||
-rw-r--r-- | tests/unistd/unlink.out | 42 |
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 - |