Skip to content

Commit 2841b59

Browse files
authored
Merge pull request #72870 from mikeash/libprespecialize-address-range-rejection
[Runtime] Don't attempt to look up prespecialized metadata involving pointers outside the shared cache.
2 parents 74cf3dd + 98229fe commit 2841b59

File tree

3 files changed

+109
-17
lines changed

3 files changed

+109
-17
lines changed

stdlib/public/runtime/LibPrespecialized.cpp

Lines changed: 96 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "swift/Runtime/LibPrespecialized.h"
14+
#include "MetadataCache.h"
1415
#include "Private.h"
1516
#include "swift/Basic/Lazy.h"
1617
#include "swift/Runtime/EnvironmentVariables.h"
@@ -75,24 +76,89 @@ static const LibPrespecializedData<InProcess> *findLibPrespecialized() {
7576
return data;
7677
}
7778

79+
struct LibPrespecializedState {
80+
struct AddressRange {
81+
uintptr_t start, end;
82+
83+
bool contains(const void *ptr) {
84+
return start <= (uintptr_t)ptr && (uintptr_t)ptr < end;
85+
}
86+
};
87+
88+
bool loggingEnabled;
89+
const LibPrespecializedData<InProcess> *data;
90+
AddressRange sharedCacheRange{0, 0};
91+
AddressRange metadataAllocatorInitialPoolRange{0, 0};
92+
93+
LibPrespecializedState() {
94+
loggingEnabled =
95+
runtime::environment::SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED_LOGGING();
96+
data = findLibPrespecialized();
97+
98+
#if DYLD_GET_SWIFT_PRESPECIALIZED_DATA_DEFINED
99+
size_t sharedCacheLength;
100+
sharedCacheRange.start =
101+
(uintptr_t)_dyld_get_shared_cache_range(&sharedCacheLength);
102+
sharedCacheRange.end = sharedCacheRange.start + sharedCacheLength;
103+
104+
auto [initialPoolStart, initialPoolLength] =
105+
MetadataAllocator::InitialPoolLocation();
106+
metadataAllocatorInitialPoolRange.start = (uintptr_t)initialPoolStart;
107+
metadataAllocatorInitialPoolRange.end =
108+
metadataAllocatorInitialPoolRange.start + initialPoolLength;
109+
#endif
110+
}
111+
};
112+
113+
static Lazy<LibPrespecializedState> LibPrespecialized;
114+
115+
#define LOG(fmt, ...) \
116+
do { \
117+
if (SWIFT_UNLIKELY(prespecialized.loggingEnabled)) \
118+
fprintf(stderr, "Prespecializations library: " fmt "\n", __VA_ARGS__); \
119+
} while (0)
120+
78121
const LibPrespecializedData<InProcess> *swift::getLibPrespecializedData() {
79122
return SWIFT_LAZY_CONSTANT(findLibPrespecialized());
80123
}
81124

82125
// Returns true if the type has any arguments that aren't plain types (packs or
83126
// unknown kinds).
84-
static bool hasNonTypeGenericArguments(const TypeContextDescriptor *description) {
85-
auto generics = description->getGenericContext();
86-
if (!generics)
87-
return false;
88-
127+
static bool
128+
hasNonTypeGenericArguments(const TargetGenericContext<InProcess> *generics) {
89129
for (auto param : generics->getGenericParams())
90130
if (param.getKind() != GenericParamKind::Type)
91131
return true;
92132

93133
return false;
94134
}
95135

136+
static bool
137+
isPotentialPrespecializedPointer(LibPrespecializedState &prespecialized,
138+
const void *pointer) {
139+
// Prespecialized metadata descriptors and arguments are always in the shared
140+
// cache. They're either statically emitted metadata, or they're
141+
// prespecialized metadata. Anything that's dynamically allocated, or
142+
// statically allocated outside the shared cache, is not a possible candidate.
143+
144+
// If we're loading a debug libprespecialized, we can't do these checks, so
145+
// just say everything is a potential argument. Performance is not so
146+
// important in that case.
147+
if (!prespecialized.sharedCacheRange.contains(prespecialized.data))
148+
return true;
149+
150+
// Anything outside the shared cache isn't a potential argument.
151+
if (!prespecialized.sharedCacheRange.contains(pointer))
152+
return false;
153+
154+
// Dynamically allocated metadata could be within the shared cache, in the
155+
// initial metadata allocation pool. Reject anything in that region.
156+
if (prespecialized.metadataAllocatorInitialPoolRange.contains(pointer))
157+
return false;
158+
159+
return true;
160+
}
161+
96162
static bool disableForValidation = false;
97163

98164
void
@@ -114,24 +180,40 @@ swift::getLibPrespecializedMetadata(const TypeContextDescriptor *description,
114180
|| disablePrespecializedMetadata.load(std::memory_order_acquire)))
115181
return nullptr;
116182

117-
auto *data = getLibPrespecializedData();
183+
auto &prespecialized = LibPrespecialized.get();
184+
185+
auto *data = prespecialized.data;
118186
if (!data)
119187
return nullptr;
120188

189+
auto *generics = description->getGenericContext();
190+
if (!generics)
191+
return nullptr;
192+
121193
// We don't support types with pack parameters yet (and especially not types
122194
// with unknown parameter kinds) so don't even try to look those up.
123-
if (hasNonTypeGenericArguments(description))
195+
if (hasNonTypeGenericArguments(generics))
124196
return nullptr;
125197

198+
if (!isPotentialPrespecializedPointer(prespecialized, description)) {
199+
LOG("Rejecting descriptor %p, not in the shared cache",
200+
(const void *)description);
201+
return nullptr;
202+
}
203+
204+
auto numKeyArguments = generics->getGenericContextHeader().NumKeyArguments;
205+
for (unsigned i = 0; i < numKeyArguments; i++) {
206+
if (!isPotentialPrespecializedPointer(prespecialized, arguments[i])) {
207+
LOG("Rejecting argument %u %p to descriptor %p, not in the shared cache",
208+
i, arguments[i], (const void *)description);
209+
return nullptr;
210+
}
211+
}
212+
126213
Demangler dem;
127214
auto mangleNode = _buildDemanglingForGenericType(description, arguments, dem);
128215
if (!mangleNode) {
129-
if (SWIFT_UNLIKELY(runtime::environment::
130-
SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED_LOGGING()))
131-
fprintf(stderr,
132-
"Prespecializations library: failed to build demangling with "
133-
"descriptor %p.\n",
134-
description);
216+
LOG("failed to build demangling with descriptor %p.", description);
135217
return nullptr;
136218
}
137219

@@ -159,10 +241,7 @@ swift::getLibPrespecializedMetadata(const TypeContextDescriptor *description,
159241
auto *metadataMap = data->getMetadataMap();
160242
auto *element = metadataMap->find(key.data(), key.size());
161243
auto *result = element ? element->value : nullptr;
162-
if (SWIFT_UNLIKELY(runtime::environment::
163-
SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED_LOGGING()))
164-
fprintf(stderr, "Prespecializations library: found %p for key '%.*s'.\n",
165-
result, (int)key.size(), key.data());
244+
LOG("found %p for key '%.*s'.", result, (int)key.size(), key.data());
166245
return result;
167246
}
168247

stdlib/public/runtime/Metadata.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7420,6 +7420,10 @@ static swift::atomic<PoolRange>
74207420
AllocationPool{PoolRange{InitialAllocationPool.Pool,
74217421
sizeof(InitialAllocationPool.Pool)}};
74227422

7423+
std::tuple<const void *, size_t> MetadataAllocator::InitialPoolLocation() {
7424+
return {InitialAllocationPool.Pool, sizeof(InitialAllocationPool.Pool)};
7425+
}
7426+
74237427
bool swift::_swift_debug_metadataAllocationIterationEnabled = false;
74247428
const void * const swift::_swift_debug_allocationPoolPointer = &AllocationPool;
74257429
std::atomic<const void *> swift::_swift_debug_metadataAllocationBacktraceList;

stdlib/public/runtime/MetadataCache.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <atomic>
2626
#include <condition_variable>
2727
#include <optional>
28+
#include <tuple>
2829

2930
#ifndef SWIFT_DEBUG_RUNTIME
3031
#define SWIFT_DEBUG_RUNTIME 0
@@ -46,6 +47,11 @@ class MetadataAllocator : public llvm::AllocatorBase<MetadataAllocator> {
4647

4748
void Reset() {}
4849

50+
/// Get the location of the allocator's initial statically allocated pool.
51+
/// The return values are start and size. If there is no statically allocated
52+
/// pool, the return values are NULL, 0.
53+
static std::tuple<const void *, size_t> InitialPoolLocation();
54+
4955
SWIFT_RETURNS_NONNULL SWIFT_NODISCARD
5056
void *Allocate(size_t size, size_t alignment);
5157
using AllocatorBase<MetadataAllocator>::Allocate;
@@ -67,6 +73,9 @@ class MetadataAllocator : public llvm::AllocatorBase<MetadataAllocator> {
6773
class MetadataAllocator {
6874
public:
6975
MetadataAllocator(uint16_t tag) {}
76+
static std::tuple<const void *, size_t> InitialPoolLocation() {
77+
return {nullptr, 0};
78+
}
7079
SWIFT_RETURNS_NONNULL SWIFT_NODISCARD
7180
void *Allocate(size_t size, size_t alignment) {
7281
if (alignment < sizeof(void*)) alignment = sizeof(void*);

0 commit comments

Comments
 (0)