Skip to content

[EH] Check if Exception.stack is writable #21050

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

Closed
wants to merge 6 commits into from

Conversation

aheejin
Copy link
Member

@aheejin aheejin commented Jan 9, 2024

Apparently WebAssembly.Exception.stack has been readonly all along and I wasn't aware. But I wonder why this has to be readonly, and currently writing to this property works in Chrome and Node and fails in Firefox. I'll ask in the EH repo whether this should be readonly, but in the meantime, we check if this is writable before writing to it.

Temporarily fixes #21044.

Not sure how to test this... Do we run Firefox tests?

Apparently `WebAssembly.Exception.stack` has been `readonly` all along
and I wasn't aware. But I wonder why this has to be `readonly`, and
currently writing to this property works in Chrome and Node and fails in
Firefox. I'll ask in the EH repo whether this should be `readonly`, but
in the meantime, we check if this is writable before writing to it.

Temporarily fixes emscripten-core#21044.

Not sure how to test this... Do we run Firefox tests?
@kripken
Copy link
Member

kripken commented Jan 9, 2024

Yes, we run all browser tests in firefox by default, so just adding a test to test/test_browser.py will test it in firefox in test-browser-firefox.

// and it is implemented as writable in Chrome and Node. Will check the
// 'writable' condition for now and later resolve this by either deleting
// this altogether or removing this condition check.
if (Object.getOwnPropertyDescriptor(e, 'stack').writable) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combine this with the above into a single if ?

Did you verify that this is indeed readonly on FF for you locally?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combined within a single if. No I haven't verified that locally because I don't have FF installed... I'll add a browser test so it will be confirmed by the CI.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would recommend confirming the issue locally, just to be sure. Is there some reason you don't want to install FF?

@aheejin
Copy link
Member Author

aheejin commented Jan 10, 2024

Added a browser test. I don't check the text of stack traces there because we check (the simplified version of) it in test_other.py with Node; this only checks if it runs without an error.

''')
self.emcc_args = ['-g', '-fwasm-exceptions']
self.set_setting('EXCEPTION_STACK_TRACES', 1)
self.btest_exit('main.c')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big deal but I wonder if this test could run the spidermonkey command line vm (and be part of test_core.py)?

Looking at our circleci config it looks like we already run test_demangle_stacks_symbol_map under spidermonkey.

If you want to try doing this locally you can use jsvu to install spidermonkey and do something like this your .emscripten:

SPIDERMONKEY_ENGINE = [os.path.expanduser('~/.jsvu/bin/spidermonkey')]           
JS_ENGINES = [SPIDERMONKEY_ENGINE]

Copy link
Member Author

@aheejin aheejin Jan 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK this gets tricky... Yeah I installed spidermonkey and moved the test to test_core.py, with which I added a few functions and decorators for spidermonkey.

One funny thing is spidermonkey doesn't even seem to return anything with Object.getOwnPropertyDescriptor(e, 'stack');, so it is not possible to check if writable is set. So I had to split it again into two ifs:

    if (e.stack) {
      var pd = Object.getOwnPropertyDescriptor(e, 'stack');
      if (pd && pd.writable) {
        var arr = e.stack.split('\n');
        arr.splice(1,1);
        e.stack = arr.join('\n');
      }
    }

But the funny thing is, my spidermonkey doesn't seem to print

TypeError: setting getter-only property "stack"

as in #21044. It just ignores whatever I set it to, but doesn't error out:

js> var tag = new WebAssembly.Tag({parameters: ["i32"]});
js> var ex = new WebAssembly.Exception(tag, [42], {traceStack: true});
js> ex.stack
"@typein:2:10\n"
js> ex.stack = "abc";
"abc"
js> ex.stack
"@typein:2:10\n"

My spidermonkey version is

aheejin@aheejin:~/emscripten$ spidermonkey --version
JavaScript-C122.0

So, yeah, I updated the test but it is not really testing what I want to test, because the way I can think of to test this is to check if the error string contains setting getter-only property "stack" (because, due to exception, the test fails anyway), and now my spidermonkey doesn't emit that string. Not sure if that's due to version differences, or due to the difference between the browser and the shell..?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spidermonkey doesn't even seem to return anything with Object.getOwnPropertyDescriptor(e, 'stack')

That's because, like all WebIDL attributes, it's a prototype-placed accessor, not an own property. WebIDL readonly attributes are implemented as prototype-placed getters without corresponding setters. Chrome is in violation of the spec in using an own property instead.

As such the way to check is something like

function propertyWritable(obj, prop) {
  let desc = Object.getOwnPropertyDescriptor(obj, prop);
  if (!desc) {
    let proto = Object.getPrototypeOf(obj);
    return proto == null || propertyWritable(proto, prop);
  }
  return "writable" in desc
    ? desc.writable
    : typeof desc.set === "function";
}

propertyWritable(new WebAssembly.Exception(new WebAssembly.Tag({parameters: ["i32"]}), [42], {traceStack: true}), 'stack'); // true in chrome, false in FF

Copy link
Collaborator

@sbc100 sbc100 Jan 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If setting .stack is not spec compliant then we should probably just not do it... even though its currently possible on chrome.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having stack be writable isn't compliant, but if you do want to set the property, you could do Object.defineProperty(e, 'stack', { value: whatever, configurable: true, writable: true }) and that would work even in browsers where .stack is non-writable. defineProperty works even for readonly properties.

(No comment on whether you should do this, just pointing out options.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the info! But yeah, after all, I think it'd be better not to do this given that this is not spec compliant. Will close this in favor of #21065.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

setting getter-only property "stack"
4 participants