WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
233945
ActiveDOMObject::suspendIfNeeded() should not be called within constructors
https://bugs.webkit.org/show_bug.cgi?id=233945
Summary
ActiveDOMObject::suspendIfNeeded() should not be called within constructors
Antoine Quint
Reported
2021-12-07 11:51:57 PST
ActiveDOMObject::suspendIfNeeded() should not be called within constructors
Attachments
Patch
(36.91 KB, patch)
2021-12-07 11:52 PST
,
Antoine Quint
no flags
Details
Formatted Diff
Diff
Patch for landing
(28.59 KB, patch)
2021-12-14 03:12 PST
,
Antoine Quint
no flags
Details
Formatted Diff
Diff
Patch
(18.53 KB, patch)
2021-12-15 08:24 PST
,
Antoine Quint
no flags
Details
Formatted Diff
Diff
Patch
(20.05 KB, patch)
2021-12-15 09:42 PST
,
Antoine Quint
ews-feeder
: commit-queue-
Details
Formatted Diff
Diff
Patch
(20.42 KB, patch)
2021-12-15 11:34 PST
,
Antoine Quint
no flags
Details
Formatted Diff
Diff
Patch
(20.29 KB, patch)
2021-12-15 12:22 PST
,
Antoine Quint
no flags
Details
Formatted Diff
Diff
Patch for landing
(20.31 KB, patch)
2021-12-15 12:46 PST
,
Antoine Quint
ews-feeder
: commit-queue-
Details
Formatted Diff
Diff
Patch for landing
(19.96 KB, patch)
2021-12-15 22:21 PST
,
Antoine Quint
no flags
Details
Formatted Diff
Diff
Patch
(45.08 KB, patch)
2021-12-16 05:17 PST
,
Antoine Quint
no flags
Details
Formatted Diff
Diff
Patch
(40.51 KB, patch)
2021-12-16 06:20 PST
,
Antoine Quint
no flags
Details
Formatted Diff
Diff
Patch for landing
(38.82 KB, patch)
2021-12-17 00:10 PST
,
Antoine Quint
no flags
Details
Formatted Diff
Diff
Patch
(5.62 KB, patch)
2021-12-17 04:11 PST
,
Antoine Quint
no flags
Details
Formatted Diff
Diff
Patch
(7.05 KB, patch)
2021-12-17 04:23 PST
,
Antoine Quint
no flags
Details
Formatted Diff
Diff
Show Obsolete
(12)
View All
Add attachment
proposed patch, testcase, etc.
Antoine Quint
Comment 1
2021-12-07 11:52:35 PST
Created
attachment 446215
[details]
Patch
Chris Dumez
Comment 2
2021-12-07 11:54:29 PST
Comment on
attachment 446215
[details]
Patch r=me assuming the bots are happy
Darin Adler
Comment 3
2021-12-07 12:08:00 PST
Comment on
attachment 446215
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=446215&action=review
Really great patch. Too bad we can’t get the compiler or an assertion to catch this mistake, but this is nicely thorough. Maybe we should rename this function suspendIfNeededDoNotCallInConstructor (just kidding, but maybe not kidding).
> Source/WebCore/Modules/cache/DOMCache.h:40 > + static Ref<DOMCache> create(ScriptExecutionContext&, String&&, uint64_t, Ref<CacheStorageConnection>&&);
Not sure that we should remove *all* of these names. The argument names "name" and "identifier" are probably still helpful.
> Source/WebCore/Modules/geolocation/Geolocation.cpp:137 > - geolocation.get().suspendIfNeeded(); > + geolocation->suspendIfNeeded();
Ah, brevity competes with "looks like a risky pointer dereference, but is not". I think the more terse version is better, and it’s what we use almost everywhere, but I am conflicted. There’s something cool about ".get()." not looking like a pointer is involved.
Antoine Quint
Comment 4
2021-12-07 12:53:21 PST
(In reply to Darin Adler from
comment #3
)
> Comment on
attachment 446215
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=446215&action=review
> > Really great patch. Too bad we can’t get the compiler or an assertion to > catch this mistake, but this is nicely thorough.
Not quite! There are 17 cases left to fix, those were just the easy ones. I'll look into fixing the other ones piecemeal.
> Maybe we should rename this function suspendIfNeededDoNotCallInConstructor > (just kidding, but maybe not kidding). > > > Source/WebCore/Modules/cache/DOMCache.h:40 > > + static Ref<DOMCache> create(ScriptExecutionContext&, String&&, uint64_t, Ref<CacheStorageConnection>&&); > > Not sure that we should remove *all* of these names. The argument names > "name" and "identifier" are probably still helpful.
Will restore those.
> > Source/WebCore/Modules/geolocation/Geolocation.cpp:137 > > - geolocation.get().suspendIfNeeded(); > > + geolocation->suspendIfNeeded(); > > Ah, brevity competes with "looks like a risky pointer dereference, but is > not". I think the more terse version is better, and it’s what we use almost > everywhere, but I am conflicted. There’s something cool about ".get()." not > looking like a pointer is involved.
I personally don't mind either way, I stumbled onto this code looking at all call sites to ActiveDOMObject::suspendIfNeeded() and it was the only call on a Ref that called .get(). Felt right to put it in line with the rest.
Darin Adler
Comment 5
2021-12-07 15:40:54 PST
(In reply to Antoine Quint from
comment #4
)
> Not quite! There are 17 cases left to fix, those were just the easy ones. > I'll look into fixing the other ones piecemeal.
!!
> Felt right to put it in line with the rest.
Agreed.
Antoine Quint
Comment 6
2021-12-14 03:12:13 PST
Created
attachment 447120
[details]
Patch for landing
Radar WebKit Bug Importer
Comment 7
2021-12-14 11:52:15 PST
<
rdar://problem/86481861
>
EWS
Comment 8
2021-12-15 01:17:16 PST
Committed
r287066
(
245261@main
): <
https://commits.webkit.org/245261@main
> All reviewed patches have been landed. Closing bug and clearing flags on
attachment 447120
[details]
.
Antoine Quint
Comment 9
2021-12-15 03:02:25 PST
Lots to do on this left, this first commit was only part of the work.
Antoine Quint
Comment 10
2021-12-15 08:24:26 PST
Created
attachment 447234
[details]
Patch
Chris Dumez
Comment 11
2021-12-15 08:38:27 PST
Comment on
attachment 447234
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=447234&action=review
r=me with suggestions.
> Source/WebCore/Modules/indexeddb/IDBIndex.cpp:45 > +std::unique_ptr<IDBIndex> IDBIndex::create(ScriptExecutionContext& context, const IDBIndexInfo& info, IDBObjectStore& objectStore)
We may want to return a UniqueRef instead since this cannot return null.
> Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp:58 > +std::unique_ptr<IDBObjectStore> IDBObjectStore::create(ScriptExecutionContext& context, const IDBObjectStoreInfo& info, IDBTransaction& transaction)
ditto.
Antoine Quint
Comment 12
2021-12-15 09:42:56 PST
Created
attachment 447245
[details]
Patch
Chris Dumez
Comment 13
2021-12-15 11:19:00 PST
Comment on
attachment 447245
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=447245&action=review
> Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp:532 > + m_referencedIndexes.set(indexName, std::unique_ptr<IDBIndex>(&index));
You want `index.moveToUniquePtr()`. This adopts the pointer so you will double-free.
Antoine Quint
Comment 14
2021-12-15 11:34:17 PST
Created
attachment 447262
[details]
Patch
Antoine Quint
Comment 15
2021-12-15 12:22:10 PST
Created
attachment 447270
[details]
Patch
Darin Adler
Comment 16
2021-12-15 12:35:49 PST
Comment on
attachment 447270
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=447270&action=review
> Source/WebCore/Modules/indexeddb/IDBObjectStore.cpp:530 > + Ref<IDBIndex> referencedIndex { index };
Since we’re touching this code, it can likely be changed to Ref instead of Ref<IDBIndex> since we have type deduction now.
> Source/WebCore/Modules/indexeddb/IDBTransaction.cpp:753 > + auto index = IDBIndex::create(*scriptExecutionContext(), info, objectStore); > + return index.moveToUniquePtr();
Should just be able to write: return IDBIndex::create(*scriptExecutionContext(), info, objectStore); Move construction of unique_ptr from UniqueRef should work.
Antoine Quint
Comment 17
2021-12-15 12:46:44 PST
Created
attachment 447279
[details]
Patch for landing
Antoine Quint
Comment 18
2021-12-15 22:21:15 PST
Created
attachment 447327
[details]
Patch for landing
Antoine Quint
Comment 19
2021-12-16 03:31:27 PST
Committed
r287129
(?): <
https://commits.webkit.org/r287129
>
Antoine Quint
Comment 20
2021-12-16 05:17:46 PST
Created
attachment 447346
[details]
Patch
Antoine Quint
Comment 21
2021-12-16 06:20:23 PST
Created
attachment 447349
[details]
Patch
Darin Adler
Comment 22
2021-12-16 11:09:23 PST
Comment on
attachment 447349
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=447349&action=review
Looks fantastic
> Source/WebCore/Modules/entriesapi/FileSystemEntry.cpp:57 > +void FileSystemEntry::initialize() > +{ > + suspendIfNeeded(); > +}
Why do we need these initialize functions instead of calling suspendIfNeeded directly? I’m sure that you thought about a reason, but I don’t know what it is. Would be nice to have one less function if there’s no abstraction here and suspendIfNeeded would do the same thing. If what we’re trying to mitigate is callers neglecting to call suspendIfNeeded, I’m not sure that renaming it to initialize will help. If we do want to tackle that problem there may be some compile time techniques or some runtime ones, like adding a debug-only boolean set every time suspendIfNeeded and finding a good place to assert afterward to catch cases where it wasn’t called even once. Could even use a micro-task to do that assertion.
> Source/WebCore/Modules/fetch/FetchBodyOwner.cpp:60 > +void FetchBodyOwner::initialize() > +{ > + suspendIfNeeded(); > +}
Ditto.
> Source/WebCore/Modules/fetch/FetchRequest.h:57 > + static Ref<FetchRequest> create(ScriptExecutionContext&, std::optional<FetchBody>&&, Ref<FetchHeaders>&&, ResourceRequest&&, FetchOptions&&, String&&);
Not sure we should have removed the name "referrer".
> Source/WebCore/Modules/filesystemaccess/FileSystemHandle.cpp:51 > +void FileSystemHandle::initialize() > +{ > + suspendIfNeeded(); > +}
Ditto.
> Source/WebCore/Modules/mediastream/RTCDTMFSender.cpp:47 > + auto result = adoptRef(* new RTCDTMFSender(context, sender, WTFMove(backend)));
Maybe get rid of the space between the "*" and "new"?
> Source/WebCore/workers/service/ServiceWorkerContainer.h:44 > +#include <wtf/UniqueRef.h>
Not something that should block landing this patch as-is, but: This should require only a forward-declaration of UniqueRef, which should be provided by Forward.h. Files where ServiceWorkerContainer::create are called will need UniquerRef.h, but this header should not require it.
> Source/WebCore/workers/service/ServiceWorkerContainer.h:61 > + static UniqueRef<ServiceWorkerContainer> create(ScriptExecutionContext*, NavigatorBase&);
Another thing not about this patch: Do you know why this takes ScriptExecutionContext* rather than ScriptExecutionContext&? Is nullptr OK?
Antoine Quint
Comment 23
2021-12-16 12:52:15 PST
(In reply to Darin Adler from
comment #22
)
> Comment on
attachment 447349
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=447349&action=review
> > Looks fantastic > > > Source/WebCore/Modules/entriesapi/FileSystemEntry.cpp:57 > > +void FileSystemEntry::initialize() > > +{ > > + suspendIfNeeded(); > > +} > > Why do we need these initialize functions instead of calling suspendIfNeeded > directly? > > I’m sure that you thought about a reason, but I don’t know what it is. Would > be nice to have one less function if there’s no abstraction here and > suspendIfNeeded would do the same thing. > > If what we’re trying to mitigate is callers neglecting to call > suspendIfNeeded, I’m not sure that renaming it to initialize will help. If > we do want to tackle that problem there may be some compile time techniques > or some runtime ones, like adding a debug-only boolean set every time > suspendIfNeeded and finding a good place to assert afterward to catch cases > where it wasn’t called even once. Could even use a micro-task to do that > assertion.
That was exactly my thought. If I were subclassing a class and looking at an existing subclass, I would see `initialize()` and think "I better call this", but if I saw `suspendIfNeeded()` without knowing necessarily much about ActiveDOMObject, it might not be as clear that it should be called. But this is just me, and it might in fact be a missed opportunity for the person subclassing to ask themselves the right questions and engage with a domain expert about what `suspendIfNeeded()` is. So I'm leaning towards removing initialize() and replacing its calls with `suspendIfNeeded()`.
> > Source/WebCore/Modules/fetch/FetchRequest.h:57 > > + static Ref<FetchRequest> create(ScriptExecutionContext&, std::optional<FetchBody>&&, Ref<FetchHeaders>&&, ResourceRequest&&, FetchOptions&&, String&&); > > Not sure we should have removed the name "referrer".
I'll put it back.
> > Source/WebCore/Modules/mediastream/RTCDTMFSender.cpp:47 > > + auto result = adoptRef(* new RTCDTMFSender(context, sender, WTFMove(backend))); > > Maybe get rid of the space between the "*" and "new"?
Yes, copying-and-pasting without thinking.
> > Source/WebCore/workers/service/ServiceWorkerContainer.h:44 > > +#include <wtf/UniqueRef.h> > > Not something that should block landing this patch as-is, but: This should > require only a forward-declaration of UniqueRef, which should be provided by > Forward.h. Files where ServiceWorkerContainer::create are called will need > UniquerRef.h, but this header should not require it.
OK, I will switch to a forward declaration and hopefully the bots will prove that is just fine.
> > Source/WebCore/workers/service/ServiceWorkerContainer.h:61 > > + static UniqueRef<ServiceWorkerContainer> create(ScriptExecutionContext*, NavigatorBase&); > > Another thing not about this patch: Do you know why this takes > ScriptExecutionContext* rather than ScriptExecutionContext&? Is nullptr OK?
I don't know, but the ActiveDOMObject constructor takes a ScriptExecutionContext* and this just passes this along to that constructor: ActiveDOMObject::ActiveDOMObject(ScriptExecutionContext* scriptExecutionContext) : ActiveDOMObject(suitableScriptExecutionContext(scriptExecutionContext), CheckedScriptExecutionContext) { } … which calls this method: static inline ScriptExecutionContext* suitableScriptExecutionContext(ScriptExecutionContext* scriptExecutionContext) { // For detached documents, make sure we observe their context document instead. return is<Document>(scriptExecutionContext) ? &downcast<Document>(*scriptExecutionContext).contextDocument() : scriptExecutionContext; } … and calls this other constructor: inline ActiveDOMObject::ActiveDOMObject(ScriptExecutionContext* context, CheckedScriptExecutionContextType) : ContextDestructionObserver(context) { ASSERT(!is<Document>(context) || &downcast<Document>(context)->contextDocument() == downcast<Document>(context)); if (!context) return; ASSERT(context->isContextThread()); context->didCreateActiveDOMObject(*this); }
Antoine Quint
Comment 24
2021-12-17 00:10:12 PST
Created
attachment 447437
[details]
Patch for landing
Antoine Quint
Comment 25
2021-12-17 03:58:42 PST
Committed
r287177
(
245346@trunk
): <
https://commits.webkit.org/245346@trunk
>
Antoine Quint
Comment 26
2021-12-17 04:11:52 PST
Created
attachment 447447
[details]
Patch
Antoine Quint
Comment 27
2021-12-17 04:23:53 PST
Created
attachment 447448
[details]
Patch
Chris Dumez
Comment 28
2021-12-17 07:26:47 PST
Comment on
attachment 447448
[details]
Patch r=me
EWS
Comment 29
2021-12-17 07:52:57 PST
Committed
r287186
(
245353@main
): <
https://commits.webkit.org/245353@main
> All reviewed patches have been landed. Closing bug and clearing flags on
attachment 447448
[details]
.
Darin Adler
Comment 30
2021-12-17 10:36:32 PST
We should also consider adding a checker that asserts if we make this error, to make sure this mistake doesn’t creep back in. I have some ideas about how to add that, for any objects that are put into our Ref/RefPtr/UniqueRef after creating them. No idea how to do the same for objects that go into unique_ptr, though.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug