Closed Bug 1406455 Opened 2 years ago Closed 2 years ago

Assertion failure: false (owner_.compareExchange(nullptr, this)), at js/Utility.h:326 with OOM and evalInWorker

Categories

(Core :: JavaScript Engine, defect, P2, critical)

x86
Linux
defect

Tracking

()

RESOLVED FIXED
mozilla58
Tracking Status
firefox-esr52 --- unaffected
firefox56 --- unaffected
firefox57 --- unaffected
firefox58 --- fixed

People

(Reporter: decoder, Assigned: jonco)

References

(Blocks 2 open bugs)

Details

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

Attachments

(1 file)

The following testcase crashes on mozilla-central revision 19b32a138d08 (build with --enable-posix-nspr-emulation --enable-valgrind --enable-gczeal --disable-tests --enable-stdcxx-compat --disable-profiling --enable-debug --without-intl-api --enable-optimize --target=i686-pc-linux-gnu, run with --fuzzing-safe):

var lfLogBuffer = `
evalInWorker(\`
    var code = "(module ";
    for (var i = 0; i < 100; oomAfterAllocations(100))
        code += "(func (param i32) (result i32) (i32.add (i32.const 1) (get_local 0))) ";
\`);
//corefuzz-dcd-endofdata
`;
lfLogBuffer = lfLogBuffer.split('\n');
var lfCodeBuffer = "";
while (true) {
    var line = lfLogBuffer.shift();
    if (line == "//corefuzz-dcd-evaluate") {} else if (line == "//corefuzz-dcd-endofdata") {
        loadFile(lfCodeBuffer);
    } else {
        lfCodeBuffer += line + "\n";
        function loadFile(lfVarx) {
            evaluate(lfVarx);
        }
    }
}


Backtrace:

received signal SIGSEGV, Segmentation fault.
#0  0x080ae309 in js::AutoEnterOOMUnsafeRegion::AutoEnterOOMUnsafeRegion (this=0xffffb650) at js/Utility.h:326
#1  0x08a5adee in js::TenuringTracer::moveSlotsToTenured (this=0xffffb93c, dst=0xf5572090, src=0xf5600000, dstKind=js::gc::AllocKind::OBJECT0_BACKGROUND) at js/src/gc/Marking.cpp:3019
#2  0x08a5b630 in js::TenuringTracer::moveObjectToTenured (this=0xffffb93c, dst=0xf5572090, src=0xf5600000, dstKind=js::gc::AllocKind::OBJECT0_BACKGROUND) at js/src/gc/Marking.cpp:2984
#3  0x08a5b921 in js::TenuringTracer::moveToTenured (this=0xffffb93c, src=0xf5600000) at js/src/gc/Marking.cpp:2856
#4  0x08a5bb63 in js::TenuringTracer::traverse<JSObject> (this=0xffffb93c, objp=0xffffb788) at js/src/gc/Marking.cpp:2672
#5  0x08a779fa in js::TenuringTraversalFunctor<JS::Value>::operator()<JSObject> (this=<synthetic pointer>, trc=0xffffb93c, t=0xf5600000) at js/src/gc/Marking.cpp:2678
#6  js::DispatchTyped<js::TenuringTraversalFunctor<JS::Value>, js::TenuringTracer*>(js::TenuringTraversalFunctor<JS::Value>, JS::Value const&, js::TenuringTracer*&&) (f=..., val=...) at js/Value.h:1434
#7  0x08a5c792 in js::TenuringTracer::traverse<JS::Value> (thingp=0xf53bdb68, this=0xffffb93c) at js/src/gc/Marking.cpp:2687
#8  js::TenuringTracer::traceSlots (end=<optimized out>, vp=0xf53bdb68, this=0xffffb93c) at js/src/gc/Marking.cpp:2931
#9  js::TenuringTracer::traceObjectSlots (this=0xffffb93c, nobj=0xf556f040, start=381, length=1) at js/src/gc/Marking.cpp:2924
#10 0x08a5c966 in js::gc::StoreBuffer::SlotsEdge::trace (this=0xf7943414, mover=...) at js/src/gc/Marking.cpp:2740
#11 0x08a77b98 in js::gc::StoreBuffer::MonoTypeBuffer<js::gc::StoreBuffer::SlotsEdge>::trace (this=0xf7954168, owner=0xf79540c8, mover=...) at js/src/gc/Marking.cpp:2701
#12 0x08a5d476 in js::gc::StoreBuffer::traceSlots (mover=..., this=<optimized out>) at js/src/gc/StoreBuffer.h:436
#13 js::Nursery::doCollection (this=0xf7953d98, reason=JS::gcreason::OUT_OF_NURSERY, tenureCounts=...) at js/src/gc/Nursery.cpp:761
#14 0x08a60763 in js::Nursery::collect (this=0xf7953d98, reason=JS::gcreason::OUT_OF_NURSERY) at js/src/gc/Nursery.cpp:642
#15 0x085fc4b5 in js::gc::GCRuntime::minorGC (this=0xf7952440, reason=JS::gcreason::OUT_OF_NURSERY, phase=js::gcstats::PhaseKind::MINOR_GC) at js/src/jsgc.cpp:7538
#16 0x0898f657 in js::gc::GCRuntime::tryNewNurseryObject<(js::AllowGC)1> (this=0xf7952440, cx=0xf791d000, thingSize=32, nDynamicSlots=0, clasp=0x8da8984 <JSFunction::class_>) at js/src/gc/Allocator.cpp:91
#17 0x0899110d in js::Allocate<JSObject, (js::AllowGC)1> (cx=0xf791d000, kind=js::gc::AllocKind::FIRST, nDynamicSlots=0, heap=js::gc::DefaultHeap, clasp=0x8da8984 <JSFunction::class_>) at js/src/gc/Allocator.cpp:55
#18 0x08638c24 in js::NativeObject::create (cx=0xf791d000, kind=js::gc::AllocKind::FIRST, heap=js::gc::DefaultHeap, shape=..., group=...) at js/src/vm/NativeObject-inl.h:511
#19 0x0866b791 in NewObject (cx=0xf791d000, group=..., kind=js::gc::AllocKind::FIRST, newKind=js::GenericObject, initialShapeFlags=0) at js/src/jsobj.cpp:731
#20 0x0866bf6f in js::NewObjectWithClassProtoCommon (cx=0xf791d000, clasp=0x8da8984 <JSFunction::class_>, protoArg=..., allocKind=js::gc::AllocKind::FIRST, newKind=js::GenericObject) at js/src/jsobj.cpp:852
#21 0x086150ea in js::NewObjectWithClassProto (newKind=js::GenericObject, allocKind=js::gc::AllocKind::FIRST, proto=..., clasp=0x8da8984 <JSFunction::class_>, cx=<optimized out>) at js/src/jsobjinlines.h:687
#22 NewFunctionClone (cx=0xf791d000, fun=fun@entry=..., newKind=newKind@entry=js::GenericObject, allocKind=js::gc::AllocKind::FIRST, proto=...) at js/src/jsfun.cpp:2182
#23 0x086179fd in js::CloneFunctionReuseScript (cx=0xf791d000, fun=..., enclosingEnv=..., allocKind=js::gc::AllocKind::FIRST, newKind=js::GenericObject, proto=...) at js/src/jsfun.cpp:2221
#24 0x081924e8 in js::CloneFunctionObjectIfNotSingleton (cx=0xf791d000, fun=..., parent=..., proto=..., newKind=js::GenericObject) at js/src/jsfuninlines.h:89
#25 0x0817435b in js::Lambda (cx=0xf791d000, fun=..., parent=...) at js/src/vm/Interpreter.cpp:4434
#26 0x20bb1bc8 in ?? ()
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
eax	0x0	0
ebx	0x8db2ff4	148582388
ecx	0xf7da4864	-136689564
edx	0x0	0
esi	0xffffb650	-18864
edi	0x8db4c30	148589616
ebp	0xffffb618	4294948376
esp	0xffffb5f0	4294948336
eip	0x80ae309 <js::AutoEnterOOMUnsafeRegion::AutoEnterOOMUnsafeRegion()+233>
=> 0x80ae309 <js::AutoEnterOOMUnsafeRegion::AutoEnterOOMUnsafeRegion()+233>:	movl   $0x0,0x0
   0x80ae313 <js::AutoEnterOOMUnsafeRegion::AutoEnterOOMUnsafeRegion()+243>:	ud2


The test seems very sensitive to allocations and I wasn't able to turn it into an OOMTest test. Not sure if this is s-s but there is GC on the stack and the assertion looks unfriendly.
The problem here is that we can start OOM simulation on a worker thread while the main thread is inside an AutoEnterOOMUnsafeRegion or when it otherwise doesn't expect it to happen.

I don't think there's a way to synchronise between the main / worker threads, so the simplest fix seems to be to disallow OOM simulation on worker threads.  I added a new thread type to distinguish cooperatively scheduled threads from workers.
Assignee: nobody → jcoppeard
Attachment #8916678 - Flags: review?(jdemooij)
Comment on attachment 8916678 [details] [diff] [review]
bug1406455-worker-simulated-oom

Review of attachment 8916678 [details] [diff] [review]:
-----------------------------------------------------------------

Makes sense. Tests still pass I assume?
Attachment #8916678 - Flags: review?(jdemooij) → review+
(In reply to Jan de Mooij [:jandem] from comment #2)
Yes, tests pass.

Unmarking s-s since this is a test issue that doesn't affect release builds.
Group: javascript-core-security
Priority: -- → P2
https://hg.mozilla.org/mozilla-central/rev/e3c821833a14
Status: NEW → RESOLVED
Closed: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla58
Whiteboard: [jsbugmon:update,bisect] → [jsbugmon:update]
Depends on: 1539019
No longer depends on: 1539019
Regressions: 1539019
You need to log in before you can comment on or make changes to this bug.