Skip to content

Closure JSC_WRONG_ARGUMENT_COUNT against the FS runtime with -sEXPORT_ES6 on 6.0.x (fatal under -Wall -Werror) #27747

Description

@Fedr

Version

emcc 6.0.9 (4e42238). 5.0.7 is clean with the same commands. Swapping google-closure-compiler between the two shows both halves are needed: 6.0.9's output with 5.0.7's Closure 20240317 is clean, and 5.0.7's output with 6.0.9's Closure 20260726 is clean too.

Repro

// a.cpp
#include <cstdio>
int main() { FILE* f = fopen("/tmp/x.txt", "w"); if (f) { fputs("x", f); fclose(f); } return 0; }
em++ a.cpp -O2 -sEXPORT_ES6=1 --closure=1 -Wall -o a.mjs
building:WARNING: /tmp/emscripten_temp_bm3tsqfu/a.jso1.js:249:46: WARNING - [JSC_WRONG_ARGUMENT_COUNT] Function FS.init: called with 0 argument(s). Function requires at least 3 argument(s) and no more than 3 argument(s).
  249|   if (!Module["noFSInit"] && !FS.initialized) FS.init();

14 JSC_WRONG_ARGUMENT_COUNT and 4 JSC_TYPE_MISMATCH warnings in total, all in emscripten's own runtime: FS.init, FS.chmod, FS.stat, FS.mkdev, FS.createDevice, FS.write, SYSCALLS.calculateAt. A larger link (our --bind module, which uses NODEFS and SOCKFS) adds FS.createNode, FS.mkdir, NODEFS.createNode, NODEFS.stream_ops.write and SOCKFS.websocket_sock_ops.createPeer: 52 arity warnings, 60 in all.

Without -sEXPORT_ES6 (including -sMODULARIZE=1 alone, or -sINCLUDE_FULL_LIBRARY) there are no warnings, which is presumably why test_closure_full_js_library does not see this. The closure diagnostic is off by default, so a plain -Werror link is unaffected; with -Wall -Werror, which a C++ project's compile flags typically carry into the link, it becomes

em++: error: closure compiler produced warnings and -W=error=closure enabled

Cause

The functions declare parameters that are optional in practice as plain ES6 method parameters with no default and no = in a @param, and are then called with fewer arguments from the same libraries, e.g. init(input, output, error) in libfs.js vs the FS.init() in its addAtInit, stat(path, dontFollow) vs FS.stat(path), calculateAt(dirfd, path, allowEmpty) in libsyscall.js vs 13 of its 15 calls passing two arguments. Two cases go the other way: libsyscall.js passes three arguments to mkdir(path, mode = 0o777), and libnodefs.js passes six to its five-parameter stream_ops.write. The calls come from libfs.js, libnodefs.js, libnoderawfs.js, libsockfs.js and libsyscall.js.

The JSC_TYPE_MISMATCH warnings have a separate cause: libfs.js declares nameTable: null (L57) and only assigns new Array(4096) in staticInit (L1578), so Closure types the field as null and objects to every FS.nameTable[hash] access and to Object.entries(FS.nameTable) in unmount.

Suggested fix

Give the optional parameters defaults, as mkdir(path, mode = 0o777) already does, or annotate them @param {...=} as libfs.js does for createDataFile's data; drop the surplus arguments at the two call sites above; and initialise nameTable to its array (or annotate the field @type {Array}) instead of null. An -sEXPORT_ES6 variant of test_closure_full_js_library would keep it from coming back.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions