Skip to content

Commit b8f29cf

Browse files
committed
[Runtime] Allow disabling/enabling prespecializations library per-process.
Read a list of disabled process names from the prespecializations library, and turn the feature off if the current process matches. Also allow passing process names in environment variables. Processes can be disabled by name using SWIFT_DEBUG_LIB_PRESPECIALIZED_DISABLED_PROCESSES, and a disable can be overridden with SWIFT_DEBUG_LIB_PRESPECIALIZED_ENABLED_PROCESSES. rdar://126216786
1 parent 734da62 commit b8f29cf

File tree

3 files changed

+118
-15
lines changed

3 files changed

+118
-15
lines changed

include/swift/Runtime/LibPrespecialized.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ struct LibPrespecializedData {
3131
uint32_t minorVersion;
3232

3333
TargetPointer<Runtime, const void> metadataMap;
34+
TargetPointer<Runtime, const void> disabledProcessesTable;
3435

3536
static constexpr uint32_t currentMajorVersion = 1;
36-
static constexpr uint32_t currentMinorVersion = 1;
37+
static constexpr uint32_t currentMinorVersion = 2;
38+
39+
static constexpr uint32_t minorVersionWithDisabledProcessesTable = 2;
3740

3841
// Helpers for retrieving the metadata map in-process.
3942
static bool stringIsNull(const char *str) { return str == nullptr; }
@@ -43,6 +46,12 @@ struct LibPrespecializedData {
4346
const MetadataMap *getMetadataMap() const {
4447
return reinterpret_cast<const MetadataMap *>(metadataMap);
4548
}
49+
50+
const char *const *getDisabledProcessesTable() const {
51+
if (minorVersion < minorVersionWithDisabledProcessesTable)
52+
return nullptr;
53+
return reinterpret_cast<const char *const *>(disabledProcessesTable);
54+
}
4655
};
4756

4857
const LibPrespecializedData<InProcess> *getLibPrespecializedData();

stdlib/public/runtime/EnvironmentVariables.def

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,19 @@ VARIABLE(SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED, bool, true,
8585
"Enable use of prespecializations library.")
8686

8787
VARIABLE(SWIFT_DEBUG_LIB_PRESPECIALIZED_PATH, string, "",
88-
"A path to a prespecializations library to use at runtime. In order to"
89-
"be used, this library must be loaded into the process by other means"
90-
"(such as DYLD_INSERT_LIBRARIES) before Swift tries to use it.")
88+
"A path to a prespecializations library to use at runtime. In order "
89+
"to be used, this library must be loaded into the process by other "
90+
"means (such as DYLD_INSERT_LIBRARIES) before Swift tries to use it.")
91+
92+
VARIABLE(SWIFT_DEBUG_LIB_PRESPECIALIZED_DISABLED_PROCESSES, string, "",
93+
"A colon-separated list of process names where the prespecializations "
94+
"library will be forcibly disabled.")
95+
96+
VARIABLE(SWIFT_DEBUG_LIB_PRESPECIALIZED_ENABLED_PROCESSES, string, "",
97+
"A colon-separated list of process names where the prespecializations "
98+
"library will be forcibly enabled. This overrides the disabled "
99+
"processes list in the prespecializations library, as well as the "
100+
"list in SWIFT_DEBUG_LIB_PRESPECIALIZED_DISABLED_PROCESSES.")
91101

92102
VARIABLE(SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED_LOGGING, bool, false,
93103
"Enable debug logging of prespecializations library use.")

stdlib/public/runtime/LibPrespecialized.cpp

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,85 @@ using namespace swift;
3232

3333
static std::atomic<bool> disablePrespecializedMetadata = false;
3434

35+
static bool prespecializedLoggingEnabled = false;
36+
37+
#define LOG(fmt, ...) \
38+
do { \
39+
if (SWIFT_UNLIKELY(prespecializedLoggingEnabled)) \
40+
fprintf(stderr, "Prespecializations library: " fmt "\n", __VA_ARGS__); \
41+
} while (0)
42+
43+
static bool environmentProcessListContainsProcess(const char *list,
44+
const char *progname) {
45+
auto prognameLen = strlen(progname);
46+
47+
const char *cursor = list;
48+
while (true) {
49+
const char *next = strchr(cursor, ':');
50+
if (!next) {
51+
// Last entry in the list. Compare with the entire rest of the string.
52+
return strcmp(progname, cursor) == 0;
53+
}
54+
55+
// Entry at beginning or middle of the list. Compare against this substring.
56+
size_t len = next - cursor;
57+
if (len == prognameLen && strncmp(cursor, progname, len) == 0)
58+
return true;
59+
60+
cursor = next + 1;
61+
}
62+
}
63+
64+
static bool isThisProcessEnabled(const LibPrespecializedData<InProcess> *data) {
65+
extern const char *__progname;
66+
67+
if (!__progname)
68+
return true;
69+
70+
auto envEnabledProcesses =
71+
runtime::environment::SWIFT_DEBUG_LIB_PRESPECIALIZED_ENABLED_PROCESSES();
72+
if (envEnabledProcesses && *envEnabledProcesses) {
73+
if (environmentProcessListContainsProcess(envEnabledProcesses,
74+
__progname)) {
75+
LOG("Found %s in SWIFT_DEBUG_LIB_PRESPECIALIZED_ENABLED_PROCESSES, "
76+
"enabling",
77+
__progname);
78+
return true;
79+
}
80+
}
81+
82+
auto envDisabledProcesses =
83+
runtime::environment::SWIFT_DEBUG_LIB_PRESPECIALIZED_DISABLED_PROCESSES();
84+
if (envDisabledProcesses && *envDisabledProcesses) {
85+
if (environmentProcessListContainsProcess(envDisabledProcesses,
86+
__progname)) {
87+
LOG("Found %s in SWIFT_DEBUG_LIB_PRESPECIALIZED_DISABLED_PROCESSES, "
88+
"disabling",
89+
__progname);
90+
return false;
91+
}
92+
}
93+
94+
if (auto *disabledProcesses = data->getDisabledProcessesTable()) {
95+
auto *cursor = disabledProcesses;
96+
while (auto *name = *cursor) {
97+
if (strcmp(name, __progname) == 0) {
98+
LOG("Found %s in disabled processes list, disabling", name);
99+
return false;
100+
}
101+
cursor++;
102+
}
103+
}
104+
105+
return true;
106+
}
107+
35108
static const LibPrespecializedData<InProcess> *findLibPrespecialized() {
36-
if (!runtime::environment::SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED())
109+
if (!runtime::environment::SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED()) {
110+
LOG("Disabling, SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED = %d",
111+
runtime::environment::SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED());
37112
return nullptr;
113+
}
38114

39115
const void *dataPtr = nullptr;
40116
#if USE_DLOPEN
@@ -51,15 +127,22 @@ static const LibPrespecializedData<InProcess> *findLibPrespecialized() {
51127
}
52128

53129
dataPtr = dlsym(handle, LIB_PRESPECIALIZED_TOP_LEVEL_SYMBOL_NAME);
130+
LOG("Loaded custom library from %s, found dataPtr %p", path, dataPtr);
54131
}
55132
#if DYLD_GET_SWIFT_PRESPECIALIZED_DATA_DEFINED
56133
else if (SWIFT_RUNTIME_WEAK_CHECK(_dyld_get_swift_prespecialized_data)) {
57134
// Disable the prespecializations library if anything in the shared cache is
58135
// overridden. Eventually we want to be cleverer and only disable the
59136
// prespecializations that have been invalidated, but we'll start with the
60137
// simplest approach.
61-
if (!dyld_shared_cache_some_image_overridden())
138+
if (!dyld_shared_cache_some_image_overridden()) {
62139
dataPtr = SWIFT_RUNTIME_WEAK_USE(_dyld_get_swift_prespecialized_data());
140+
LOG("Got dataPtr %p from _dyld_get_swift_prespecialized_data", dataPtr);
141+
} else {
142+
LOG("Not calling _dyld_get_swift_prespecialized_data "
143+
"dyld_shared_cache_some_image_overridden = %d",
144+
dyld_shared_cache_some_image_overridden());
145+
}
63146
}
64147
#endif
65148
#endif
@@ -70,8 +153,16 @@ static const LibPrespecializedData<InProcess> *findLibPrespecialized() {
70153
auto *data =
71154
reinterpret_cast<const LibPrespecializedData<InProcess> *>(dataPtr);
72155
if (data->majorVersion !=
73-
LibPrespecializedData<InProcess>::currentMajorVersion)
156+
LibPrespecializedData<InProcess>::currentMajorVersion) {
157+
LOG("Unknown major version %" PRIu32 ", disabling", data->majorVersion);
74158
return nullptr;
159+
}
160+
161+
if (!isThisProcessEnabled(data))
162+
return nullptr;
163+
164+
LOG("Returning data %p, major version %" PRIu32 " minor %" PRIu32, data,
165+
data->majorVersion, data->minorVersion);
75166

76167
return data;
77168
}
@@ -85,13 +176,12 @@ struct LibPrespecializedState {
85176
}
86177
};
87178

88-
bool loggingEnabled;
89179
const LibPrespecializedData<InProcess> *data;
90180
AddressRange sharedCacheRange{0, 0};
91181
AddressRange metadataAllocatorInitialPoolRange{0, 0};
92182

93183
LibPrespecializedState() {
94-
loggingEnabled =
184+
prespecializedLoggingEnabled =
95185
runtime::environment::SWIFT_DEBUG_ENABLE_LIB_PRESPECIALIZED_LOGGING();
96186
data = findLibPrespecialized();
97187

@@ -112,12 +202,6 @@ struct LibPrespecializedState {
112202

113203
static Lazy<LibPrespecializedState> LibPrespecialized;
114204

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-
121205
const LibPrespecializedData<InProcess> *swift::getLibPrespecializedData() {
122206
return SWIFT_LAZY_CONSTANT(findLibPrespecialized());
123207
}

0 commit comments

Comments
 (0)