Closed Bug 1445974 Opened 6 years ago Closed 2 years ago

Crash [@ HasWrapperFlag]

Categories

(Core :: DOM: Core & HTML, defect, P2)

59 Branch
defect

Tracking

()

RESOLVED WORKSFORME

People

(Reporter: jkratzer, Unassigned)

References

(Blocks 1 open bug)

Details

(Keywords: crash, testcase, Whiteboard: [bugmon:confirmed])

Crash Data

Attachments

(1 file)

Attached file testcase
Testcase found while fuzzing mozilla-central rev fcb11e93adf5.

==17754==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000010 (pc 0x7f7bc04d5c60 bp 0x7ffde51bcb70 sp 0x7ffde51bca80 T0)
==17754==The signal is caused by a READ memory access.
==17754==Hint: address points to the zero page.
    #0 0x7f7bc04d5c5f in HasWrapperFlag /builds/worker/workspace/build/src/obj-firefox/dist/include/nsWrapperCache.h:369:15
    #1 0x7f7bc04d5c5f in IsDOMBinding /builds/worker/workspace/build/src/obj-firefox/dist/include/nsWrapperCache.h:202
    #2 0x7f7bc04d5c5f in CouldBeDOMBinding /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/dom/BindingUtils.h:902
    #3 0x7f7bc04d5c5f in DoGetOrCreateDOMReflector<nsINode, mozilla::dom::binding_detail::GetOrCreateReflectorWrapBehavior::eWrapIntoContextCompartment> /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/dom/BindingUtils.h:1095
    #4 0x7f7bc04d5c5f in GetOrCreateDOMReflector<nsINode> /builds/worker/workspace/build/src/obj-firefox/dist/include/mozilla/dom/BindingUtils.h:1179
    #5 0x7f7bc04d5c5f in mozilla::dom::RangeBinding::get_commonAncestorContainer(JSContext*, JS::Handle<JSObject*>, nsRange*, JSJitGetterCallArgs) /builds/worker/workspace/build/src/obj-firefox/dom/bindings/RangeBinding.cpp:426
    #6 0x7f7bc1cc922b in mozilla::dom::GenericBindingGetter(JSContext*, unsigned int, JS::Value*) /builds/worker/workspace/build/src/dom/bindings/BindingUtils.cpp:2905:13
    #7 0x7f7bc9366f20 in js::jit::CallNativeGetter(JSContext*, JS::Handle<JSFunction*>, JS::Handle<JSObject*>, JS::MutableHandle<JS::Value>) /builds/worker/workspace/build/src/js/src/jit/VMFunctions.cpp:1557:10
    #8 0x169957c5a032  (<unknown module>)
Flags: in-testsuite?
Priority: -- → P2
Component: DOM → DOM: Core & HTML
Attachment #8959158 - Attachment description: trigger.html → testcase

Bugmon Analysis:
Verified bug as reproducible on mozilla-central 20210224100119-b3eb91f0b5a7.

Whiteboard: [bugmon:confirmed]

From https://crash-stats.mozilla.org/report/index/1ca561d6-dc24-4839-b96e-8646f0200908 it seems that we want to access mWrapper on a nullptr "instance" of some nsWrapperCache ? There is quite some inlining between the last two stack frames, which makes it a bit difficult to guess further. Can we get a pernsoco session for this?

Flags: needinfo?(twsmith)

A Pernosco session is available here: https://pernos.co/debug/QdoqJ2l8rQcwXQVWBhgb9g/index.html

Flags: needinfo?(twsmith)

So we have an endless recursion here, it seems to me.

<html>
  <head>
    <script>
      function func_1 (e) {
        try { e.currentTarget.appendChild(o4) } catch (e) {}    <-- THIS will cause another DOMSubtreeModified event and call func_1 again, I assume?
        try { o7.selectNode(o2) } catch (e) {}
        try { o7.commonAncestorContainer } catch (e) {}
        try { o7.setEndAfter(o0) } catch (e) {}
        try { o8.appendChild(o9) } catch (e) {}
      }
      try { window.o = [window, document, document.documentElement] } catch (e) {}
      try { o0 = document.documentElement } catch (e) {}
      try { o1 = document.createElement('frame') } catch (e) {}
      try { o2 = document.createElement('frame') } catch (e) {}
      try { o3 = document.createElement("n") } catch (e) {}
      try { o4 = document.createElement('a') } catch (e) {}
      try { o5 = document.createElement('m') } catch (e) {}
      try { o6 = document.createElement('t') } catch (e) {}
      try { o7 = new Range() } catch (e) {}
      try { document.documentElement.appendChild(o1) } catch (e) {}
      try { document.documentElement.appendChild(o2) } catch (e) {}
      try { o8 = o2.contentDocument.childNodes[0] } catch (e) {}
      try { o3.insertAdjacentElement("afterbegin", o6) } catch (e) {}
      try { o9 = o5.cloneNode(false) } catch (e) {}
      try { o3.addEventListener('DOMSubtreeModified', func_1, true) } catch (e) {}
      try { o9.prepend(document.documentElement) } catch (e) {}
      try { o2.appendChild(o6) } catch (e) {}
    </script>
  </head>
</html>

Not sure if we want to be able to detect something like this, do we?

Flags: needinfo?(bugs)

Not sure what we could do if we're running out of stack space.
There are tons of ways in the web platform to trigger that.

Chrome gives: Maximum call stack size exceeded.

Usually spidermonkey manages to throw similar error well before a crash. I wonder why not in this case.
Jan, perhaps you know.

Flags: needinfo?(bugs) → needinfo?(jdemooij)

(In reply to Olli Pettay [:smaug] from comment #6)

Usually spidermonkey manages to throw similar error well before a crash. I wonder why not in this case.
Jan, perhaps you know.

FWIW, there are the following messages in the pernosco log:

JavaScript error: http://127.0.0.1:49333/testcase.html, line 5: InternalError: too much recursion
JavaScript error: http://127.0.0.1:49333/testcase.html, line 5: InternalError: too much recursion
JavaScript error: http://127.0.0.1:49333/testcase.html, line 5: InternalError: too much recursion
JavaScript error: http://127.0.0.1:49333/testcase.html, line 5: InternalError: too much recursion
JavaScript error: http://127.0.0.1:49333/testcase.html, line 5: InternalError: too much recursion
JavaScript error: http://127.0.0.1:49333/testcase.html, line 5: InternalError: too much recursion
JavaScript error: http://127.0.0.1:49333/testcase.html, line 5: InternalError: too much recursion
JavaScript error: http://127.0.0.1:49333/testcase.html, line 5: InternalError: too much recursion
AddressSanitizer:DEADLYSIGNAL

So something detects the over-recursion but this seems to not be enough to halt it?

See Also: → 1422409
Severity: critical → S2

So, this is somewhat complicated...

The JS engine does have code to detect and prevent native stack overflow. We're crashing here in native code, which the JS engine technically can't prevent. But it tries anyway, by setting a relatively conservative stack limit for untrusted JS, and a less conservative limit for trusted JS, hopefully ensuring that web JS can safely call any relatively reasonable native code or system JS.

However, this crash is happening on an ASan build, and for ASan we set a much less conservative native stack limit of 6MiB rather than the 2MiB. So this should not actually be a problem in the real world, at least, not in the test case as it's currently written.

That said, I'm also not entirely sure what's happening here, since we get a SEGV presumably trying to access a stack bottom guard page for a relatively trivial stack frame, and then proceed to create a number of stack frames for the signal handler. Maybe those stack frames just don't use much stack space due to arguments being passed in registers, and maybe the faulting stack frame is doing something tricker than I realize such that we actually do have room to put return addresses for the signal handler functions on the stack... I don't know.

Severity: S2 → S4
Status: NEW → RESOLVED
Closed: 2 years ago
Flags: needinfo?(jdemooij)
Resolution: --- → WORKSFORME
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: