Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assertion failure when logging into gmail #14480

Closed
jdm opened this issue Dec 7, 2016 · 19 comments
Closed

Assertion failure when logging into gmail #14480

jdm opened this issue Dec 7, 2016 · 19 comments

Comments

@jdm
Copy link
Member

@jdm jdm commented Dec 7, 2016

STR:

  1. open https://mail.google.com
  2. type your gmail account into the login box
  3. press enter
assertion failed: !node.get_flag(HAS_DIRTY_DESCENDANTS) (thread ScriptThread PipelineId { namespace_id: PipelineNamespaceId(0), index: PipelineIndex(1) }, at /Users/jdm/src/servo/components/script/dom/node.rs:246)
(lldb) bt
error: need to add support for DW_TAG_base_type '()' encoded with DW_ATE = 0x7, bit_size = 0
* thread #24: tid = 0x1514f0, 0x00007fff8d66da81 libunwind.dylib`libunwind::CompactUnwinder_x86_64<libunwind::LocalAddressSpace>::stepWithCompactEncodingFrameless(unsigned int, unsigned long long, libunwind::LocalAddressSpace&, libunwind::Registers_x86_64&, bool) + 565, stop reason = EXC_BAD_ACCESS (code=1, address=0x20e809c43)
  * frame #0: 0x00007fff8d66da81 libunwind.dylib`libunwind::CompactUnwinder_x86_64<libunwind::LocalAddressSpace>::stepWithCompactEncodingFrameless(unsigned int, unsigned long long, libunwind::LocalAddressSpace&, libunwind::Registers_x86_64&, bool) + 565
    frame #1: 0x00007fff8d66b33b libunwind.dylib`libunwind::CompactUnwinder_x86_64<libunwind::LocalAddressSpace>::stepWithCompactEncoding(unsigned int, unsigned long long, libunwind::LocalAddressSpace&, libunwind::Registers_x86_64&) + 41
    frame #2: 0x00007fff8d66b2e1 libunwind.dylib`libunwind::UnwindCursor<libunwind::LocalAddressSpace, libunwind::Registers_x86_64>::step() + 113
    frame #3: 0x00007fff8d66f262 libunwind.dylib`_Unwind_Backtrace + 65
    frame #4: 0x0000000100aba0d2 servo`backtrace::backtrace::trace<closure> + 24 at mod.rs:82
    frame #5: 0x0000000100aba0ba servo`backtrace::backtrace::trace<closure>(cb=closure at 0x0000000121ff3500) + 58 at mod.rs:70
    frame #6: 0x0000000100aba779 servo`backtrace::capture::{{impl}}::new + 73 at lib.rs:96
    frame #7: 0x00000001000ed16d servo`servo::main::{{closure}}((null)=0x0000000000000001, info=0x0000000121ff3bb8) + 1901 at main.rs:120
    frame #8: 0x00000001056c41e4 servo`std::panicking::rust_panic_with_hook + 292 at panicking.rs:452
    frame #9: 0x000000010137a814 servo`std::panicking::begin_panic<&str>(msg=&str at 0x0000000121ff3c60, file_line=0x0000000106ef14a8) + 164 at panicking.rs:413
    frame #10: 0x000000010234f071 servo`script::dom::node::{{impl}}::add_child(self=0x000000012724d580, new_child=0x000000012724d700, before=Option<&script::dom::node::Node> at 0x0000000121ff3fa8) + 2289 at node.rs:246
    frame #11: 0x0000000102361878 servo`script::dom::node::{{impl}}::insert(node=0x000000012724d700, parent=0x000000012724d580, child=Option<&script::dom::node::Node> at 0x0000000121ff4358, suppress_observers=Unsuppressed) + 1848 at node.rs:1595
    frame #12: 0x0000000102360f72 servo`script::dom::node::{{impl}}::pre_insert(node=0x000000012724d700, parent=0x000000012724d580, child=Option<&script::dom::node::Node> at 0x0000000121ff4518) + 786 at node.rs:1539
    frame #13: 0x00000001023664b8 servo`script::dom::node::{{impl}}::AppendChild(self=0x000000012724d580, node=0x000000012724d700) + 72 at node.rs:1998
    frame #14: 0x00000001028e2303 servo`script::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::appendChild::{{closure}} + 883 at mod.rs:160
    frame #15: 0x0000000102bd0fe9 servo`core::ops::FnOnce::call_once::h8a31707b5998400f + 9
    frame #16: 0x00000001020189fb servo`std::panic::{{impl}}::call_once<bool,closure>(self=AssertUnwindSafe<closure> at 0x0000000121ff4858, _args=<unavailable>) + 91 at panic.rs:295
    frame #17: 0x000000010167c13b servo`std::panicking::try::do_call<std::panic::AssertUnwindSafe<closure>,bool>(data=0x0000000121ff4aa0) + 283 at panicking.rs:356
    frame #18: 0x00000001056c50bb servo`panic_unwind::__rust_maybe_catch_panic + 27 at lib.rs:97
    frame #19: 0x0000000101559ce5 servo`std::panicking::try<bool,std::panic::AssertUnwindSafe<closure>>(f=AssertUnwindSafe<closure> at 0x0000000121ff4ae8) + 293 at panicking.rs:332
    frame #20: 0x0000000101332627 servo`std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure>,bool>(f=AssertUnwindSafe<closure> at 0x0000000121ff4b68) + 103 at panic.rs:351
    frame #21: 0x0000000100dfd5be servo`js::panic::wrap_panic<std::panic::AssertUnwindSafe<closure>,bool>(function=AssertUnwindSafe<closure> at 0x0000000121ff4c38, generic_return_type=false) + 158 at panic.rs:22
    frame #22: 0x00000001028e1f6e servo`script::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::appendChild(cx=0x000000010db0da00, _obj=Handle<*mut js::jsapi::JSObject> at 0x0000000121ff4cd0, this=0x000000012724d580, args=0x0000000121ff4d28) + 126 at mod.rs:160
    frame #23: 0x0000000102c14091 servo`CallJitMethodOp(info=0x0000000106ebc178, cx=0x000000010db0da00, thisObj=JS::HandleObject at 0x0000000121ff4d78, specializedThis=0x000000012724d580, argc=1, vp=0x0000000110032a48) + 241 at jsglue.cpp:472
    frame #24: 0x00000001022031fb servo`script::dom::bindings::utils::generic_call(cx=0x000000010db0da00, argc=1, vp=0x0000000110032a48, is_lenient=false, call=0x0000000102c13fa0) + 3163 at utils.rs:446
    frame #25: 0x0000000102203342 servo`script::dom::bindings::utils::generic_method(cx=0x000000010db0da00, argc=1, vp=0x0000000110032a48) + 66 at utils.rs:454
    frame #26: 0x0000000103a87636 servo`js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) [inlined] js::CallJSNative(native=<unavailable>)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) + 226 at jscntxtinlines.h:232
    frame #27: 0x0000000103a87554 servo`js::InternalCallOrConstruct(cx=0x000000010db0da00, args=0x0000000121ff55a0, construct=<unavailable>) + 692 at Interpreter.cpp:453
    frame #28: 0x0000000103a800a3 servo`Interpret(JSContext*, js::RunState&) [inlined] js::CallFromStack(cx=<unavailable>, args=0x0000000110032a58) + 63955 at Interpreter.cpp:504
    frame #29: 0x0000000103a80098 servo`Interpret(cx=<unavailable>, state=<unavailable>) + 63944 at Interpreter.cpp:2873
    frame #30: 0x0000000103a7069b servo`js::RunScript(cx=0x000000010db0da00, state=0x0000000121ff5d60) + 411 at Interpreter.cpp:399
    frame #31: 0x0000000103a8791e servo`js::InternalCallOrConstruct(cx=0x000000010db0da00, args=<unavailable>, construct=<unavailable>) + 1662 at Interpreter.cpp:471
    frame #32: 0x0000000103a87a86 servo`js::Call(cx=<unavailable>, args=0x0000000121ff5e10, fval=<unavailable>, thisv=<unavailable>, rval=<unavailable>) + 38 at Interpreter.cpp:517
    frame #33: 0x00000001039acec9 servo`js::fun_call(cx=<unavailable>, argc=<unavailable>, vp=<unavailable>) + 553 at jsfun.cpp:1256
    frame #34: 0x0000000103a87636 servo`js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) [inlined] js::CallJSNative(native=<unavailable>)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) + 226 at jscntxtinlines.h:232
    frame #35: 0x0000000103a87554 servo`js::InternalCallOrConstruct(cx=0x000000010db0da00, args=0x0000000121ff6020, construct=<unavailable>) + 692 at Interpreter.cpp:453
    frame #36: 0x0000000103724311 servo`js::jit::DoCallFallback(cx=0x000000010db0da00, frame=0x0000000121ff62f8, stub_=0x000000010dbaa468, argc=2, vp=0x0000000121ff6268, res=<unavailable>) + 1329 at BaselineIC.cpp:5970
    frame #37: 0x000000011adf3759
(lldb) f 10
frame #10: 0x000000010234f071 servo`script::dom::node::{{impl}}::add_child(self=0x000000012724d580, new_child=0x000000012724d700, before=Option<&script::dom::node::Node> at 0x0000000121ff3fa8) + 2289 at node.rs:246
   243 	        for node in new_child.traverse_preorder() {
   244 	            node.set_flag(IS_IN_DOC, parent_in_doc);
   245 	            // Out-of-document elements never have the descendants flag set.
-> 246 	            debug_assert!(!node.get_flag(HAS_DIRTY_DESCENDANTS));
   247 	            vtable_for(&&*node).bind_to_tree(parent_in_doc);
   248 	        }
   249 	        let document = new_child.owner_doc();
@jdm
Copy link
Member Author

@jdm jdm commented Dec 7, 2016

cc @emilio

@jdm
Copy link
Member Author

@jdm jdm commented Dec 7, 2016

@bholley
Copy link
Contributor

@bholley bholley commented Dec 20, 2016

Hm. We're supposed to have the invariant that a node never has the dirty descendants bit (or non-null layout data) when it's not in a document.

I don't have the cycles to debug this, but could make good piranha food?

@emilio
Copy link
Member

@emilio emilio commented Dec 20, 2016

I agree that the fix could end up being trivial, but diagnosing it may not.

I bet it could be something like what was causing the underflows in #10110? That is, an element kind that Gmail uses where our implementation of unbind_from_tree doesn't end up calling the super class?

@emilio
Copy link
Member

@emilio emilio commented Dec 20, 2016

Or maybe an unbind_from_tree impl that sets dirty bits around? That'd be weird, but I guess it can happen transitively. I'll take a quick look though I'm about to sleep. I can't promise anything though.

@jdm
Copy link
Member Author

@jdm jdm commented Dec 29, 2016

This also reproduces on http://universidad.continental.edu.pe.

@jdm
Copy link
Member Author

@jdm jdm commented Dec 29, 2016

After throwing a bunch of assertions in places that set the flags, I finally caught this. The flag is being set on elements that aren't actually in the document during layout; next step is figuring out why layout is interacting with nodes that aren't in the document.

@emilio
Copy link
Member

@emilio emilio commented Dec 29, 2016

Heh, #14776

@emilio
Copy link
Member

@emilio emilio commented Dec 29, 2016

The easy answer is: getComputedStyle.

@emilio
Copy link
Member

@emilio emilio commented Dec 29, 2016

(or CSSStyleDeclaration).

@jdm
Copy link
Member Author

@jdm jdm commented Dec 29, 2016

That is in the backtrace of the script thread, so that's plausible!

@jdm
Copy link
Member Author

@jdm jdm commented Dec 29, 2016

However, CSSStyleDeclaration::get_computed_style checks whether the node is in a document, so it's got to be more subtle than that.

@emilio
Copy link
Member

@emilio emilio commented Dec 29, 2016

@jdm do you have that backtrace? Other suspects are offsetTop and friends, and pretty much everything that does uses the rpc interface to layout.

@jdm
Copy link
Member Author

@jdm jdm commented Dec 29, 2016

    frame #9: 0x0000000102affc55 servo`script::dom::window::{{impl}}::force_reflow(self=0x0000000123a53500, goal=ForScriptQuery, query_type=ReflowQueryType at 0x000000012d217dc8, reason=Query) + 4501 at window.rs:1098
    frame #10: 0x0000000102b003e2 servo`script::dom::window::{{impl}}::reflow(self=0x0000000123a53500, goal=ForScriptQuery, query_type=ReflowQueryType at 0x000000012d218318, reason=Query) + 514 at window.rs:1142
    frame #11: 0x0000000102b01dfc servo`script::dom::window::{{impl}}::resolved_style_query(self=0x0000000123a53500, element=TrustedNodeAddress at 0x000000012d2184b0, pseudo=Option<style::servo::selector_parser::PseudoElement> at 0x000000012d2184a0, property=PropertyId at 0x000000012d218488) + 284 at window.rs:1302
    frame #12: 0x0000000102920427 servo`script::dom::cssstyledeclaration::{{impl}}::get_computed_style(self=0x00000001198f52e0, property=PropertyId at 0x000000012d2185c8) + 503 at cssstyledeclaration.rs:84
    frame #13: 0x0000000102920558 servo`script::dom::cssstyledeclaration::{{impl}}::get_property_value(self=0x00000001198f52e0, id=PropertyId at 0x000000012d2186f8) + 200 at cssstyledeclaration.rs:90
    frame #14: 0x0000000102921f88 servo`script::dom::cssstyledeclaration::{{impl}}::GetPropertyValue(self=0x00000001198f52e0, property=DOMString at 0x000000012d218830) + 536 at cssstyledeclaration.rs:208
    frame #15: 0x0000000102c2ba62 servo`script::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationBinding::getPropertyValue::{{closure}} + 866 at mod.rs:160
    frame #16: 0x00000001032d9139 servo`core::ops::FnOnce::call_once::h4058a05f78e680fa + 9
@jdm
Copy link
Member Author

@jdm jdm commented Dec 29, 2016

Full backtrace:

  * frame #0: 0x00007fff8b986716 libsystem_kernel.dylib`__psynch_cvwait + 10
    frame #1: 0x00007fff8e40bc3b libsystem_pthread.dylib`_pthread_cond_wait + 727
    frame #2: 0x00000001056eea19 servo`std::thread::park [inlined] std::sys::imp::condvar::{{impl}}::wait + 265 at condvar.rs:64
    frame #3: 0x00000001056eea14 servo`std::thread::park [inlined] std::sys_common::condvar::{{impl}}::wait at condvar.rs:51
    frame #4: 0x00000001056eea14 servo`std::thread::park [inlined] std::sync::condvar::{{impl}}::wait<bool> + 29 at condvar.rs:125
    frame #5: 0x00000001056ee9f7 servo`std::thread::park + 231 at mod.rs:466
    frame #6: 0x00000001056fb320 servo`std::sync::mpsc::blocking::{{impl}}::wait + 32 at blocking.rs:81
    frame #7: 0x000000010241d400 servo`std::sync::mpsc::oneshot::{{impl}}::recv<(self=0x00000001280ef010, deadline=Option<std::time::Instant> at 0x000000012d216ff8)> + 416 at oneshot.rs:158
    frame #8: 0x0000000101f54b16 servo`std::sync::mpsc::{{impl}}::recv<(self=0x000000012d217b00)> + 374 at mod.rs:867
    frame #9: 0x0000000102affc55 servo`script::dom::window::{{impl}}::force_reflow(self=0x0000000123a53500, goal=ForScriptQuery, query_type=ReflowQueryType at 0x000000012d217dc8, reason=Query) + 4501 at window.rs:1098
    frame #10: 0x0000000102b003e2 servo`script::dom::window::{{impl}}::reflow(self=0x0000000123a53500, goal=ForScriptQuery, query_type=ReflowQueryType at 0x000000012d218318, reason=Query) + 514 at window.rs:1142
    frame #11: 0x0000000102b01dfc servo`script::dom::window::{{impl}}::resolved_style_query(self=0x0000000123a53500, element=TrustedNodeAddress at 0x000000012d2184b0, pseudo=Option<style::servo::selector_parser::PseudoElement> at 0x000000012d2184a0, property=PropertyId at 0x000000012d218488) + 284 at window.rs:1302
    frame #12: 0x0000000102920427 servo`script::dom::cssstyledeclaration::{{impl}}::get_computed_style(self=0x00000001198f52e0, property=PropertyId at 0x000000012d2185c8) + 503 at cssstyledeclaration.rs:84
    frame #13: 0x0000000102920558 servo`script::dom::cssstyledeclaration::{{impl}}::get_property_value(self=0x00000001198f52e0, id=PropertyId at 0x000000012d2186f8) + 200 at cssstyledeclaration.rs:90
    frame #14: 0x0000000102921f88 servo`script::dom::cssstyledeclaration::{{impl}}::GetPropertyValue(self=0x00000001198f52e0, property=DOMString at 0x000000012d218830) + 536 at cssstyledeclaration.rs:208
    frame #15: 0x0000000102c2ba62 servo`script::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationBinding::getPropertyValue::{{closure}} + 866 at mod.rs:160
    frame #16: 0x00000001032d9139 servo`core::ops::FnOnce::call_once::h4058a05f78e680fa + 9
    frame #17: 0x000000010277d08b servo`std::panic::{{impl}}::call_once<bool,closure>(self=AssertUnwindSafe<closure> at 0x000000012d218ae8, _args=<unavailable>) + 91 at panic.rs:295
    frame #18: 0x0000000101ebc21b servo`std::panicking::try::do_call<std::panic::AssertUnwindSafe<closure>,bool>(data=0x000000012d218d30) + 283 at panicking.rs:356
    frame #19: 0x000000010570624b servo`panic_unwind::__rust_maybe_catch_panic + 27 at lib.rs:97
    frame #20: 0x0000000101ae6bc5 servo`std::panicking::try<bool,std::panic::AssertUnwindSafe<closure>>(f=AssertUnwindSafe<closure> at 0x000000012d218d78) + 293 at panicking.rs:332
    frame #21: 0x0000000101aa3647 servo`std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure>,bool>(f=AssertUnwindSafe<closure> at 0x000000012d218df8) + 103 at panic.rs:351
    frame #22: 0x000000010165071e servo`js::panic::wrap_panic<std::panic::AssertUnwindSafe<closure>,bool>(function=AssertUnwindSafe<closure> at 0x000000012d218ec8, generic_return_type=false) + 158 at panic.rs:22
    frame #23: 0x0000000102c2b6de servo`script::dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclarationBinding::getPropertyValue(cx=0x0000000114005c00, _obj=Handle<*mut js::jsapi::JSObject> at 0x000000012d218f60, this=0x00000001198f52e0, args=0x000000012d218fb8) + 126 at mod.rs:160
    frame #24: 0x0000000103310a61 servo`CallJitMethodOp(info=0x0000000106eed0a0, cx=0x0000000114005c00, thisObj=JS::HandleObject at 0x000000012d219008, specializedThis=0x00000001198f52e0, argc=1, vp=0x000000010f878870) + 241 at jsglue.cpp:472
    frame #25: 0x00000001028dcd1b servo`script::dom::bindings::utils::generic_call(cx=0x0000000114005c00, argc=1, vp=0x000000010f878870, is_lenient=false, call=0x0000000103310970) + 3163 at utils.rs:446
    frame #26: 0x00000001028dce62 servo`script::dom::bindings::utils::generic_method(cx=0x0000000114005c00, argc=1, vp=0x000000010f878870) + 66 at utils.rs:454
    frame #27: 0x00000001044b1496 servo`js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) [inlined] js::CallJSNative(native=<unavailable>)(JSContext*, unsigned int, JS::Value*), JS::CallArgs const&) + 226 at jscntxtinlines.h:232
    frame #28: 0x00000001044b13b4 servo`js::InternalCallOrConstruct(cx=0x0000000114005c00, args=0x000000012d219830, construct=<unavailable>) + 692 at Interpreter.cpp:453
    frame #29: 0x00000001044a9f03 servo`Interpret(JSContext*, js::RunState&) [inlined] js::CallFromStack(cx=<unavailable>, args=0x000000010f878880) + 63955 at Interpreter.cpp:504
    frame #30: 0x00000001044a9ef8 servo`Interpret(cx=<unavailable>, state=<unavailable>) + 63944 at Interpreter.cpp:2873
    frame #31: 0x000000010449a4fb servo`js::RunScript(cx=0x0000000114005c00, state=0x000000012d219fc0) + 411 at Interpreter.cpp:399
    frame #32: 0x00000001044b2303 servo`js::ExecuteKernel(cx=<unavailable>, scopeChainArg=<unavailable>, newTargetValue=<unavailable>, result=<unavailable>, script=<unavailable>, evalInFrame=<unavailable>) + 371 at Interpreter.cpp:679
    frame #33: 0x00000001044b2457 servo`js::Execute(cx=0x0000000114005c00, scopeChainArg=<unavailable>, rval=0x000000012d21aa98, script=<unavailable>) + 279 at Interpreter.cpp:711
    frame #34: 0x000000010437a549 servo`Evaluate(cx=0x0000000114005c00, optionsArg=<unavailable>, srcBuf=<unavailable>, scope=<unavailable>, staticScope=<unavailable>, rval=<unavailable>) + 313 at jsapi.cpp:4406
    frame #35: 0x000000010437a706 servo`JS::Evaluate(JSContext*, JS::ReadOnlyCompileOptions const&, char16_t const*, unsigned long, JS::MutableHandle<JS::Value>) [inlined] Evaluate(chars=<unavailable>, length=<unavailable>) + 196 at jsapi.cpp:4443
    frame #36: 0x000000010437a642 servo`JS::Evaluate(cx=0x0000000114005c00, optionsArg=0x000000012917f930, chars=<unavailable>, length=<unavailable>, rval=<unavailable>) + 18 at jsapi.cpp:4501
    frame #37: 0x00000001029a4988 servo`script::dom::globalscope::{{impl}}::evaluate_script_on_global_with_result::{{closure}} + 632 at globalscope.rs:370
    frame #38: 0x00000001013435b4 servo`profile_traits::time::profile<(category=ScriptEvaluate, meta=Option<profile_traits::time::TimerMetadata> at 0x000000012d21a648, profiler_chan=ProfilerChan at 0x000000012d21a640, callback=closure at 0x000000012d21a618),closure> + 564 at time.rs:119
    frame #39: 0x00000001029a4686 servo`script::dom::globalscope::{{impl}}::evaluate_script_on_global_with_result(self=0x0000000123a53500, code=&str at 0x000000012d21a7d8, filename=&str at 0x000000012d21a7c8, rval=MutableHandle<js::jsapi::Value> at 0x000000012d21a7c0) + 678 at globalscope.rs:357
    frame #40: 0x0000000102a0674e servo`script::dom::htmlscriptelement::{{impl}}::execute(self=0x0000000123b6db80) + 2974 at htmlscriptelement.rs:497
    frame #41: 0x0000000102a8e35f servo`script::dom::servoparser::{{impl}}::resume_with_pending_parsing_blocking_script(self=0x000000012b740900, script=0x0000000123b6db80) + 1231 at mod.rs:183
    frame #42: 0x000000010293bdf7 servo`script::dom::document::{{impl}}::finish_load(self=0x0000000123b9a900, load=LoadType at 0x000000012d21b548) + 1511 at document.rs:1585
    frame #43: 0x0000000102a02499 servo`script::dom::htmlscriptelement::{{impl}}::process_response_eof(self=0x0000000128ec8220, response=Result<(), net_traits::NetworkError> at 0x000000012d21b7c8) + 905 at htmlscriptelement.rs:214
    frame #44: 0x00000001025d546e servo`net_traits::{{impl}}::process<script::dom::htmlscriptelement::ScriptContext>(self=FetchResponseMsg at 0x000000012d21be68, listener=0x0000000128ec8220) + 782 at lib.rs:236
    frame #45: 0x0000000102b35e2d servo`script::network_listener::{{impl}}::handler<net_traits::FetchResponseMsg,script::dom::htmlscriptelement::ScriptContext>(self=0x000000012f7e03c0) + 429 at network_listener.rs:71
    frame #46: 0x0000000102b4148d servo`script::script_thread::{{impl}}::handler<script::network_listener::ListenerRunnable<net_traits::FetchResponseMsg, script::dom::htmlscriptelement::ScriptContext>>(self=0x00000001199748d0) + 29 at script_thread.rs:213
    frame #47: 0x0000000102b4fb3e servo`script::script_thread::{{impl}}::handle_msg_from_script(self=0x000000012d21fe08, msg=MainThreadScriptMsg at 0x000000012d21c938) + 1038 at script_thread.rs:1032
    frame #48: 0x0000000102b4c234 servo`script::script_thread::{{impl}}::handle_msgs::{{closure}} + 436 at script_thread.rs:861
    frame #49: 0x0000000102b4cce8 servo`script::script_thread::{{impl}}::profile_event<closure,core::option::Option<bool>>(self=0x000000012d21fe08, category=NetworkEvent, f=closure at 0x000000012d21d320) + 296 at script_thread.rs:954
    frame #50: 0x0000000102b4a8ad servo`script::script_thread::{{impl}}::handle_msgs(self=0x000000012d21fe08) + 6861 at script_thread.rs:854
    frame #51: 0x0000000102b48c9f servo`script::script_thread::{{impl}}::start(self=0x000000012d21fe08) + 271 at script_thread.rs:711
    frame #52: 0x0000000102b44d15 servo`script::script_thread::{{impl}}::create::{{closure}}::{{closure}} + 37 at script_thread.rs:549
    frame #53: 0x0000000101341f39 servo`profile_traits::mem::{{impl}}::run_with_memory_reporting<closure,fn(self=0x000000012d220058, f=closure at 0x000000012d21fa30, reporter_name=String at 0x000000012d21fa10, channel_for_reporter=Sender<script::script_thread::MainThreadScriptMsg> at 0x000000012d21fa00, msg=0x0000000000000000) -> script::script_runtime::CommonScriptMsg,script::script_runtime::CommonScriptMsg,std::sync::mpsc::Sender<script::script_thread::MainThreadScriptMsg>> + 761 at mem.rs:63
    frame #54: 0x0000000102b453aa servo`script::script_thread::{{impl}}::create::{{closure}} + 1610 at script_thread.rs:548
    frame #55: 0x0000000102766f2b servo`std::panic::{{impl}}::call_once<(self=AssertUnwindSafe<closure> at 0x000000012d2204b8, _args=<unavailable>),closure> + 155 at panic.rs:295
    frame #56: 0x0000000101e2ed19 servo`std::panicking::try::do_call<std::panic::AssertUnwindSafe<closure>,(data=0x000000012d221128)> + 425 at panicking.rs:356
    frame #57: 0x000000010570624b servo`panic_unwind::__rust_maybe_catch_panic + 27 at lib.rs:97
    frame #58: 0x0000000101b594fa servo`std::panicking::try<(f=AssertUnwindSafe<closure> at 0x000000012d221388),std::panic::AssertUnwindSafe<closure>> + 346 at panicking.rs:332
    frame #59: 0x0000000101a66d55 servo`std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure>,(f=AssertUnwindSafe<closure> at 0x000000012d221768)> + 165 at panic.rs:351
    frame #60: 0x0000000101aafcfd servo`std::thread::{{impl}}::spawn::{{closure}}<closure,()> + 429 at mod.rs:287
    frame #61: 0x0000000102411ada servo`alloc::boxed::{{impl}}::call_box<(self=0x000000010e296500, args=<unavailable>),closure> + 74 at boxed.rs:595
    frame #62: 0x00000001057042f5 servo`std::sys::imp::thread::{{impl}}::new::thread_start [inlined] alloc::boxed::{{impl}}::call_once<(),()> + 37 at boxed.rs:605
    frame #63: 0x00000001057042ef servo`std::sys::imp::thread::{{impl}}::new::thread_start [inlined] std::sys_common::thread::start_thread + 15 at thread.rs:21
    frame #64: 0x00000001057042e0 servo`std::sys::imp::thread::{{impl}}::new::thread_start + 16 at thread.rs:84
    frame #65: 0x00007fff8e409899 libsystem_pthread.dylib`_pthread_body + 138
    frame #66: 0x00007fff8e40972a libsystem_pthread.dylib`_pthread_start + 137
    frame #67: 0x00007fff8e40dfc9 libsystem_pthread.dylib`thread_start + 13
