Closed Bug 306482 Opened 20 years ago Closed 20 years ago

Chatzilla accesses DOM objects from off the UI thread

Categories

(Other Applications Graveyard :: ChatZilla, defect)

x86
Linux
defect
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: bzbarsky, Assigned: rginda)

Details

(Whiteboard: [cz-0.9.69])

Attachments

(1 file)

STEPS TO REPRODUCE: start chatzilla ACTUAL RESULTS: ###!!! ASSERTION: nsGlobalWindow not thread-safe: '_mOwningThread.GetThread() == PR_GetCurrentThread()', file ../../../../mozilla/dom/src/base/nsGlobalWindow.cpp, line 481 EXPECTED RESULTS: no asserts OTHER INFORMATION: The problem is that chatzilla does: 132 var dnsRecord = this._dnsSvc.asyncResolve(host, false, listener, null); in dcc.js. The documentation for asyncResolve's last arg says: 61 * @param aListenerEventTarget 62 * optional parameter (may be null). if non-null, this parameter 63 * specifies the nsIEventTarget of the thread on which the listener's 64 * onLookupComplete should be called. however, if this parameter is 65 * null, then onLookupComplete will be called on an unspecified 66 * thread (possibly recursively). In other words, Chatzilla should be passing in the UI thread event queue here, not null.
Please be careful what you accuse. null was passed specifically because the code being called does not touch any DOM stuff knowingly. You'll need to identify EXACTLY what part of the lookup callback touches DOM before I care.
Any function from a script loaded in a DOM context (loaded from a window, not a JS component) must be main-thread only, because the global object is the DOM window object. And please, bz is not "accusing" anything, he's filing a fairly simple threadsafety bug report based on an assertion.
FWIW, here's a quick code snipet that can be used to get the proper value for the nsIEventTarget parameter: var eqs = Components.classes["@mozilla.org/event-queue-service;1"]. getService(Components.interfaces.nsIEventQueueService); var eq = eqs.getSpecialEventQueue(eqs.CURRENT_THREAD_EVENT_QUEUE);
I would have thought simply doing the steps to reproduce would have shown you the problem, but since you insist here is the stack: #0 0xb7f19f07 in nsDebug::Assertion (aStr=0xb6af19c4 "nsGlobalWindow not thread-safe", aExpr=0xb6af1990 "_mOwningThread.GetThread() == PR_GetCurrentThread()", aFile=0xb6af184c "../../../../mozilla/dom/src/base/nsGlobalWindow.cpp", aLine=481) at nsDebug.cpp:108 #1 0xb688dbd1 in nsGlobalWindow::AddRef (this=0xb22abb00) at ../../../../mozilla/dom/src/base/nsGlobalWindow.cpp:481 #2 0xb68a5f91 in nsGlobalChromeWindow::AddRef (this=0xb22abb00) at ../../../../mozilla/dom/src/base/nsGlobalWindow.cpp:6845 #3 0xb688db2b in nsGlobalWindow::QueryInterface (this=0xb22abb00, aIID=@0xb784ab10, aInstancePtr=0xb0cfce80) at ../../../../mozilla/dom/src/base/nsGlobalWindow.cpp:478 #4 0xb68a5f46 in nsGlobalChromeWindow::QueryInterface (this=0xb22abb00, aIID=@0xb784ab10, aInstancePtr=0xb0cfcec0) at ../../../../mozilla/dom/src/base/nsGlobalWindow.cpp:6843 #5 0xb7f192dc in nsQueryInterface::operator() (this=0xb0cfced4, aIID=@0xb784ab10, answer=0xb0cfcec0) at nsCOMPtr.cpp:47 #6 0xb784381f in nsCOMPtr<nsIScriptObjectPrincipal>::assign_from_qi (this=0xb0cfcf20, qi={mRawPtr = 0xb22abb28}, aIID=@0xb784ab10) at ../../dist/include/xpcom/nsCOMPtr.h:1232 #7 0xb7841f06 in nsCOMPtr<nsIScriptObjectPrincipal>::operator= (this=0xb0cfcf20, rhs= {mRawPtr = 0xb22abb28}) at ../../dist/include/xpcom/nsCOMPtr.h:731 #8 0xb783a8a2 in nsScriptSecurityManager::doGetObjectPrincipal (aCx=0x8524830, aObj=0xb2256618) at ../../../mozilla/caps/src/nsScriptSecurityManager.cpp:2100 #9 0xb783a3c8 in nsScriptSecurityManager::GetFunctionObjectPrincipal (cx=0x8524830, obj=0xb1a31418, fp=0xb0cfdf20, rv=0xb0cfd2bc) at ../../../mozilla/caps/src/nsScriptSecurityManager.cpp:1961 #10 0xb783a497 in nsScriptSecurityManager::GetFramePrincipal (cx=0x8524830, fp=0xb0cfdf20, rv=0xb0cfd2bc) at ../../../mozilla/caps/src/nsScriptSecurityManager.cpp:1985 #11 0xb783a58e in nsScriptSecurityManager::GetPrincipalAndFrame (cx=0x8524830, frameResult=0xb0cfd020, rv=0xb0cfd2bc) at ../../../mozilla/caps/src/nsScriptSecurityManager.cpp:2016 #12 0xb783a73b in nsScriptSecurityManager::GetSubjectPrincipal (cx=0x8524830, rv=0xb0cfd2bc) at ../../../mozilla/caps/src/nsScriptSecurityManager.cpp:2058 #13 0xb783555f in nsScriptSecurityManager::CheckPropertyAccessImpl (this=0x8233d38, aAction=0, aCallContext=0xb0cfd5c0, cx=0x8524830, aJSObject=0xb1a31660, aObj=0x85413d8, aTargetURI=0x0, aClassInfo=0x0, aClassName=0x0, aProperty=-1305190004, aCachedClassPolicy=0x0) at ../../../mozilla/caps/src/nsScriptSecurityManager.cpp:606 #14 0xb783d486 in nsScriptSecurityManager::CanAccess (this=0x8233d38, aAction=0, aCallContext=0xb0cfd5c0, cx=0x8524830, aJSObject=0xb1a31660, aObj=0x85413d8, aClassInfo=0x0, aPropertyName=-1305190004, aPolicy=0x0) at ../../../mozilla/caps/src/nsScriptSecurityManager.cpp:2800 #15 0xb79a584c in XPCWrappedNative::CallMethod (ccx=@0xb0cfd5c0, mode=CALL_METHOD) at ../../../../../mozilla/js/src/xpconnect/src/xpcwrappednative.cpp:1792 #16 0xb79b0e33 in XPC_WN_CallMethod (cx=0x8524830, obj=0xb1a31660, argc=0, argv=0x85a8fbc, vp=0xb0cfd770) at ../../../../../mozilla/js/src/xpconnect/src/xpcwrappednativejsops.cpp:1402 #17 0xb7e13a5f in js_Invoke (cx=0x8524830, argc=0, flags=0) at ../../../mozilla/js/src/jsinterp.c:1174 #18 0xb7e23442 in js_Interpret (cx=0x8524830, pc=0xb1e813c5 ":", result=0xb0cfdf0c) at ../../../mozilla/js/src/jsinterp.c:3469 #19 0xb7e13ae1 in js_Invoke (cx=0x8524830, argc=3, flags=2) at ../../../mozilla/js/src/jsinterp.c:1194 #20 0xb799ebf8 in nsXPCWrappedJSClass::CallMethod (this=0xb1add638, wrapper=0xb1743858, methodIndex=3, info=0xb1adcbc8, nativeParams=0xb0cfe2a0) at ../../../../../mozilla/js/src/xpconnect/src/xpcwrappedjsclass.cpp:1339 #21 0xb799790d in nsXPCWrappedJS::CallMethod (this=0xb1743858, methodIndex=3, info=0xb1adcbc8, params=0xb0cfe2a0) at ../../../../../mozilla/js/src/xpconnect/src/xpcwrappedjs.cpp:461 #22 0xb7fc5096 in PrepareAndDispatch (methodIndex=3, self=0xb1743858, args=0xb0cfe344) at ../../../../../../../mozilla/xpcom/reflect/xptcall/src/md/unix/xptcstubs_gcc_x86_unix.cpp:100 #23 0xb770a9bd in nsDNSAsyncRequest::OnLookupComplete (this=0xb1743890, resolver=0x8253950, hostRecord=0xb17438c8, status=0) at ../../../../mozilla/netwerk/dns/src/nsDNSService2.cpp:223 The JS stack looks like: 0 [native frame] 1 _onLookupComplete(request = [xpconnect wrapped nsICancelable @ 0x85e0560 (native @ 0xb3c6a6c4)], record = [xpconnect wrapped nsIDNSRecord @ 0x85dd6b0 (native @ 0x85eb8d0)], status = 0) ["chrome://chatzilla/content/lib/js/dcc.js":125] this = [object Object] 2 [native frame] So as Benjamin pointed out the problem is that any call through XPConnect (the hasMore call here, for example) will try to look up the security context of the caller, and for code in a DOM window this is the DOM window; as a result, operations will be performed on the DOM window while attempting to establish that it's allowed to make this call.
(In reply to comment #4) > I would have thought simply doing the steps to reproduce would have shown you > the problem, but since you insist here is the stack: I would have thought you, of all people, would understand the need for a stack with an assertion failure. bsmedberg, thank you for totally failing to say anything consturctive. Also, this bug is mislabeled. ChatZilla does NOT touch DOM. I will reserve judement on XPConnect's sanity until a later date after people have stopped being such idiots.
> I would have thought you, of all people, would understand the need for a stack Why, when the failure is 100% reproducible so anyone with a debugger can just get the stack? > Also, this bug is mislabeled. ChatZilla does NOT touch DOM. It does, because it runs code on a DOM JS context. That means that properties of the JS context might be needed at any time for whatever internal purpose, and there is no way to avoid that. I'm not sure what makes you think people are being "idiots" and what's happened to make you so upset, but feel free to send me personal mail about it if you want...
> Why, when the failure is 100% reproducible so anyone with a debugger can just > get the stack? Since when does everyone automatically have a debug build and a debugger available to them? I happen to be away from my home (never mind my computer) for a few days, and I don't even know if Mozilla will build on my build box *anyway* (it has a great knack of totally failing). And before you ask why I didn't wait until I got back, it's because I wanted to know how code that very specifically did NOT go near DOM managed to trigger such an assertion. Obviously, the sheer weirdness of XPConnect was not taken into account. > It does, because it runs code on a DOM JS context. That means that properties > of the JS context might be needed at any time for whatever internal purpose, and > there is no way to avoid that. *XPConnect* touches DOM, not ChatZilla. The fact XPConnect's design is flawed is a separate issue. I hope you realise that this makes real threading in JS impossible, too - even though the API for starting a new thread is scriptable. As for idiots, that's not you bz. I'm also not upset, just annoyed at the stupidity of certain people (again, not you) within the Mozilla project. Either way, they should be able to work it out themselves without me expalining here.
Yeah, I've had a lot of trouble trying to use XPConnect on a background thread as well. I tried to execute PAC on a background thread, but I couldn't get XPConnect to work with me on that. I eventually gave up. I think it's best to keep JS on the main thread. At least in this case, there's no real benefit to using a background thread for receiving the DNS lookup result.
What would it take to get the window object to be threadsafe? I suppose probably the generic element would need a beating to do most of it, if it is not already. Somewhat related, how does line 608 here work without causing an assertion? http://lxr.mozilla.org/seamonkey/source/extensions/irc/js/lib/irc.js#602 I'm reasonably sure Necko calls us on its own thread (the stream listener in connection-xpcom.js calls onStreamDataAvailable), but that call in turn calls a native function to read the data from the input stream itself. Does Necko not call stream listeners on its thread as claimed previously, or does reafing from an input stream not need any security checks?
> What would it take to get the window object to be threadsafe? probably a lot of work... and it is probably well beyond the scope of the Mozilla 1.8 branch. > Somewhat related, how does line 608 here work without causing an assertion? > > http://lxr.mozilla.org/seamonkey/source/extensions/irc/js/lib/irc.js#602 > > I'm reasonably sure Necko calls us on its own thread... Does Necko not > call stream listeners on its thread as claimed previously not sure where that was claimed. necko calls stream listeners on the thread that called asyncOpen, which is always the main application thread.
I wasn't for a minute suggesting any such thing for the 1.8 branch. I guess the Necko thing must just be something that someone once said, and has been passed on from there. I've heard it time and again, though, so Bob only knows how it got so commonly known when it is wrong (such is the way of documentation-by-word-of-mouth, for lack of anything better).
> The fact XPConnect's design is flawed XPConnect can't very well avoid touching the execution context; I don't know what design would allow it to do that, exactly. > I hope you realise that this makes real threading in JS impossible, too It's quite possible inside a JS component, which doesn't come anywhere near the DOM... > What would it take to get the window object to be threadsafe? A huge amount of work, if you mean making the DOM threadsafe. If nothing else, there are lots of static vars used in gklayout without any sort of locking. Worse yet, just doing this straight off would be a fairly big performance hit that I don't think we're willing to take.
people have actively refused to allow that change because threadsafety=perf hit.
There should be no need for XPConnect to touch any objects involved within the context of execution - only the context itself - when checking if the context has permission X. Anyway, I don't really care who you blame within the DOM/Spidermonkey/XPConnect mess - it's imaterial, now that we've established that JS threading simply wont work today. Also, I didn't say DOM, I said window object. From the POV of making the "Mozilla Platform" not suck, though, I suppose you would really need to do the entire thing.
> only the context itself The context is the window... This is nothing to do with XPConnect and everything to do with the way the DOM sets up its scripting. Again JS threading works fine. Simply don't define any of the scripts involved on a DOM window.
Note: all of the core code *will* be ending up within the scope of a JS XPCOM Component prior to CZ 1.0, so this will revert back to proper threading at that point.
Attachment #195729 - Flags: review?(rginda)
fwiw, the exact part of this function that causes this assertion is the calling of getService, a global function here. that accesses the global object, which is the window.
Uh, you mean the getService call which does not exist? The stack also shows it is the access of a method via XPConnect that triggers the assertion.
Comment on attachment 195729 [details] [diff] [review] Use main thread to work around DOM suckage r=rginda
Attachment #195729 - Flags: review?(rginda) → review+
Checked in --> FIXED.
Status: NEW → RESOLVED
Closed: 20 years ago
Resolution: --- → FIXED
(In reply to comment #18) > Uh, you mean the getService call which does not exist? The stack also shows it > is the access of a method via XPConnect that triggers the assertion. oops, sorry, I suck...
Whiteboard: [cz-0.9.69]
Product: Other Applications → Other Applications Graveyard
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: