Closed Bug 1470921 Opened 3 years ago Closed 3 years ago

Crash [@ AssertShouldMarkInZone]


(Core :: JavaScript Engine, defect, P1)




Tracking Status
firefox-esr52 --- unaffected
firefox-esr60 --- disabled
firefox61 --- disabled
firefox62 --- disabled
firefox63 --- fixed


(Reporter: decoder, Assigned: sfink)



(5 keywords, Whiteboard: [jsbugmon:][post-cristsmash-triage])

Crash Data


(2 files)

The following testcase crashes on mozilla-central revision d69b7fc884fb (build with --enable-posix-nspr-emulation --enable-valgrind --enable-gczeal --disable-tests --disable-profiling --enable-debug --enable-optimize, run with --fuzzing-safe --cpu-count=2 --ion-offthread-compile=off --baseline-eager --ion-eager --ion-check-range-analysis --ion-extra-checks --disable-oom-functions --nursery-strings=on):

See attachment.


received signal SIGSEGV, Segmentation fault.
AssertShouldMarkInZone (str=<optimized out>) at js/src/gc/Marking.cpp:362
#0  AssertShouldMarkInZone (str=<optimized out>) at js/src/gc/Marking.cpp:362
#1  0x0000000000f888e5 in js::GCMarker::mark<JSString> (this=this@entry=0x7ffff5f1a6c8, thing=thing@entry=0x7ffff5900008) at js/src/gc/Marking.cpp:908
#2  0x0000000000f89268 in js::GCMarker::eagerlyMarkChildren (this=0x7ffff5f1a6c8, rope=0x7ffff4c89970) at js/src/gc/Marking.cpp:1117
#3  0x0000000000f768b4 in js::GCMarker::eagerlyMarkChildren (str=<optimized out>, this=<optimized out>) at js/src/gc/Marking.cpp:1036
#4  js::GCMarker::markAndScan<JSString> (this=<optimized out>, thing=<optimized out>) at js/src/gc/Marking.cpp:794
#5  0x0000000000f89659 in js::GCMarker::markAndScan<JSString> (thing=<optimized out>, this=<optimized out>) at js/src/gc/Marking.cpp:865
#6  js::GCMarker::traverse<JSString*> (thing=<optimized out>, this=<optimized out>) at js/src/gc/Marking.cpp:797
#7  js::GCMarker::traverseEdge<JSObject*, JSString> (this=<optimized out>, source=<optimized out>, target=<optimized out>) at js/src/gc/Marking.cpp:864
#8  0x0000000000f9acad in TraverseObjectFunctor::operator()<JSString*> (this=<optimized out>, thing=<optimized out>, src=<optimized out>, gcmarker=<optimized out>) at js/src/gc/Marking.cpp:1449
#9  VisitTraceList<TraverseObjectFunctor, js::GCMarker*, JSObject*&>(const int32_t *, uint8_t *, <unknown type in /mnt/LangFuzz/work/builds/debug64/dist/bin/js, CU 0x7cb4043, DIE 0x7e27bf1>, JSObject *&) (traceList=0x7ffff4c22e7c, memory=0x7fffffff8e20 "Ȧ\361\365\377\177", memory@entry=0x7ffff4c22e90 "\300.\302\364\377\177", f=...) at js/src/gc/Marking.cpp:1509
#10 0x0000000000f9bb3e in CallTraceHook<TraverseObjectFunctor, js::GCMarker*, JSObject*&> (check=CheckGeneration::DoChecks, obj=0x7ffff4c22e80, trc=0x7ffff4c22e80, f=...) at js/src/gc/Marking.cpp:1490
#11 js::GCMarker::processMarkStackTop (this=this@entry=0x7ffff5f1a6c8, budget=...) at js/src/gc/Marking.cpp:1733
#12 0x0000000000f87025 in js::GCMarker::drainMarkStack (this=this@entry=0x7ffff5f1a6c8, budget=...) at js/src/gc/Marking.cpp:1543
#13 0x0000000000f08ccb in js::gc::GCRuntime::drainMarkStack (this=this@entry=0x7ffff5f19710, sliceBudget=..., phase=phase@entry=js::gcstats::PhaseKind::MARK) at js/src/gc/GC.cpp:5959
#14 0x0000000000f38c6e in js::gc::GCRuntime::incrementalCollectSlice (this=this@entry=0x7ffff5f19710, budget=..., reason=reason@entry=JS::gcreason::ALLOC_TRIGGER, session=...) at js/src/gc/GC.cpp:7168
#15 0x0000000000f39ff1 in js::gc::GCRuntime::gcCycle (this=this@entry=0x7ffff5f19710, nonincrementalByAPI=nonincrementalByAPI@entry=false, budget=..., reason=reason@entry=JS::gcreason::ALLOC_TRIGGER) at js/src/gc/GC.cpp:7532
#16 0x0000000000f3a78d in js::gc::GCRuntime::collect (this=this@entry=0x7ffff5f19710, nonincrementalByAPI=nonincrementalByAPI@entry=false, budget=..., reason=reason@entry=JS::gcreason::ALLOC_TRIGGER) at js/src/gc/GC.cpp:7678
#17 0x0000000000f3ada2 in js::gc::GCRuntime::gcSlice (this=0x7ffff5f19710, reason=JS::gcreason::ALLOC_TRIGGER, millis=0) at js/src/gc/GC.cpp:7769
#18 0x0000000000f3ae6e in js::gc::GCRuntime::gcIfRequested (this=0x7ffff5f19710) at js/src/gc/GC.cpp:7946
#19 0x0000000000c6f4d4 in HandleInterrupt (cx=0x7ffff5f17000, invokeCallback=false) at js/src/vm/Runtime.cpp:427
#20 0x00000e9b67cfc6d6 in ?? ()
#21 0xfffe2d2d2d2d2d2d in ?? ()
#22 0x00007fffffff97f8 in ?? ()
#23 0x0000000000000000 in ?? ()
rax	0xfffe2f2f2f2f2f2f	-511070251831505
rbx	0x7ffff5900008	140737313243144
rcx	0x1132e	70446
rdx	0x0	0
rsi	0x7ffff5900008	140737313243144
rdi	0x7ffff59fffe8	140737314291688
rbp	0x7fffffff8980	140737488324992
rsp	0x7fffffff8980	140737488324992
r8	0x7fffffff89a0	140737488325024
r9	0x7ffff5200000	140737305903104
r10	0x0	0
r11	0x206	518
r12	0x3	3
r13	0x7ffff5f1a6c8	140737319642824
r14	0x7ffff5f1a6e0	140737319642848
r15	0x7ffff5900008	140737313243144
rip	0xf6fe39 <AssertShouldMarkInZone(JSString*)+9>
=> 0xf6fe39 <AssertShouldMarkInZone(JSString*)+9>:	mov    0x10(%rax),%edx
   0xf6fe3c <AssertShouldMarkInZone(JSString*)+12>:	test   %edx,%edx

Test is pretty fragile, doesn't reduce properly any further without breaking. Might also be intermittent. Marking s-s due to 0x2f pattern in crash address.
Attached file Testcase
JSBugMon: Cannot process bug: Unable to automatically reproduce, please track manually.
Whiteboard: [jsbugmon:update,bisect] → [jsbugmon:bisect]
Whiteboard: [jsbugmon:bisect] → [jsbugmon:]
Needinfo Steve for --nursery-strings=on.
Flags: needinfo?(sphink)
Keywords: sec-high
On my first run (without any of the given options, but with a build that defaults nursery strings to on), I hit a different assert:

Assertion failure: cx->isExceptionPending() (Thunk execution failed but no exception was raised - missing call to js::ReportOutOfMemory()?), at /home/sfink/src/mozilla2/js/src/builtin/TestingFunctions.cpp:1797

I'll probably fix it first. But I will definitely try to reproduce the problem originally reported here; it's very similar to the crash I see in automation for nursery strings right now.
Steve - are you taking this bug (or did you file another one for the assertion you mention in comment 4?)
Assignee: nobody → sphink
Flags: needinfo?(sphink)
Priority: -- → P1
Chatting with sfink right now.  If this only happens for --nursery-strings=on then it probably doesn't need P1 or security, since that's not yet enabled.
Blocks: 1442481
What's happening here is that we are creating a string, nursery strings are enabled, so we try to allocate it in the nursery. But the nursery is full, so we do a minor GC to clear it out. During that minor GC, we decide to stop nursery-allocating strings -- but then when we continue the allocation, we don't re-check that flag, and happily allocate the string in the nursery.

Later, we compile some JIT code that concatenates two strings together. The macroassembler sees that nursery strings are disabled, so it doesn't emit post barriers.

In short, very much the exact sort of thing that fuzzing is great at uncovering and I wouldn't have stumbled across myself in 100 years. I am really glad this wasn't too timing-sensitive to reduce.
Comment on attachment 9001801 [details] [diff] [review]
Re-check whether nursery strings are enabled after collecting during allocation

Review of attachment 9001801 [details] [diff] [review]:

Attachment #9001801 - Flags: review?(jcoppeard) → review+
Duplicate of this bug: 1482993
Blocks: 903519
Group: javascript-core-security → core-security-release
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla63
Flags: qe-verify-
Whiteboard: [jsbugmon:] → [jsbugmon:][post-cristsmash-triage]
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.