Skip to content

Commit 26c093a

Browse files
hebastolaanwj
andcommitted
Replace thread_local g_lockstack with a mutex-protected map
This change prevents UB in case of early g_lockstack destroying. Co-authored-by: Wladimir J. van der Laan <[email protected]>
1 parent 58e6881 commit 26c093a

File tree

1 file changed

+37
-14
lines changed

1 file changed

+37
-14
lines changed

src/sync.cpp

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include <map>
1717
#include <set>
1818
#include <system_error>
19+
#include <thread>
20+
#include <unordered_map>
1921
#include <utility>
2022
#include <vector>
2123

@@ -77,12 +79,14 @@ struct CLockLocation {
7779

7880
using LockStackItem = std::pair<void*, CLockLocation>;
7981
using LockStack = std::vector<LockStackItem>;
82+
using LockStacks = std::unordered_map<std::thread::id, LockStack>;
8083

8184
using LockPair = std::pair<void*, void*>;
8285
using LockOrders = std::map<LockPair, LockStack>;
8386
using InvLockOrders = std::set<LockPair>;
8487

8588
struct LockData {
89+
LockStacks m_lock_stacks;
8690
LockOrders lockorders;
8791
InvLockOrders invlockorders;
8892
std::mutex dd_mutex;
@@ -95,8 +99,6 @@ LockData& GetLockData() {
9599
return lock_data;
96100
}
97101

98-
static thread_local LockStack g_lockstack;
99-
100102
static void potential_deadlock_detected(const LockPair& mismatch, const LockStack& s1, const LockStack& s2)
101103
{
102104
LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
@@ -132,16 +134,16 @@ static void push_lock(void* c, const CLockLocation& locklocation)
132134
LockData& lockdata = GetLockData();
133135
std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
134136

135-
g_lockstack.push_back(std::make_pair(c, locklocation));
136-
137-
for (const LockStackItem& i : g_lockstack) {
137+
LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];
138+
lock_stack.emplace_back(c, locklocation);
139+
for (const LockStackItem& i : lock_stack) {
138140
if (i.first == c)
139141
break;
140142

141143
const LockPair p1 = std::make_pair(i.first, c);
142144
if (lockdata.lockorders.count(p1))
143145
continue;
144-
lockdata.lockorders.emplace(p1, g_lockstack);
146+
lockdata.lockorders.emplace(p1, lock_stack);
145147

146148
const LockPair p2 = std::make_pair(c, i.first);
147149
lockdata.invlockorders.insert(p2);
@@ -152,7 +154,14 @@ static void push_lock(void* c, const CLockLocation& locklocation)
152154

153155
static void pop_lock()
154156
{
155-
g_lockstack.pop_back();
157+
LockData& lockdata = GetLockData();
158+
std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
159+
160+
LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];
161+
lock_stack.pop_back();
162+
if (lock_stack.empty()) {
163+
lockdata.m_lock_stacks.erase(std::this_thread::get_id());
164+
}
156165
}
157166

158167
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
@@ -162,11 +171,17 @@ void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs
162171

163172
void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line)
164173
{
165-
if (!g_lockstack.empty()) {
166-
const auto& lastlock = g_lockstack.back();
167-
if (lastlock.first == cs) {
168-
lockname = lastlock.second.Name();
169-
return;
174+
{
175+
LockData& lockdata = GetLockData();
176+
std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
177+
178+
const LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];
179+
if (!lock_stack.empty()) {
180+
const auto& lastlock = lock_stack.back();
181+
if (lastlock.first == cs) {
182+
lockname = lastlock.second.Name();
183+
return;
184+
}
170185
}
171186
}
172187
throw std::system_error(EPERM, std::generic_category(), strprintf("%s:%s %s was not most recent critical section locked", file, line, guardname));
@@ -179,15 +194,23 @@ void LeaveCritical()
179194

180195
std::string LocksHeld()
181196
{
197+
LockData& lockdata = GetLockData();
198+
std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
199+
200+
const LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];
182201
std::string result;
183-
for (const LockStackItem& i : g_lockstack)
202+
for (const LockStackItem& i : lock_stack)
184203
result += i.second.ToString() + std::string("\n");
185204
return result;
186205
}
187206

188207
static bool LockHeld(void* mutex)
189208
{
190-
for (const LockStackItem& i : g_lockstack) {
209+
LockData& lockdata = GetLockData();
210+
std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
211+
212+
const LockStack& lock_stack = lockdata.m_lock_stacks[std::this_thread::get_id()];
213+
for (const LockStackItem& i : lock_stack) {
191214
if (i.first == mutex) return true;
192215
}
193216

0 commit comments

Comments
 (0)