Closed Bug 1462939 Opened 7 years ago Closed 7 years ago

Crash [@ MOZ_CrashPrintf] or Crash [@ js::ObjectGroup::sweep] or Assertion failure: MapTypeToTraceKind<typename mozilla::RemovePointer<T>::Type>::kind == thing->getTraceKind(), at gc/Marking.cpp:233

Categories

(Core :: JavaScript Engine, defect)

x86_64
Linux
defect
Not set
critical

Tracking

()

VERIFIED FIXED
mozilla62
Tracking Status
firefox-esr52 --- unaffected
firefox-esr60 --- unaffected
firefox60 --- unaffected
firefox61 --- unaffected
firefox62 --- verified

People

(Reporter: decoder, Assigned: Waldo)

References

Details

(6 keywords, Whiteboard: [jsbugmon:update][fuzzblocker])

Crash Data

Attachments

(2 files)

The following testcase crashes on mozilla-central revision 1d26b327ee6b (build with --enable-posix-nspr-emulation --enable-valgrind --enable-gczeal --disable-tests --disable-profiling --disable-debug --enable-optimize, run with --fuzzing-safe --ion-offthread-compile=off): var o = { p: 1, r: 3, s: 4, }; for (var i in o) { gc(); delete o.s; } Backtrace: received signal SIGSEGV, Segmentation fault. MOZ_CrashPrintf (aLine=aLine@entry=2613, aFormat=aFormat@entry=0xf404d0 "Got 0x%lx expected magic word 0x%lx flags 0x%lx objectSet 0x%lx") at mfbt/Assertions.cpp:63 #0 MOZ_CrashPrintf (aLine=aLine@entry=2613, aFormat=aFormat@entry=0xf404d0 "Got 0x%lx expected magic word 0x%lx flags 0x%lx objectSet 0x%lx") at mfbt/Assertions.cpp:63 #1 0x0000000000a68de3 in js::ReportMagicWordFailure (actual=<optimized out>, expected=expected@entry=11647069175327152090, flags=<optimized out>, objectSet=<optimized out>) at js/src/vm/TypeInference.cpp:2611 #2 0x0000000000c37a77 in js::ConstraintTypeSet::checkMagic (this=0x1ea1c88 <js::PropertyIteratorObject::class_+8>) at js/src/vm/TypeInference.h:739 #3 js::ObjectGroup::getProperty (sweep=..., i=<optimized out>, this=0x7ffff4ca2128) at js/src/vm/TypeInference-inl.h:1211 #4 js::GCMarker::lazilyMarkChildren (this=this@entry=0x7ffff5f1a098, group=0x7ffff4ca2128) at js/src/gc/Marking.cpp:1522 #5 0x0000000000c4c7ad in js::GCMarker::processMarkStackTop (this=this@entry=0x7ffff5f1a098, budget=...) at js/src/gc/Marking.cpp:1752 #6 0x0000000000c3cf37 in js::GCMarker::drainMarkStack (this=this@entry=0x7ffff5f1a098, budget=...) at js/src/gc/Marking.cpp:1651 #7 0x0000000000bf05d0 in js::gc::GCRuntime::drainMarkStack (this=0x7ffff5f194b0, sliceBudget=..., phase=<optimized out>) at js/src/gc/GC.cpp:5903 #8 0x0000000000c0e45a in js::gc::GCRuntime::incrementalCollectSlice (this=this@entry=0x7ffff5f194b0, budget=..., reason=reason@entry=JS::gcreason::API, session=...) at js/src/gc/GC.cpp:7116 #9 0x0000000000c0f427 in js::gc::GCRuntime::gcCycle (this=this@entry=0x7ffff5f194b0, nonincrementalByAPI=nonincrementalByAPI@entry=true, budget=..., reason=reason@entry=JS::gcreason::API) at js/src/gc/GC.cpp:7478 #10 0x0000000000c0f9ad in js::gc::GCRuntime::collect (this=this@entry=0x7ffff5f194b0, nonincrementalByAPI=nonincrementalByAPI@entry=true, budget=..., reason=reason@entry=JS::gcreason::API) at js/src/gc/GC.cpp:7621 #11 0x0000000000c0fc78 in js::gc::GCRuntime::gc (this=0x7ffff5f194b0, gckind=<optimized out>, reason=reason@entry=JS::gcreason::API) at js/src/gc/GC.cpp:7691 #12 0x0000000000c0fcb0 in JS::GCForReason (cx=cx@entry=0x7ffff5f14000, gckind=<optimized out>, reason=reason@entry=JS::gcreason::API) at js/src/gc/GC.cpp:8531 #13 0x000000000079338a in GC (cx=0x7ffff5f14000, argc=<optimized out>, vp=0x7ffff49eb0a0) at js/src/builtin/TestingFunctions.cpp:351 #14 0x00000000005657b1 in js::CallJSNative (args=..., native=0x7932a0 <GC(JSContext*, unsigned int, JS::Value*)>, cx=0x7ffff5f14000) at js/src/vm/JSContext-inl.h:280 [...] #27 main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at js/src/shell/js.cpp:9330 rax 0x1ec8660 32278112 rbx 0x7ffff5f1a098 140737319641240 rcx 0x7fffffad 2147483565 rdx 0x1ec8712 32278290 rsi 0x0 0 rdi 0x1ec86c0 32278208 rbp 0x1ea1c80 <js::PropertyIteratorObject::class_> rsp 0x7fffffffc800 140737488340992 r8 0x0 0 r9 0x52 82 r10 0x0 0 r11 0xfffffffffffffffa -6 r12 0x0 0 r13 0x7ffff4ca2128 140737300275496 r14 0x7ff8 32760 r15 0xa1a2b3b4c5c6d7da -6799674898382399526 rip 0x430bcb <MOZ_CrashPrintf(int, char const*, ...)+243> => 0x430bcb <MOZ_CrashPrintf(int, char const*, ...)+243>: movl $0x0,0x0 0x430bd6 <MOZ_CrashPrintf(int, char const*, ...)+254>: ud2 This crashes in various ways depending on 32 or 64-bit build, sometimes asserts with magic word failure, in debug builds shows a type mismatch GC assert. Marking s-s and sec-high.
This can also show up as: Assertion failure: [barrier verifier] Unmarked edge: Object 0xf59610e0 'receiver_guard_shape' edge to Shape 0xf597a7f0, at gc/Verifier.cpp:384
Crash Signature: [@ MOZ_CrashPrintf][@ js::ObjectGroup::sweep] → [@ MOZ_CrashPrintf][@ js::ObjectGroup::sweep][@ js::ObjectGroup::getProperty]
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: https://hg.mozilla.org/mozilla-central/rev/7d83c7de9404 user: Jeff Walden date: Wed May 16 23:24:28 2018 -0700 summary: Bug 1462540 - Remove NativeIterator::guard_array: its numeric value is identical to NativeIterator::props_end. r=jandem This iteration took 244.659 seconds to run.
Also seeing: Assertion failure: !overlay->isForwarded(), at gc/Marking-inl.h:41 Needinfo from Jeff based on comment 2. Also marking fuzzblocker due to the high amount of different signatures caused by this.
Flags: needinfo?(jwalden+bmo)
Whiteboard: [jsbugmon:update] → [jsbugmon:update][fuzzblocker]
FYI, OSS-Fuzz has also discovered this, which attaches a 90 day disclosure deadline to it.
Good to know. This should be fixable far before then. Also: hrm. This was very carefully written to avoid such issues, so it will be interesting to see what's up here.
Bah, I am a dumb. Property deletion causes NativeIterator::props_end to be decremented, which means guardArray() starts pointing into zeroed-out GCPtrFlatStrings and mis-offsetting which causes (in this case, with a property deletions) an ObjectGroup* to be interpreted as a Shape* and so that gets you the trace-kind mismatch from the assertion. Readding the field is the stupidest fix, but obviously it's better to not have the extra field. What if we preserved the lost-field by flipping the trailer fields after the NativeIterator? That is, instead of having [NativeIterator fields][prop0][prop1]...[propM-1][guard0][guard1]...[guardN-1] we had [NativeIterator fields][guard0][guard1]...[guardM-1][prop0][prop1]...[propN-1] ? NativeIterator::guard_length is only mutated during NativeIterator creation, now, so we could basically just swap props/guard in all the fields and functions and the current broken design would be fixed. This would slow down begin() because it'd have to do a pointer-load in |this->guards_end|, but it's only called in somewhat rare-ish places -- and I can't find any in JITted code, where |this->props_cursor| is already a necessary pointer-load -- so marginally slower perf seems unimportant. And if we changed how props are accessed to have a index/length to access them, deleting a property would just be decrementing the length, not doing |this->props_end - 1|, so it seems like a perf wash. Is there anything in this that seems un-sensible? I don't see clear, new complexity to making the change, but I'd rather get a seems-right before tackling.
Flags: needinfo?(jwalden+bmo) → needinfo?(jdemooij)
I went ahead and did comment 6. The renaming is a combination of style cleanup and forcing function to be sure I touched everything that could be affected by this. (I could style-fix the rest of this struct in a followup patch if desired, but I wanted to not grow this too much.) As far as size-consumption goes, we change from ... JSString* props_cursor; JSString* props_end; uint32_t guard_length, guard_key, flags; NativeIterator* next_; ... which including next_ (because it forces extra alignment on 64-bit) is 6 uint32_t on 32-bit, 10 uint32_t on 64-bit, to HeapReceiverGuard* guardsEnd_; JSString* propertyCursor_; JSString* propertiesEnd_; uint32_t guard_key, flags; NativeIterator* next_; ... which including next_ is 6 uint32_t on 32-bit, 10 uint32_t on 64-bit. So, no size-regression in this patch.
Attachment #8979773 - Flags: review?(jdemooij)
Assignee: nobody → jwalden+bmo
Status: NEW → ASSIGNED
Attached patch Test (deleted) — Splinter Review
The 1-deletion variant is the only one that crashes. 1 gets you the offset that mis-interprets a Shape* as ObjectGroup*. But if you have 2 or 3 or presumably more, you're going to just hit a mismatch and nothing will happen. Or so it appears at casual glance -- the extra tests are because why not, not because anything breaks if you run them.
Attachment #8979777 - Flags: review?(jdemooij)
Flags: needinfo?(jdemooij)
Comment on attachment 8979773 [details] [diff] [review] Patch that reorders guards to precede property strings and has pointer fields for guards-end, property-cursor, properties-end Review of attachment 8979773 [details] [diff] [review]: ----------------------------------------------------------------- Gah, I wish I had thought of the property suppression code messing with the properties list. ::: js/src/vm/Iteration.cpp @@ +63,5 @@ > // GC removes any elements from the list, it won't remove this one. > if (iterObj_) > TraceManuallyBarrieredEdge(trc, &iterObj_, "iterObj"); > + > + std::for_each(guardsBegin(), guardsEnd(), Fancy ::: js/src/vm/Iteration.h @@ +50,5 @@ > + // The next property, pointing into an array of strings directly after any > + // HeapReceiverGuards that appear directly after |*this|, as part of an > + // overall allocation that stores |*this|, receiver guards, and iterated > + // strings. > + GCPtrFlatString* propertyCursor_; // initialized by constructor Nit: for these public fields I'd prefer either making them private and adding accessors, or dropping the trailing _. That would also be consistent with {obj, guard_key, flags}.
Attachment #8979773 - Flags: review?(jdemooij) → review+
Attachment #8979777 - Flags: review?(jdemooij) → review+
(In reply to Jeff Walden [:Waldo] from comment #7) > (I could style-fix the rest of this struct in a followup > patch if desired, but I wanted to not grow this too much.) I missed this part. That's fine, also considering [fuzzblocker] status.
Kicked off a try-run, will land once that looks good: https://treeherder.mozilla.org/#/jobs?repo=try&revision=e1295b639a833b12b2084a3d3cc318261da77ccf In light of comment 10, I didn't bother changing anything style-wise for comment 9's nit. Will get to after this has landed in a separate bug. Also per my usual practice, I'll hold off landing the test for a week or so as nicety to nightly users, even if technically I could just land it with the patch because nightly-only.
Has Regression Range: --- → yes
Has STR: --- → yes
Group: javascript-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 7 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla62
Status: RESOLVED → VERIFIED
JSBugMon: This bug has been automatically verified fixed.
Depends on: 1464472
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: