Closed Bug 1703750 Opened 5 years ago Closed 5 years ago

Assertion failure: !cx->isExceptionPending(), at vm/JSContext-inl.h:258 with RegExp

Categories

(Core :: JavaScript Engine, defect, P1)

x86_64
Linux
defect

Tracking

()

VERIFIED FIXED
89 Branch
Tracking Status
firefox-esr78 --- wontfix
firefox87 --- wontfix
firefox88 --- wontfix
firefox89 --- verified

People

(Reporter: decoder, Assigned: iain)

References

(Regression)

Details

(Keywords: assertion, regression, testcase, Whiteboard: [bugmon:update,bisected,confirmed])

Attachments

(2 files)

The following testcase crashes on mozilla-central revision 20210407-b740f950e497 (debug build, run with --fuzzing-safe --ion-offthread-compile=off --fast-warmup):

function a() {
  const b = "".match();
  try {
      a();
  } catch {}
}
new a;

Backtrace:

received signal SIGSEGV, Segmentation fault.
#0  0x0000555556a41765 in js::CheckForInterrupt(JSContext*) ()
#1  0x0000555556f148f9 in js::RegExpShared::execute(JSContext*, JS::MutableHandle<js::RegExpShared*>, JS::Handle<JSLinearString*>, unsigned long, js::VectorMatchPairs*) ()
#2  0x0000555556b13f0d in ExecuteRegExp(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSString*>, int, js::VectorMatchPairs*) ()
#3  0x0000555556b1278a in RegExpMatcherImpl(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSString*>, int, JS::MutableHandle<JS::Value>) ()
#4  0x0000555556b12a14 in js::RegExpMatcherRaw(JSContext*, JS::Handle<JSObject*>, JS::Handle<JSString*>, int, js::MatchPairs*, JS::MutableHandle<JS::Value>) ()
#5  0x0000555557a2d802 in js::jit::RRegExpMatcher::recover(JSContext*, js::jit::SnapshotIterator&) const ()
#6  0x000055555795033d in js::jit::SnapshotIterator::computeInstructionResults(JSContext*, js::jit::RInstructionResults*) const ()
#7  0x000055555794f69a in js::jit::SnapshotIterator::initInstructionResults(js::jit::MaybeReadFallback&) ()
#8  0x00005555575bf46b in js::jit::BailoutIonToBaseline(JSContext*, js::jit::JitActivation*, js::jit::JSJitFrameIter const&, js::jit::BaselineBailoutInfo**, js::jit::ExceptionBailoutInfo const*) ()
#9  0x00005555575c06d7 in js::jit::ExceptionHandlerBailout(JSContext*, js::jit::InlineFrameIterator const&, js::jit::ResumeFromException*, js::jit::ExceptionBailoutInfo const&) ()
#10 0x000055555794815d in js::jit::HandleException(js::jit::ResumeFromException*) ()
#11 0x000017eb2838fe26 in ?? ()
[...]
#18 0x0000000000000000 in ?? ()
rax	0x5555557ca877	93824994814071
rbx	0xffffffff	4294967295
rcx	0x555557ffc488	93825036960904
rdx	0x0	0
rsi	0x7ffff7105770	140737338431344
rdi	0x7ffff7104540	140737338426688
rbp	0x7fffffdfce00	140737486245376
rsp	0x7fffffdfcdf0	140737486245360
r8	0x7ffff7105770	140737338431344
r9	0x7ffff7f99840	140737353717824
r10	0x0	0
r11	0x0	0
r12	0x7fffffdfcf20	140737486245664
r13	0x7ffff6026000	140737320738816
r14	0x7ffff6026000	140737320738816
r15	0x5	5
rip	0x555556a41765 <js::CheckForInterrupt(JSContext*)+245>
=> 0x555556a41765 <_ZN2js17CheckForInterruptEP9JSContext+245>:	movl   $0x102,0x0
   0x555556a41770 <_ZN2js17CheckForInterruptEP9JSContext+256>:	callq  0x555556a7fa0f <abort>
Attached file Testcase —

Bugmon Analysis:
Verified bug as reproducible on mozilla-central 20210407212527-b740f950e497.
The bug appears to have been introduced in the following build range:

Start: 3693f90f395dee3127a99f18ad1434ddc1300b33 (20210405180104)
End: a14b2864e74d73b2bb5ab77fa6513154994b2144 (20210405180138)
Pushlog: https://hg.mozilla.org/integration/autoland/pushloghtml?fromchange=3693f90f395dee3127a99f18ad1434ddc1300b33&tochange=a14b2864e74d73b2bb5ab77fa6513154994b2144

Whiteboard: [bugmon:update,bisect] → [bugmon:update,bisected,confirmed]

This fuzzbug triggers a particularly weird case:

  1. We overflow the stack with a large number of small stack frames, each of which has optimized away an unused regexp match.
  2. We try to bail out to the catch block by recreating the stack frame.
  3. In the recovery code, RRegExpMatcher::recover calls into RegExpMatcherRaw.
  4. We call into the regexp jitcode, which checks the stack limit and fails.
  5. RegExpShared::execute calls ReportOverRecursed to allocate an exception. This puts an entry in the store buffer.
  6. We failed to recreate the stack frame, so HandleException unwinds to the next frame and tries again.
  7. We repeat steps 2-6 until the store buffer fills up and requests an interrupt to collect the nursery.
  8. RegExpShared::execute calls CheckForInterrupt, which asserts because there's a pending exception.

The simplest way to stop this nonsense is by checking for a pending exception in the failure handling code in RegExpShared::execute, and returning that exception immediately if it exists.

Assignee: nobody → iireland
Status: NEW → ASSIGNED
Severity: -- → S3
Priority: -- → P1
Pushed by iireland@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/b124b005977c Fix regexp error handling during exception bailouts r=mgaudet
Status: ASSIGNED → RESOLVED
Closed: 5 years ago
Resolution: --- → FIXED
Target Milestone: --- → 89 Branch

Bugmon Analysis:
Verified bug as fixed on rev mozilla-central 20210413035647-d68cc4d521d9.
Removing bugmon keyword as no further action possible.
Please review the bug and re-add the keyword for further analysis.

Status: RESOLVED → VERIFIED
Keywords: bugmon

:iain, since this bug contains a bisection range, could you fill (if possible) the regressed_by field?
For more information, please visit auto_nag documentation.

Flags: needinfo?(iireland)

Semi-arbitrarily picking the patch that added the regexp retry mechanism as the regressor, because that's the part I fixed.

Flags: needinfo?(iireland)
Regressed by: 1628835
Has Regression Range: --- → yes
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: