Skip to content
This repository was archived by the owner on Jun 24, 2022. It is now read-only.

Commit dc8c392

Browse files
[JSC] Use LazyNeverDestroyed & std::call_once for complex singletons
https://bugs.webkit.org/show_bug.cgi?id=215153 <rdar://problem/65718983> Reviewed by Mark Lam. Source/JavaScriptCore: We are getting some crashes in RemoteInspector and this speculatively fixes the crash. My guess is that NeverDestroyed<RemoteInspector> calls constructor twice in heavily contended situation: WebKit's static does not have thread-safety. If two threads come here at the same time, it is possible that constructor is invoked twice. In that case, later constructor will clear members, which involves clearing Lock m_mutex field. This makes Lock's invariant broken. This patch uses LazyNeverDestroyed and std::call_once to ensure invoking constructor only once. * API/glib/JSCVirtualMachine.cpp: * dfg/DFGCommonData.cpp: * disassembler/Disassembler.cpp: * inspector/remote/RemoteInspector.h: * inspector/remote/cocoa/RemoteInspectorCocoa.mm: (Inspector::RemoteInspector::singleton): * inspector/remote/glib/RemoteInspectorGlib.cpp: (Inspector::RemoteInspector::singleton): * inspector/remote/socket/RemoteInspectorServer.cpp: (Inspector::RemoteInspectorServer::singleton): * inspector/remote/socket/RemoteInspectorServer.h: * inspector/remote/socket/RemoteInspectorSocket.cpp: (Inspector::RemoteInspector::singleton): * inspector/remote/socket/RemoteInspectorSocketEndpoint.cpp: (Inspector::RemoteInspectorSocketEndpoint::singleton): * interpreter/Interpreter.cpp: (JSC::Interpreter::opcodeIDTable): * runtime/IntlObject.cpp: (JSC::intlAvailableLocales): (JSC::intlCollatorAvailableLocales): (JSC::defaultLocale): (JSC::numberingSystemsForLocale): Source/WTF: Add lock's bits in crash information to investigate if this speculative fix does not work. * wtf/LockAlgorithmInlines.h: (WTF::Hooks>::lockSlow): (WTF::Hooks>::unlockSlow): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@265276 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent db751bf commit dc8c392

15 files changed

+120
-38
lines changed

Source/JavaScriptCore/API/glib/JSCVirtualMachine.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,12 @@ static Lock wrapperCacheMutex;
5151

5252
static HashMap<JSContextGroupRef, JSCVirtualMachine*>& wrapperMap()
5353
{
54-
static NeverDestroyed<HashMap<JSContextGroupRef, JSCVirtualMachine*>> map;
55-
return map;
54+
static LazyNeverDestroyed<HashMap<JSContextGroupRef, JSCVirtualMachine*>> shared;
55+
static std::once_flag onceKey;
56+
std::call_once(onceKey, [&] {
57+
shared.construct();
58+
});
59+
return shared;
5660
}
5761

5862
static void addWrapper(JSContextGroupRef group, JSCVirtualMachine* vm)

Source/JavaScriptCore/ChangeLog

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,41 @@
1+
2020-08-04 Yusuke Suzuki <[email protected]>
2+
3+
[JSC] Use LazyNeverDestroyed & std::call_once for complex singletons
4+
https://bugs.webkit.org/show_bug.cgi?id=215153
5+
<rdar://problem/65718983>
6+
7+
Reviewed by Mark Lam.
8+
9+
We are getting some crashes in RemoteInspector and this speculatively fixes the crash.
10+
My guess is that NeverDestroyed<RemoteInspector> calls constructor twice in heavily contended situation:
11+
WebKit's static does not have thread-safety. If two threads come here at the same time, it is possible that
12+
constructor is invoked twice. In that case, later constructor will clear members, which involves clearing
13+
Lock m_mutex field. This makes Lock's invariant broken.
14+
This patch uses LazyNeverDestroyed and std::call_once to ensure invoking constructor only once.
15+
16+
* API/glib/JSCVirtualMachine.cpp:
17+
* dfg/DFGCommonData.cpp:
18+
* disassembler/Disassembler.cpp:
19+
* inspector/remote/RemoteInspector.h:
20+
* inspector/remote/cocoa/RemoteInspectorCocoa.mm:
21+
(Inspector::RemoteInspector::singleton):
22+
* inspector/remote/glib/RemoteInspectorGlib.cpp:
23+
(Inspector::RemoteInspector::singleton):
24+
* inspector/remote/socket/RemoteInspectorServer.cpp:
25+
(Inspector::RemoteInspectorServer::singleton):
26+
* inspector/remote/socket/RemoteInspectorServer.h:
27+
* inspector/remote/socket/RemoteInspectorSocket.cpp:
28+
(Inspector::RemoteInspector::singleton):
29+
* inspector/remote/socket/RemoteInspectorSocketEndpoint.cpp:
30+
(Inspector::RemoteInspectorSocketEndpoint::singleton):
31+
* interpreter/Interpreter.cpp:
32+
(JSC::Interpreter::opcodeIDTable):
33+
* runtime/IntlObject.cpp:
34+
(JSC::intlAvailableLocales):
35+
(JSC::intlCollatorAvailableLocales):
36+
(JSC::defaultLocale):
37+
(JSC::numberingSystemsForLocale):
38+
139
2020-08-04 Keith Miller <[email protected]>
240

