Summary: | IDBTransaction and IDBRequest can be deleted while ScriptExecutionContext is iterating....which is bad | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Product: | WebKit | Reporter: | Jeremy Orlow <jorlow> | ||||||||||||||
Component: | New Bugs | Assignee: | Jeremy Orlow <jorlow> | ||||||||||||||
Status: | RESOLVED FIXED | ||||||||||||||||
Severity: | Normal | CC: | abarth, andreip, ap, commit-queue, dglazkov, dgrogan, eric, hans, jamesr, japhet, jorlow, mihaip, webkit.review.bot | ||||||||||||||
Priority: | P2 | ||||||||||||||||
Version: | 528+ (Nightly build) | ||||||||||||||||
Hardware: | PC | ||||||||||||||||
OS: | OS X 10.5 | ||||||||||||||||
Attachments: |
|
Description
Jeremy Orlow
2011-01-19 06:52:31 PST
Alexey Proskuryakov is ap@webkit.org I believe FWIW, I'm currently writing this patch and I'm finding that it's an awful lot of similar/duplicate code to ActiveDOMObject. It's really making me think we should just make the changes to ADO itself. Created attachment 80158 [details]
Patch
Attachment 80158 [details] did not build on chromium: Build output: http://queues.webkit.org/results/7540357 Attachment 80158 [details] did not build on chromium: Build output: http://queues.webkit.org/results/7542347 Comment on attachment 80158 [details] Patch Did IDBActiveDOMObject.h slip out of this patch? I can't find it, and that seems to be what makes the bots red. > Source/WebCore/ChangeLog:9 > + ActiveDOMObject. The former has less implications the latter and iterates nit: less implications *than* the latter > Source/WebCore/storage/IDBActiveDOMObject.cpp:2 > + * Copyright (C) 2010 Google Inc. All rights reserved. nit: 2011? > Source/WebCore/storage/IDBActiveDOMObject.cpp:13 > + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of I thought this should be a two-clause thing nowadays? (In reply to comment #6) > (From update of attachment 80158 [details]) > Did IDBActiveDOMObject.h slip out of this patch? I can't find it, and that seems to be what makes the bots red. oops...will make sure it's added > > Source/WebCore/ChangeLog:9 > > + ActiveDOMObject. The former has less implications the latter and iterates > > nit: less implications *than* the latter oops..will fix > > Source/WebCore/storage/IDBActiveDOMObject.cpp:2 > > + * Copyright (C) 2010 Google Inc. All rights reserved. > > nit: 2011? k > > Source/WebCore/storage/IDBActiveDOMObject.cpp:13 > > + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of > > I thought this should be a two-clause thing nowadays? k...will change to this: http://webkit.org/coding/bsd-license.html Created attachment 80207 [details]
new
Weird....webkit-patch refuses to upload that file....created a patch manually.
Alexey, can you take a look at the general approach of IDBActiveDOMObject here and give your comments? As I mentioned, I want to have something in by EOW even if we need to continue iterating after that. Comment on attachment 80207 [details]
new
I talked to Nate and JamesR and we came up with something that I think will be far superior and not require all the IDBActiveDOMObject stuff.
IDBTransaction will be an ActiveDOMObject. IDBRequest won't be. I'll be able to get rid of the self ref for request. And IDBTransaction can probably use the built in machinery in ActiveDOMObject for that.
Will try to upload something tomorrow.
Ok, after more experimenting and chatting with people, I'm pretty positive of a few things: * IDBRequest needs to have access to a ScriptExecutionContext* and needs to know when stop is called so it can null out the pointer when it's invalid. * IDBTransaction needs the same + it needs to abort its transaction on ::stop and disable suspension while transactions are running. * IDBTransaction and IDBTransactionBackend both depend on each other (well, technically the former implements the IDBTransactionCallbacks interface and the latter actually owns that). The transaction finishing is, as far as I can tell, the only suitable time to break the reference cycles. As far as I can tell, the only solution is to allow IDBTransaction to be deleted while the ::stop()s are being called. So, first of all, how do we allow ::stop() to be called and handle the ScriptExecutionContext* bit? Well, to me, these are clearly ActiveDOMObjects even if the name of the class needs to be changed. (If so, please make a suggestion for a new name? Or we can do it in a later patch.) Next, assuming we have to "allow IDBTransaction to be deleted while the ::stop()s are being called", I see a couple options: 1) ActiveDOMObject could iterate on a copy. We do this fairly often. It shouldn't be too bad perf wise since we should never have too many. 2) We could make the IDBTransactionBackend -> IDBTransaction connection weak. 3) We could switch its HashMap to be some data structure which would handle the iteration fine. 4) We could make HashMap handle such iteration. 5) We could fork ActiveDOMObject and create some base type for things that can be deleted during iteration. Personally, this seems like premature optimization to me. Personally I think #1 is best because the rest are making things more difficult than necessary. But #2 would work and I had actually considered doing it at an earlier point. Note that https://bug-52366-attachments.webkit.org/attachment.cgi?id=78812 implemented #1. Oops + mihai and jamesr. If you had any thoughts about comment #11, they'd be greatly appreciated. Created attachment 80871 [details]
reposting my original solution to this problem
I'm reposting my original solution to the problem as I think it's the best answer.
(In reply to comment #11) > Ok, after more experimenting and chatting with people, I'm pretty positive of a few things: > * IDBRequest needs to have access to a ScriptExecutionContext* and needs to know when stop is called so it can null out the pointer when it's invalid. > * IDBTransaction needs the same + it needs to abort its transaction on ::stop and disable suspension while transactions are running. > * IDBTransaction and IDBTransactionBackend both depend on each other (well, technically the former implements the IDBTransactionCallbacks interface and the latter actually owns that). The transaction finishing is, as far as I can tell, the only suitable time to break the reference cycles. As far as I can tell, the only solution is to allow IDBTransaction to be deleted while the ::stop()s are being called. > Maybe stupid question: rather than http://trac.webkit.org/browser/trunk/Source/WebCore/storage/IDBTransactionBackendImpl.cpp#L126 could we call onAbort asynchronously (e.g. schedule an event or use a timer)? That means that the cycle would be broken outside of the loop in ScriptExecutionContext::stopActiveDOMObjects() Andrei (In reply to comment #15) > (In reply to comment #11) > > Ok, after more experimenting and chatting with people, I'm pretty positive of a few things: > > * IDBRequest needs to have access to a ScriptExecutionContext* and needs to know when stop is called so it can null out the pointer when it's invalid. > > * IDBTransaction needs the same + it needs to abort its transaction on ::stop and disable suspension while transactions are running. > > * IDBTransaction and IDBTransactionBackend both depend on each other (well, technically the former implements the IDBTransactionCallbacks interface and the latter actually owns that). The transaction finishing is, as far as I can tell, the only suitable time to break the reference cycles. As far as I can tell, the only solution is to allow IDBTransaction to be deleted while the ::stop()s are being called. > > > > > Maybe stupid question: rather than > > http://trac.webkit.org/browser/trunk/Source/WebCore/storage/IDBTransactionBackendImpl.cpp#L126 > > could we call onAbort asynchronously (e.g. schedule an event or use a timer)? That means that the cycle would be broken outside of the loop in ScriptExecutionContext::stopActiveDOMObjects() I'm not sure about that exact location, but having the abort call in IDBTransaction/IDBRequest::stop() seems like a pretty good solution. > * IDBRequest needs to have access to a ScriptExecutionContext* and needs to know when stop is called so it can null out the pointer when it's invalid.
The ScriptExecutionContext pointer is normally zeroed out in contextDestroyed(), not in stop().
(In reply to comment #17) > > * IDBRequest needs to have access to a ScriptExecutionContext* and needs to know when stop is called so it can null out the pointer when it's invalid. > > The ScriptExecutionContext pointer is normally zeroed out in contextDestroyed(), not in stop(). Oops! Good catch. I guess I'll add a flag to keep track of it then. (In reply to comment #18) > (In reply to comment #17) > > > * IDBRequest needs to have access to a ScriptExecutionContext* and needs to know when stop is called so it can null out the pointer when it's invalid. > > > > The ScriptExecutionContext pointer is normally zeroed out in contextDestroyed(), not in stop(). > > Oops! Good catch. I guess I'll add a flag to keep track of it then. Er...I thought this was the other bug where I have code that assumes this. Anyway, you're right that it's contextDestroyed not stop, but I don't think that actually changes anything in this case. ......hm.... Actually, can't we just do what Geoffrey suggested in https://bugs.webkit.org/show_bug.cgi?id=52719#c5 in contextDestroyed and then do the work that could lead to destruction in contextDestroyed? It seems like this should be permissible even if you're going to argue that destruction of ActiveDOMObjects during the other points of iteration isn't. Thoughts? > can't we just do what Geoffrey suggested in https://bugs.webkit.org/show_bug.cgi?id=52719#c5 in contextDestroyed
Sounds good to me, as long as we have an assertion that new ActiveDOMObjects aren't added during contextDestroyed() iteration. Again, if we could have an assertion that no JS is executed during the iteration, that would be better yet. Maybe ScriptController is already dysfunctional at this point?
*** Bug 52366 has been marked as a duplicate of this bug. *** Created attachment 80952 [details]
Patch
Comment on attachment 80952 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=80952&action=review > Source/WebCore/dom/ScriptExecutionContext.cpp:261 > + ASSERT(!m_iteratingActiveDOMObjects); > + ASSERT(!m_inDestructor); Here and elsewhere: Should we be doing something more than just ASSERTing in debug? This seems like it'll be a security problem if we do ever hit this case in release builds. LGTM otherwise. (In reply to comment #23) > (From update of attachment 80952 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=80952&action=review > > > Source/WebCore/dom/ScriptExecutionContext.cpp:261 > > + ASSERT(!m_iteratingActiveDOMObjects); > > + ASSERT(!m_inDestructor); > > Here and elsewhere: Should we be doing something more than just ASSERTing in debug? This seems like it'll be a security problem if we do ever hit this case in release builds. > > LGTM otherwise. Good point! Although this should never happen in theory, if it did, it could turn into a security vulnerability (due to the dangling ScriptExecutionContext pointer). It seems there's really nothing good to do in such a case, so we should probably just crash in such a case. Will make the change. Created attachment 80984 [details]
Patch
Created attachment 80990 [details]
Patch
Comment on attachment 80990 [details]
Patch
Ok.
Is it worth an explanatory comment as to why we're crashing instead of just asserting?
Comment on attachment 80990 [details]
Patch
If someone wants to remove it, I'd hope they'd look at the change that added it and thus see this thread. That seems to be the WebKit way anyhow...for better or worse.
Comment on attachment 80990 [details] Patch Clearing flags on attachment: 80990 Committed r77456: <http://trac.webkit.org/changeset/77456> All reviewed patches have been landed. Closing bug. |