-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: prevent mangling errno codes for nodefs #14722
Conversation
Thank you for submitting a pull request! If this is your first PR, make sure to add yourself to AUTHORS. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand the issue exactly. Can you point me to where in the nodefs code things go wrong without this change?
tests/test_core.py
Outdated
@@ -5202,6 +5202,10 @@ def test_fs_nodefs_home(self): | |||
self.emcc_args += ['-lnodefs.js'] | |||
self.do_runf(test_file('fs/test_nodefs_home.c'), 'success', js_engines=[config.NODE_JS]) | |||
|
|||
def test_fs_nodefs_stat(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this test is specifically related to closure perhaps it should be named as such? Maybe test_fs_nodefs_errno_closure
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a better name for it; I've made the change in abd8d45
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would updating
ERRNO_CODES
in src/library.js to be defined with strings for keys fix the issue also (or have the same effect)?I just gave it a try, the test fails and the keys are transformed by Closure
I think its our library system the removes the quotes here, rather than closure. Sadly I can't think of a better way to achieve this, but I worry that this will increase code side a fair bit for programs that need ERRNO_CODE.
I wonder if we can convert a lot of the uses of ERRNO_CODES
to use the {{{ cDefine('ENOTTY') }}}
pattern and therefore avoid including ERRNO_CODES
unless really needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the problem is that the code is dynamically returned by Node itself as a property of the error, not minifying the codes is the only way I can think of to allow that dynamic lookup :/
For the code size, I'm unsure how big the real world impact could be, but I doubt the impact would be anything more than a couple bytes, considering I've seen during my Closure-ified code exploration that all references to the ERRNO_CODES enum were inlined; if it wasn't for that dynamic lookup imposed by nodefs.js the object would already get stipped away.
Would updating |
When doing some operations (like stat on a non existing file), node throws an error with the errno attached to it as a string. This string is used to lookup the error code in the map (in the convertNodeError method), which fails when the map has been reprocessed by Closure |
I just gave it a try, the test fails and the keys are transformed by Closure |
Good find, yes, dynamic name lookups on After #14730 we will at least only use ERRNO_CODES = {
"EAGAIN": .. Doing it that way instead of as a closure extern is slightly simpler, and better as it will still be able to minify the name of |
Oh, sorry, I just saw the earlier comments on quoting now. We should probably fix the quoting in our JS library. But this should also work, to move the object values into a string: diff --git a/src/library.js b/src/library.js
index dc9566970..36fb829b5 100644
--- a/src/library.js
+++ b/src/library.js
@@ -1550,8 +1550,8 @@ LibraryManager.library = {
// errno.h
// ==========================================================================
- $ERRNO_CODES: {
- EPERM: {{{ cDefine('EPERM') }}},
+ $ERRNO_CODES__postset: `ERRNO_CODES = {
+ "EPERM": {{{ cDefine('EPERM') }}},
ENOENT: {{{ cDefine('ENOENT') }}},
ESRCH: {{{ cDefine('ESRCH') }}},
EINTR: {{{ cDefine('EINTR') }}},
@@ -1672,7 +1672,8 @@ LibraryManager.library = {
ENOTRECOVERABLE: {{{ cDefine('ENOTRECOVERABLE') }}},
EOWNERDEAD: {{{ cDefine('EOWNERDEAD') }}},
ESTRPIPE: {{{ cDefine('ESTRPIPE') }}},
- },
+ };`,
+ $ERRNO_CODES: {},
$ERRNO_MESSAGES: {
0: 'Success',
{{{ cDefine('EPERM') }}}: 'Not super-user', |
tests/test_core.py
Outdated
@@ -5202,6 +5202,10 @@ def test_fs_nodefs_home(self): | |||
self.emcc_args += ['-lnodefs.js'] | |||
self.do_runf(test_file('fs/test_nodefs_home.c'), 'success', js_engines=[config.NODE_JS]) | |||
|
|||
def test_fs_nodefs_errno_closure(self): | |||
self.emcc_args += ['-lnodefs.js', '--closure=1'] | |||
self.do_runf(test_file('fs/test_nodefs_errno_closure.c'), 'success', js_engines=[config.NODE_JS]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we can get test coverage for this simply by adding self.maybe_closure()
to some/all of the exists nodefs tests? (i.e. avoid adding a new test).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, even we do add this new test that way to get closure coverage in the core tests in this file is to add self.maybe_closure()
rather than '--closure=1'
directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it looks like for example you can add self.maybe_closure()
to the existing test_fs_nodefs_home
test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm unsure if test_fs_nodefs_home
or any existing test would catch this specific case, as this issue happens only when an error is thrown by Node and it seems all these tests expect no error to happen (and therefore we never need to do that problematic dynamic lookup).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm.. if none of the existing tests are testing error conditions that sounds pretty bad.. maybe find the existing test that uses exercises stat
and add some error condition testing to it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those existing tests do look quite spotty!
How about you just add a new assert to ./tests/fs/test_nodefs_rw.c
? Just try to open a non-existent file and check the error code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've replaced my test case by 2 additional asserts in 99b9306, seems to cover the case nicely
Thanks! |
The SIMD errors have been fixed on |
Perfect, thanks @cyyynthia ! |
As described in #14705, errno codes may be looked up dynamically when using nodefs, but closure was mangling the properties making some fs operations behave unexpectedly resulting in undefined behavior.
This PR adds ERRNO_CODES and its properties as node externs, to solve this issue and only affect code size when property names may be needed (witnin a web browser, we will never need plain code names). Also includes a test case to prevent future regressions.
Closes #14705