341
CheckpointSideState shoud play nicely with StackOverflowException unwinding.

Source/JavaScriptCore/dfg/DFGCommonData.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ void CommonData::shrinkToFit()
6161
static Lock pcCodeBlockMapLock;
6262
inline HashMap<void*, CodeBlock*>& pcCodeBlockMap(AbstractLocker&)
6363
{
64-
static NeverDestroyed<HashMap<void*, CodeBlock*>> pcCodeBlockMap;
64+
static LazyNeverDestroyed<HashMap<void*, CodeBlock*>> pcCodeBlockMap;
65+
static std::once_flag onceKey;
66+
std::call_once(onceKey, [&] {
67+
pcCodeBlockMap.construct();
68+
});
6569
return pcCodeBlockMap;
6670
}
6771

Source/JavaScriptCore/disassembler/Disassembler.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,12 @@ bool hadAnyAsynchronousDisassembly = false;
119119

120120
AsynchronousDisassembler& asynchronousDisassembler()
121121
{
122-
static NeverDestroyed<AsynchronousDisassembler> disassembler;
123-
hadAnyAsynchronousDisassembly = true;
122+
static LazyNeverDestroyed<AsynchronousDisassembler> disassembler;
123+
static std::once_flag onceKey;
124+
std::call_once(onceKey, [&] {
125+
disassembler.construct();
126+
hadAnyAsynchronousDisassembly = true;
127+
});
124128
return disassembler.get();
125129
}
126130

Source/JavaScriptCore/inspector/remote/RemoteInspector.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ class JS_EXPORT_PRIVATE RemoteInspector final
119119
#endif
120120
static void startDisabled();
121121
static RemoteInspector& singleton();
122-
friend class NeverDestroyed<RemoteInspector>;
122+
friend class LazyNeverDestroyed<RemoteInspector>;
123123

124124
void registerTarget(RemoteControllableTarget*);
125125
void unregisterTarget(RemoteControllableTarget*);

Source/JavaScriptCore/inspector/remote/cocoa/RemoteInspectorCocoa.mm

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,11 @@ static bool globalAutomaticInspectionState()
8585

8686
RemoteInspector& RemoteInspector::singleton()
8787
{
88-
static NeverDestroyed<RemoteInspector> shared;
88+
static LazyNeverDestroyed<RemoteInspector> shared;
89+
static dispatch_once_t onceConstructKey;
90+
dispatch_once(&onceConstructKey, ^{
91+
shared.construct();
92+
});
8993

9094
#if PLATFORM(COCOA)
9195
if (needMachSandboxExtension)

Source/JavaScriptCore/inspector/remote/glib/RemoteInspectorGlib.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ namespace Inspector {
4040

4141
RemoteInspector& RemoteInspector::singleton()
4242
{
43-
static NeverDestroyed<RemoteInspector> shared;
43+
static LazyNeverDestroyed<RemoteInspector> shared;
44+
static std::once_flag onceKey;
45+
std::call_once(onceKey, [&] {
46+
shared.construct();
47+
});
4448
return shared;
4549
}
4650

Source/JavaScriptCore/inspector/remote/socket/RemoteInspectorServer.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ namespace Inspector {
3535

3636
RemoteInspectorServer& RemoteInspectorServer::singleton()
3737
{
38-
static NeverDestroyed<RemoteInspectorServer> server;
39-
return server;
38+
static LazyNeverDestroyed<RemoteInspectorServer> shared;
39+
static std::once_flag onceKey;
40+
std::call_once(onceKey, [&] {
41+
shared.construct();
42+
});
43+
return shared;
4044
}
4145

4246
RemoteInspectorServer::~RemoteInspectorServer()

Source/JavaScriptCore/inspector/remote/socket/RemoteInspectorServer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class RemoteInspectorServer final : public RemoteInspectorSocketEndpoint::Listen
4343
bool isRunning() const { return !!m_server; }
4444

4545
private:
46-
friend class NeverDestroyed<RemoteInspectorServer>;
46+
friend class LazyNeverDestroyed<RemoteInspectorServer>;
4747
RemoteInspectorServer() { Socket::init(); }
4848

4949
bool didAccept(ConnectionID acceptedID, ConnectionID listenerID, Socket::Domain) final;

Source/JavaScriptCore/inspector/remote/socket/RemoteInspectorSocket.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ namespace Inspector {
4141

4242
RemoteInspector& RemoteInspector::singleton()
4343
{
44-
static NeverDestroyed<RemoteInspector> shared;
44+
static LazyNeverDestroyed<RemoteInspector> shared;
45+
static std::once_flag onceKey;
46+
std::call_once(onceKey, [&] {
47+
shared.construct();
48+
});
4549
return shared;
4650
}
4751

0 commit comments

Comments
 (0)