Skip to content

Commit 027da91

Browse files
authored
Merge pull request #72881 from mikeash/libprespecialize-address-range-rejection-6.0
[6.0][Runtime] Don't attempt to look up prespecialized metadata involving pointers outside the shared cache.
2 parents 35153d8 + 1a62477 commit 027da91

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"
@@ -71,24 +72,89 @@ static const LibPrespecializedData<InProcess> *findLibPrespecialized() {
7172
return data;
7273
}
7374

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

78121
// Returns true if the type has any arguments that aren't plain types (packs or
79122
// unknown kinds).
80-
static bool hasNonTypeGenericArguments(const TypeContextDescriptor *description) {
81-
auto generics = description->getGenericContext();
82-
if (!generics)
83-
return false;
84-
123+
static bool
124+
hasNonTypeGenericArguments(const TargetGenericContext<InProcess> *generics) {
85125
for (auto param : generics->getGenericParams())
86126
if (param.getKind() != GenericParamKind::Type)
87127
return true;
88128

89129
return false;
90130
}
91131

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

94160
Metadata *
@@ -97,24 +163,40 @@ swift::getLibPrespecializedMetadata(const TypeContextDescriptor *description,
97163
if (disableForValidation)
98164
return nullptr;
99165

100-
auto *data = getLibPrespecializedData();
166+
auto &prespecialized = LibPrespecialized.get();
167+
168+
auto *data = prespecialized.data;
101169
if (!data)
102170
return nullptr;
103171

172+
auto *generics = description->getGenericContext();
173+
if (!generics)
174+
return nullptr;
175+
104176
// We don't support types with pack parameters yet (and especially not types
105177
// with unknown parameter kinds) so don't even try to look those up.
106-
if (hasNonTypeGenericArguments(description))
178+
if (hasNonTypeGenericArguments(generics))
107179
return nullptr;
108180

181+
if (!isPotentialPrespecializedPointer(prespecialized, description)) {
182+
LOG("Rejecting descriptor %p, not in the shared cache",
183+
(const void *)description);
184+
return nullptr;
185+
}
186+
187+
auto numKeyArguments = generics->getGenericContextHeader().NumKeyArguments;
188+
for (unsigned i = 0; i < numKeyArguments; i++) {
189+
if (!isPotentialPrespecializedPointer(prespecialized, arguments[i])) {
190+
LOG("Rejecting argument %u %p to descriptor %p, not in the shared cache",
191+
i, arguments[i], (const void *)description);
192+
return nullptr;
193+
}
194+
}
195+
109196
Demangler dem;
110197
auto mangleNode = _buildDemanglingForGenericType(description, arguments, dem);
111198
if (!mangleNode) {
112-
if (SWIFT_UNLIKELY(runtime::environment::
113-
SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED_LOGGING()))
114-
fprintf(stderr,
115-
"Prespecializations library: failed to build demangling with "
116-
"descriptor %p.\n",
117-
description);
199+
LOG("failed to build demangling with descriptor %p.", description);
118200
return nullptr;
119201
}
120202

@@ -142,10 +224,7 @@ swift::getLibPrespecializedMetadata(const TypeContextDescriptor *description,
142224
auto *metadataMap = data->getMetadataMap();
143225
auto *element = metadataMap->find(key.data(), key.size());
144226
auto *result = element ? element->value : nullptr;
145-
if (SWIFT_UNLIKELY(runtime::environment::
146-
SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED_LOGGING()))
147-
fprintf(stderr, "Prespecializations library: found %p for key '%.*s'.\n",
148-
result, (int)key.size(), key.data());
227+
LOG("found %p for key '%.*s'.", result, (int)key.size(), key.data());
149228
return result;
150229
}
151230

stdlib/public/runtime/Metadata.cpp

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

7435+
std::tuple<const void *, size_t> MetadataAllocator::InitialPoolLocation() {
7436+
return {InitialAllocationPool.Pool, sizeof(InitialAllocationPool.Pool)};
7437+
}
7438+
74357439
bool swift::_swift_debug_metadataAllocationIterationEnabled = false;
74367440
const void * const swift::_swift_debug_allocationPoolPointer = &AllocationPool;
74377441
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)