@jdm
Copy link
Member Author

@jdm jdm commented Dec 29, 2016

My assertions:

diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs
index d2bdf3a..9a95c9a 100644
--- a/components/layout_thread/lib.rs
+++ b/components/layout_thread/lib.rs
@@ -1082,6 +1082,8 @@ impl LayoutThread {
 
                 let mut next = iter.next();
                 while let Some(node) = next {
+                    use script::dom::node::LayoutNodeHelpers;
+                    assert!(node.is_in_doc());
                     if node.needs_dirty_on_viewport_size_changed() {
                         let el = node.as_element().unwrap();
                         el.mutate_data().map(|mut d| d.restyle()
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 3e2de9b..f0e00c7 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -290,6 +290,7 @@ impl Node {
 
         self.owner_doc().content_and_heritage_changed(self, NodeDamage::OtherNodeDamage);
         child.owner_doc().content_and_heritage_changed(child, NodeDamage::OtherNodeDamage);
+        assert!(!child.has_dirty_descendants());
     }
 
     pub fn to_untrusted_node_address(&self) -> UntrustedNodeAddress {
@@ -419,6 +420,9 @@ impl Node {
             flags.remove(flag);
         }
 
+        if value && flag.contains(HAS_DIRTY_DESCENDANTS) {
+            assert!(self.is_in_doc());
+        }
         self.flags.set(flags);
     }
 
@@ -427,6 +431,7 @@ impl Node {
     }
 
     pub fn set_has_dirty_descendants(&self, state: bool) {
+        assert!(self.is_in_doc());
         self.set_flag(HAS_DIRTY_DESCENDANTS, state)
     }
 
diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs
index dca0750..659d1c4 100644
--- a/components/script/layout_wrapper.rs
+++ b/components/script/layout_wrapper.rs
@@ -36,7 +36,7 @@ use dom::bindings::js::LayoutJS;
 use dom::characterdata::LayoutCharacterDataHelpers;
 use dom::document::{Document, LayoutDocumentHelpers, PendingRestyle};
 use dom::element::{Element, LayoutElementHelpers, RawLayoutElementHelpers};
-use dom::node::{CAN_BE_FRAGMENTED, DIRTY_ON_VIEWPORT_SIZE_CHANGE, HAS_DIRTY_DESCENDANTS};
+use dom::node::{CAN_BE_FRAGMENTED, DIRTY_ON_VIEWPORT_SIZE_CHANGE, HAS_DIRTY_DESCENDANTS, IS_IN_DOC};
 use dom::node::{LayoutNodeHelpers, Node};
 use dom::text::Text;
 use gfx_traits::ByteIndex;
@@ -131,6 +131,12 @@ impl<'ln> ServoLayoutNode<'ln> {
     pub fn as_document(&self) -> Option<ServoLayoutDocument<'ln>> {
         self.node.downcast().map(ServoLayoutDocument::from_layout_js)
     }
+
+    pub fn is_in_doc(&self) -> bool {
+        unsafe {
+            self.node.get_flag(IS_IN_DOC)
+        }
+    }
 }
 
 impl<'ln> NodeInfo for ServoLayoutNode<'ln> {
@@ -400,6 +406,8 @@ impl<'le> TElement for ServoLayoutElement<'le> {
     }
 
     unsafe fn set_dirty_descendants(&self) {
+        assert!(self.as_node().node.get_flag(IS_IN_DOC));
+
         self.as_node().node.set_flag(HAS_DIRTY_DESCENDANTS, true)
     }

It's hitting the one added to set_dirty_descendants:

* thread #76: tid = 0x15ef7e, 0x0000000105705434 servo`std::panicking::rust_panic + 4 at panicking.rs:482, stop reason = breakpoint 1.1
    frame #0: 0x0000000105705434 servo`std::panicking::rust_panic + 4 at panicking.rs:482
    frame #1: 0x0000000105705405 servo`std::panicking::rust_panic_with_hook + 437 at panicking.rs:467
    frame #2: 0x0000000101ab0834 servo`std::panicking::begin_panic<&str>(msg=&str at 0x000000012d420070, file_line=0x0000000106f4dba8) + 164 at panicking.rs:413
  * frame #3: 0x0000000102b2573a servo`script::layout_wrapper::{{impl}}::set_dirty_descendants(self=0x000000012d420138) + 106 at layout_wrapper.rs:409
    frame #4: 0x0000000102b25cd6 servo`script::layout_wrapper::{{impl}}::note_dirty_descendant(self=0x000000012d421058) + 86 at layout_wrapper.rs:482
    frame #5: 0x000000010120e5f3 servo`layout_thread::{{impl}}::handle_reflow(self=0x000000012d422f18, data=0x000000012d422088, possibly_locked_rw_data=0x000000012d422ed0) + 9475 at lib.rs:1125
    frame #6: 0x00000001012087ee servo`layout_thread::{{impl}}::handle_request_helper::{{closure}} + 62 at lib.rs:654
    frame #7: 0x0000000100fdeae0 servo`profile_traits::time::profile<(category=LayoutPerform, meta=Option<profile_traits::time::TimerMetadata> at 0x000000012d421ca8, profiler_chan=ProfilerChan at 0x000000012d421ca0, callback=closure at 0x000000012d421c80),closure> + 528 at time.rs:119
    frame #8: 0x0000000101207d0f servo`layout_thread::{{impl}}::handle_request_helper(self=0x000000012d422f18, request=Msg at 0x000000012d4221f0, possibly_locked_rw_data=0x000000012d422ed0) + 1743 at lib.rs:651
    frame #9: 0x00000001012069f6 servo`layout_thread::{{impl}}::handle_request(self=0x000000012d422f18, possibly_locked_rw_data=0x000000012d422ed0) + 2070 at lib.rs:590
    frame #10: 0x0000000101205916 servo`layout_thread::{{impl}}::start(self=LayoutThread at 0x000000012d423058) + 326 at lib.rs:503
    frame #11: 0x0000000101201d1e servo`layout_thread::{{impl}}::create::{{closure}}::{{closure}} + 126 at lib.rs:285
    frame #12: 0x0000000100fde56f servo`profile_traits::mem::{{impl}}::run_with_memory_reporting<closure,fn(self=0x000000012d4240cc, f=closure at 0x000000012d4238b0, reporter_name=String at 0x000000012d423898, channel_for_reporter=Sender<script_layout_interface::message::Msg> at 0x000000012d423888, msg=0x0000000000000000) -> script_layout_interface::message::Msg,script_layout_interface::message::Msg,std::sync::mpsc::Sender<script_layout_interface::message::Msg>> + 911 at mem.rs:63
    frame #13: 0x00000001012023e6 servo`layout_thread::{{impl}}::create::{{closure}} + 1670 at lib.rs:284
    frame #14: 0x00000001011da60c servo`std::panic::{{impl}}::call_once<(self=AssertUnwindSafe<closure> at 0x000000012d424258, _args=<unavailable>),closure> + 124 at panic.rs:295
    frame #15: 0x000000010105c460 servo`std::panicking::try::do_call<std::panic::AssertUnwindSafe<closure>,(data=0x000000012d424838)> + 384 at panicking.rs:356
    frame #16: 0x000000010570624b servo`panic_unwind::__rust_maybe_catch_panic + 27 at lib.rs:97
    frame #17: 0x000000010105aa31 servo`std::panicking::try<(f=AssertUnwindSafe<closure> at 0x000000012d424938),std::panic::AssertUnwindSafe<closure>> + 305 at panicking.rs:332
    frame #18: 0x00000001010596d6 servo`std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure>,(f=AssertUnwindSafe<closure> at 0x000000012d424ae8)> + 134 at panic.rs:351
    frame #19: 0x000000010105a611 servo`std::thread::{{impl}}::spawn::{{closure}}<closure,()> + 401 at mod.rs:287
    frame #20: 0x00000001010ea35a servo`alloc::boxed::{{impl}}::call_box<(self=0x000000011e226140, args=<unavailable>),closure> + 74 at boxed.rs:595
    frame #21: 0x00000001057042f5 servo`std::sys::imp::thread::{{impl}}::new::thread_start [inlined] alloc::boxed::{{impl}}::call_once<(),()> + 37 at boxed.rs:605
    frame #22: 0x00000001057042ef servo`std::sys::imp::thread::{{impl}}::new::thread_start [inlined] std::sys_common::thread::start_thread + 15 at thread.rs:21
    frame #23: 0x00000001057042e0 servo`std::sys::imp::thread::{{impl}}::new::thread_start + 16 at thread.rs:84
    frame #24: 0x00007fff8e409899 libsystem_pthread.dylib`_pthread_body + 138
    frame #25: 0x00007fff8e40972a libsystem_pthread.dylib`_pthread_start + 137
    frame #26: 0x00007fff8e40dfc9 libsystem_pthread.dylib`thread_start + 13
@jdm
Copy link
Member Author

@jdm jdm commented Dec 29, 2016

I think I see one problem - the pending restyle vector in Document can contain nodes that have been removed from the tree, since they're never removed from the vector except by layout.

@jdm
Copy link
Member Author

@jdm jdm commented Dec 30, 2016

diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 79acb69..4a2b998 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -67,7 +67,7 @@ use dom::keyboardevent::KeyboardEvent;
 use dom::location::Location;
 use dom::messageevent::MessageEvent;
 use dom::mouseevent::MouseEvent;
-use dom::node::{self, CloneChildrenFlag, Node, NodeDamage, window_from_node};
+use dom::node::{self, CloneChildrenFlag, Node, NodeDamage, window_from_node, IS_IN_DOC, LayoutNodeHelpers};
 use dom::nodeiterator::NodeIterator;
 use dom::nodelist::NodeList;
 use dom::pagetransitionevent::PageTransitionEvent;
@@ -1790,7 +1790,7 @@ impl LayoutDocumentHelpers for LayoutJS<Document> {
     #[allow(unrooted_must_root)]
     unsafe fn drain_pending_restyles(&self) -> Vec<(LayoutJS<Element>, PendingRestyle)> {
         let mut elements = (*self.unsafe_get()).pending_restyles.borrow_mut_for_layout();
-        let result = elements.drain().map(|(k, v)| (k.to_layout(), v)).collect();
+        let result = elements.drain().map(|(k, v)| (k.to_layout(), v)).filter(|&(ref k, _)| k.upcast::<Node>().get_flag(IS_IN_DOC)).collect();
         result
     }

diff --git a/components/script/layout_wrapper.rs b/components/script/layout_wrapper.rs
index e6c38aa..b1bde4e 100644
--- a/components/script/layout_wrapper.rs
+++ b/components/script/layout_wrapper.rs
@@ -36,7 +36,7 @@ use dom::bindings::js::LayoutJS;
 use dom::characterdata::LayoutCharacterDataHelpers;
 use dom::document::{Document, LayoutDocumentHelpers, PendingRestyle};
 use dom::element::{Element, LayoutElementHelpers, RawLayoutElementHelpers};
-use dom::node::{CAN_BE_FRAGMENTED, DIRTY_ON_VIEWPORT_SIZE_CHANGE, HAS_DIRTY_DESCENDANTS};
+use dom::node::{CAN_BE_FRAGMENTED, DIRTY_ON_VIEWPORT_SIZE_CHANGE, HAS_DIRTY_DESCENDANTS, IS_IN_DOC};
 use dom::node::{LayoutNodeHelpers, Node};
 use dom::text::Text;
 use gfx_traits::ByteIndex;
@@ -400,6 +400,7 @@ impl<'le> TElement for ServoLayoutElement<'le> {
     }

     unsafe fn set_dirty_descendants(&self) {
+        assert!(self.as_node().node.get_flag(IS_IN_DOC));
         self.as_node().node.set_flag(HAS_DIRTY_DESCENDANTS, true)
     }

This patch appears to fix the problem for me.

@emilio
Copy link
Member

@emilio emilio commented Dec 31, 2016

Hmm... Good catch. I guess constructing a test case isn't terribly hard.

That patch looks ok to me (with a comment in the filter call). Do you have cycles to do that? Otherwise i can try to build the test case and get that landed.

@jdm jdm added the C-has-patch label Jan 2, 2017
@jdm jdm mentioned this issue Jan 4, 2017
4 of 4 tasks complete
@jdm jdm removed the C-has-patch label Jan 4, 2017
@emilio emilio added the C-has open PR label Jan 4, 2017
bors-servo added a commit that referenced this issue Jan 4, 2017
Avoid restyling elements that aren't in a document

- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix #14480
- [X] There are tests for these changes

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/14845)
<!-- Reviewable:end -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

3 participants
You can’t perform that action at this time.