Skip to content

Commit 0db7b5a

Browse files
committed
Ensure Debug Help library calls on Windows are made in as thread-safe a manner as possible by wrapping them in a scoped lock.
1 parent 7c63b8a commit 0db7b5a

File tree

3 files changed

+90
-26
lines changed

3 files changed

+90
-26
lines changed

stdlib/public/runtime/Errors.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,13 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName,
8585
// providing failure status instead of just returning the original string like
8686
// swift demangle.
8787
#if defined(_WIN32)
88-
static StaticMutex mutex;
89-
9088
char szUndName[1024];
91-
DWORD dwResult = mutex.withLock([&syminfo, &szUndName]() {
89+
DWORD dwResult;
90+
dwResult = _swift_withWin32DbgHelpLibrary([&] (bool isInitialized) -> DWORD {
91+
if (!isInitialized) {
92+
return 0;
93+
}
94+
9295
DWORD dwFlags = UNDNAME_COMPLETE;
9396
#if !defined(_WIN64)
9497
dwFlags |= UNDNAME_32_BIT_DECODE;
@@ -98,7 +101,7 @@ static bool getSymbolNameAddr(llvm::StringRef libraryName,
98101
sizeof(szUndName), dwFlags);
99102
});
100103

101-
if (dwResult == TRUE) {
104+
if (dwResult) {
102105
symbolName += szUndName;
103106
return true;
104107
}

stdlib/public/runtime/ImageInspection.h

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121
#ifndef SWIFT_RUNTIME_IMAGEINSPECTION_H
2222
#define SWIFT_RUNTIME_IMAGEINSPECTION_H
2323

24+
#include "swift/Runtime/Config.h"
25+
2426
#include <cstdint>
2527
#include <cstddef>
26-
#if defined(__cplusplus)
28+
#include <functional>
2729
#include <memory>
28-
#endif
30+
#include <type_traits>
2931

3032
namespace swift {
3133

@@ -106,6 +108,47 @@ void addImageAccessibleFunctionsBlockCallbackUnsafe(const void *baseAddress,
106108

107109
int lookupSymbol(const void *address, SymbolInfo *info);
108110

111+
#if defined(_WIN32)
112+
/// Configure the environment to allow calling into the Debug Help library.
113+
///
114+
/// \param body A function to invoke. This function attempts to first initialize
115+
/// the Debug Help library. The result of that operation is passed to this
116+
/// function.
117+
///
118+
/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All
119+
/// calls into it from the Swift runtime and stdlib should route through this
120+
/// function.
121+
SWIFT_RUNTIME_STDLIB_SPI
122+
void _swift_withWin32DbgHelpLibrary(
123+
const std::function<void(bool /*isInitialized*/)>& body);
124+
125+
/// Configure the environment to allow calling into the Debug Help library.
126+
///
127+
/// \param body A function to invoke. This function attempts to first initialize
128+
/// the Debug Help library. The result of that operation is passed to this
129+
/// function.
130+
///
131+
/// \returns Whatever is returned from \a body.
132+
///
133+
/// On Windows, the Debug Help library (DbgHelp.lib) is not thread-safe. All
134+
/// calls into it from the Swift runtime and stdlib should route through this
135+
/// function.
136+
template <
137+
typename F,
138+
typename R = typename std::result_of_t<F&(bool /*isInitialized*/)>,
139+
typename = typename std::enable_if_t<!std::is_same<void, R>::value>
140+
>
141+
static inline R _swift_withWin32DbgHelpLibrary(const F& body) {
142+
R result;
143+
144+
_swift_withWin32DbgHelpLibrary([&body, &result] (bool isInitialized) {
145+
result = body(isInitialized);
146+
});
147+
148+
return result;
149+
}
150+
#endif
151+
109152
} // end namespace swift
110153

111154
#endif

stdlib/public/runtime/ImageInspectionCOFF.cpp

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <DbgHelp.h>
2424
#endif
2525

26+
#include "swift/Runtime/Mutex.h"
27+
2628
using namespace swift;
2729

2830
int swift::lookupSymbol(const void *address, SymbolInfo *info) {
@@ -38,36 +40,52 @@ int swift::lookupSymbol(const void *address, SymbolInfo *info) {
3840
info->symbolAddress = dli_saddr;
3941
return 1;
4042
#elif defined(_WIN32)
41-
static const constexpr size_t kSymbolMaxNameLen = 1024;
42-
static bool bInitialized = false;
43+
return _swift_withWin32DbgHelpLibrary([&] (bool isInitialized) {
44+
static const constexpr size_t kSymbolMaxNameLen = 1024;
4345

44-
if (bInitialized == false) {
45-
if (SymInitialize(GetCurrentProcess(), /*UserSearchPath=*/NULL,
46-
/*fInvadeProcess=*/TRUE) == FALSE)
46+
if (!isInitialized) {
4747
return 0;
48-
bInitialized = true;
49-
}
48+
}
5049

51-
char buffer[sizeof(SYMBOL_INFO) + kSymbolMaxNameLen];
52-
PSYMBOL_INFO pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
53-
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
54-
pSymbol->MaxNameLen = kSymbolMaxNameLen;
50+
char buffer[sizeof(SYMBOL_INFO) + kSymbolMaxNameLen];
51+
PSYMBOL_INFO pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
52+
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
53+
pSymbol->MaxNameLen = kSymbolMaxNameLen;
5554

56-
DWORD64 dwDisplacement = 0;
55+
DWORD64 dwDisplacement = 0;
5756

58-
if (SymFromAddr(GetCurrentProcess(), reinterpret_cast<const DWORD64>(address),
59-
&dwDisplacement, pSymbol) == FALSE)
60-
return 0;
57+
if (SymFromAddr(GetCurrentProcess(),
58+
reinterpret_cast<const DWORD64>(address),
59+
&dwDisplacement, pSymbol) == FALSE) {
60+
return 0;
61+
}
6162

62-
info->fileName = NULL;
63-
info->baseAddress = reinterpret_cast<void *>(pSymbol->ModBase);
64-
info->symbolName.reset(_strdup(pSymbol->Name));
65-
info->symbolAddress = reinterpret_cast<void *>(pSymbol->Address);
63+
info->fileName = NULL;
64+
info->baseAddress = reinterpret_cast<void *>(pSymbol->ModBase);
65+
info->symbolName.reset(_strdup(pSymbol->Name));
66+
info->symbolAddress = reinterpret_cast<void *>(pSymbol->Address);
6667

67-
return 1;
68+
return 1;
69+
});
6870
#else
6971
return 0;
7072
#endif // defined(__CYGWIN__) || defined(_WIN32)
7173
}
7274

75+
#if defined(_WIN32)
76+
static StaticMutex mutex;
77+
static bool isDbgHelpInitialized = false;
78+
79+
void swift::_swift_withWin32DbgHelpLibrary(
80+
const std::function<void(bool /* isInitialized */)>& body) {
81+
mutex.withLock([&body] () {
82+
if (!isDbgHelpInitialized) {
83+
SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
84+
isDbgHelpInitialized = SymInitialize(GetCurrentProcess(), nullptr, true);
85+
}
86+
body(isDbgHelpInitialized);
87+
});
88+
}
89+
#endif
90+
7391
#endif // !defined(__ELF__) && !defined(__MACH__)

0 commit comments

Comments
 (0)