Closed Bug 948459 Opened 12 years ago Closed 12 years ago

[jsdbg2] Assertion failure: isNonEvalFunctionFrame(), at ../vm/Stack.h:834 or Crash [@ IsAboutToBeFinalized<JSObject>] or Crash [@ address]

Categories

(Core :: JavaScript Engine, defect)

defect
Not set
critical

Tracking

()

VERIFIED FIXED
mozilla29

People

(Reporter: decoder, Assigned: jimb)

References

Details

(Keywords: assertion, crash, testcase, Whiteboard: [jsbugmon:update])

Attachments

(2 files)

The following testcase asserts on mozilla-central revision df82be9d89a5 (run with --fuzzing-safe): gcPreserveCode() gczeal(9, 2); function test2() { var g = newGlobal(); var dbg = new Debugger; var gw = dbg.addDebuggee(g); g.eval("function h() { debugger; }"); dbg.onDebuggerStatement = function (hframe) { var env = hframe.older.environment; }; g.eval("(function () { h(); return []; })();"); } test2(); function test() { var TZ_DIFF_RAW = GetRawTimezoneOffset(); var TIME_NOW = now.valueOf(); function GetRawTimezoneOffset() { var t1 = new Date(2000, 1, 1).getTimezoneOffset(); var t2 = new Date(2000, 1 + 6, 1).getTimezoneOffset(); } } test();
Needinfo from jimb because this is Debugger-related.
Flags: needinfo?(jimb)
Keywords: crash
Whiteboard: [jsbugmon:update,bisect]
Whiteboard: [jsbugmon:update,bisect] → [jsbugmon:update]
JSBugMon: Bisection requested, result: autoBisect shows this is probably related to the following changeset: The first bad revision is: changeset: http://hg.mozilla.org/mozilla-central/rev/f5eca934fa16 user: Jan de Mooij date: Fri Jun 21 08:28:06 2013 +0200 summary: Bug 881902 - Remove ContextStack and StackSpace. r=luke,njn This iteration took 2.239 seconds to run.
OOH LURVLEY, looks like it could be related to bug 947773.
Flags: needinfo?(jimb)
It seems that a scope object is being associated with a given stack frame in the debugger's liveScopes table, but that the liveScopes entry isn't being cleared when the stack frame is popped. The crash occurs because DebugScopes::sweep calls maybeSuspendedGenerator on a StackFrame * abstract frame pointer, and the frame claims to be a generator but not a function frame, which is bogus. This is because the 'flags' field of the alleged stack frame is actually the integer constant 2000, being pushed by the 'test' function in the test case. Not s-s, because it only occurs when Debugger is active, and Debugger isn't exposed to content.
The problem here is that DebugScopes::onPopCall only removes an entry from liveScopes mapping a synthesized CallObject to a non-heavyweight frame if that frame has an entry in missingScopes. If the DebugScopeObject is GC'd but its synthesized CallObject is not, then DebugScopes::sweep will remove the missingScopes entry, but not the liveScopes entry. Then, onPopCall can't find the liveScopes entry to remove it, so the entry's AbstractFramePtr becomes a dangling pointer. The next DebugScopes::sweep call tries to use it, and (if we're lucky) we crash.
(I don't know why a DebugScopeObject would be GC'd, but its synthesized CallObject not. I had thought the DebugScopeObject was the only thing that ever referred to the CallObject.)
Wow, nice detectiving! It seems like the fix is to add a 'liveScopes.remove(&debugScope.scope())' right before we remove the about-to-be-finalized debug scope from missingScopes in DebugScopes::sweep. Does that make sense to you too?
I checked and indeed for (MissingScopeMap::Enum e(missingScopes); !e.empty(); e.popFront()) { - if (IsObjectAboutToBeFinalized(e.front().value().unsafeGet())) + DebugScopeObject **debugScope = e.front().value().unsafeGet(); + if (IsObjectAboutToBeFinalized(debugScope)) { + liveScopes.remove(&(*debugScope)->scope()); e.removeFront(); + } } fixes the crash. However, part 4 in bug 948459 actually removes all this special-case generator junk (by making all generator variables 'aliased') and removes the cycle that necessitates the sweeping here. Instead, we could have missingScopes mark its values which would remove this sweeping code, the ReadBarriered, and make this all simpler to reason about.
(In reply to Luke Wagner [:luke] from comment #8) > Wow, nice detectiving! It seems like the fix is to add a > 'liveScopes.remove(&debugScope.scope())' right before we remove the > about-to-be-finalized debug scope from missingScopes in DebugScopes::sweep. > Does that make sense to you too? Yes, I was thinking that might be a fix - if we know that the synthetic call object won't be used once the DebugScopeObject for which it was created is gone. But the synthetic call object is marked, while the DebugScopeObject isn't; perhaps that's just a fluke, but if it's not, then it does suggest that that condition doesn't hold. I'll spend another hour to see if I can understand why the call object is marked. But then let's land this fix, until bug 948459 lands.
(In reply to Luke Wagner [:luke] from comment #9) > fixes the crash. However, part 4 in bug 948459 actually removes all this You meant bug 927782, right?
(In reply to Jim Blandy :jimb from comment #10) > I'll spend another hour to see if I can understand why the call object is > marked. But then let's land this fix, until bug 948459 lands. Conservative marker. !@#$%^&*
lol. I hate that thing. Btw, here's a shorter-running testcase that reproduces the assertion: gcPreserveCode() var g = newGlobal(); var dbg = new Debugger; var gw = dbg.addDebuggee(g); g.eval("function h() { debugger; }"); dbg.onDebuggerStatement = function (hframe) { hframe.older.environment; }; gczeal(9, 2); g.eval("(function () { h(); return []; })();"); (function() { var a = new Date(2000).getTimezoneOffset(); var b = new Date(2000).getTimezoneOffset(); })();
I haven't included the test case in this patch, because: 1) it takes seven seconds to run, because it depends on gczeal 2) the bug depends on the conservative scanner marking one particular object but not another, so it will have very limited value as a regression test 3) there isn't another way to get the one object marked (that's kind of the reason the bug was present in the first place - nobody was expecting that) 4) bug 927782 is going to remove all this code anyway. Try push: https://tbpl.mozilla.org/?tree=Try&rev=038595afcc5e
Attachment #8346096 - Flags: review?(luke)
(In reply to Luke Wagner [:luke] from comment #13) > lol. I hate that thing. Btw, here's a shorter-running testcase that > reproduces the assertion: That gets it down to two seconds; better! I still would argue that it's not very valuable, because it depends on conservative GC finding a particular pointer.
Comment on attachment 8346096 [details] [diff] [review] Reliably clean up DebugScopes::liveScopes when DebugScopeObjects are finalized. Review of attachment 8346096 [details] [diff] [review]: ----------------------------------------------------------------- Great! Thanks again for the digging into this. ::: js/src/vm/ScopeObject.cpp @@ +1835,5 @@ > +#if DEBUG > + /* Now this frame should not appear in liveScopes. */ > + for (LiveScopeMap::Enum e(scopes->liveScopes); !e.empty(); e.popFront()) > + JS_ASSERT(e.front().value() != frame); > +#endif This could produce pretty massive O(n^2) runtime behavior (for deep stacks) so I'd be a little worried about this seriously increasing mochtest times.
Attachment #8346096 - Flags: review?(luke) → review+
Note, bug 927782 will just frob the comment but otherwise leave the weak behavior of missingScopes intact so we'd want to remove it in a followup bug.
Hmm, that assertion I added tripped up a bunch of stuff with generational GC enabled.
Oh, hah, e.front().value() will trigger a read barrier which I get is bad during sweep :)
Pushed without the assertion, as discussed on IRC: https://hg.mozilla.org/integration/mozilla-inbound/rev/52e299230d26
Flags: in-testsuite-
OS: Linux → All
Hardware: x86_64 → All
Target Milestone: --- → mozilla29
Assignee: general → jimb
Status: NEW → ASSIGNED
Status: ASSIGNED → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Keywords: verifyme
Status: RESOLVED → VERIFIED
JSBugMon: This bug has been automatically verified fixed.
Keywords: verifyme
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: