-
Notifications
You must be signed in to change notification settings - Fork 183
Expand file tree
/
Copy pathconfig.c
More file actions
339 lines (294 loc) · 12.6 KB
/
Copy pathconfig.c
File metadata and controls
339 lines (294 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#include "./config.h"
#include <assert.h>
#include <json/json.h>
#include <main/php.h>
#include <main/SAPI.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
HashTable zai_config_name_map = {0};
bool zai_config_first_rinit_done = false;
uint16_t zai_config_memoized_entries_count = 0;
zai_config_memoized_entry zai_config_memoized_entries[ZAI_CONFIG_ENTRIES_COUNT_MAX];
// Indexed [config_id][name_index]; NULL means not set.
static char *zai_config_cached_sys_env[ZAI_CONFIG_ENTRIES_COUNT_MAX][ZAI_CONFIG_NAMES_COUNT_MAX];
const char *zai_config_sys_env_cached(zai_config_id id, uint8_t name_index) {
return zai_config_cached_sys_env[id][name_index];
}
static void zai_config_cache_sys_env(void) {
for (zai_config_id i = 0; i < zai_config_memoized_entries_count; i++) {
zai_config_memoized_entry *m = &zai_config_memoized_entries[i];
for (uint8_t n = 0; n < m->names_count; n++) {
zai_str name = ZAI_STR_NEW(m->names[n].ptr, m->names[n].len);
zai_option_str val = zai_sys_getenv(name);
zai_config_cached_sys_env[i][n] = zai_option_str_is_some(val)
? pestrdup(val.ptr, 1) : NULL;
}
}
}
static void zai_config_clear_sys_env_cache(void) {
for (zai_config_id i = 0; i < zai_config_memoized_entries_count; i++) {
for (uint8_t n = 0; n < zai_config_memoized_entries[i].names_count; n++) {
if (zai_config_cached_sys_env[i][n]) {
pefree(zai_config_cached_sys_env[i][n], 1);
zai_config_cached_sys_env[i][n] = NULL;
}
}
}
}
static inline void zai_config_process_env(zai_config_memoized_entry *memoized, zai_env_buffer buf, zai_option_str *value) {
zval tmp;
ZVAL_UNDEF(&tmp);
zai_str env_value = ZAI_STR_FROM_CSTR(buf.ptr);
if (!zai_config_decode_value(env_value, memoized->type, memoized->parser, &tmp, /* persistent */ true)) {
// TODO Log decoding error
} else {
zai_json_dtor_pzval(&tmp);
*value = zai_option_str_from_str(env_value);
}
}
static void zai_config_find_and_set_value(zai_config_memoized_entry *memoized, zai_config_id id, bool in_request) {
// TODO Use less buffer space
// TODO Make a more generic zai_string_buffer
ZAI_ENV_BUFFER_INIT(buf, ZAI_ENV_MAX_BUFSIZ);
zai_option_str value = ZAI_OPTION_STR_NONE;
int16_t name_index = 0;
for (; name_index < memoized->names_count; name_index++) {
zai_str name = {.len = memoized->names[name_index].len, .ptr = memoized->names[name_index].ptr};
zai_config_stable_file_entry *entry = zai_config_stable_file_get_value(name);
if (entry && entry->source == DDOG_LIBRARY_CONFIG_SOURCE_FLEET_STABLE_CONFIG) {
strcpy(buf.ptr, ZSTR_VAL(entry->value));
zai_config_process_env(memoized, buf, &value);
name_index = ZAI_CONFIG_ORIGIN_FLEET_STABLE;
memoized->config_id = (zai_str) ZAI_STR_FROM_ZSTR(entry->config_id);
break;
} else {
// SAPI env (e.g. Apache SetEnv) takes priority over the sys env
// cache and must be checked here at first RINIT, not only in
// zai_config_ini_rinit. Code that runs between first_time_rinit
// and zai_config_ini_rinit--such as the signal handler setup that
// reads DD_TRACE_HEALTH_METRICS_ENABLED--relies on SAPI-provided
// values being present in the decoded config.
if (in_request && zai_sapi_getenv(name, &buf) == ZAI_ENV_SUCCESS) {
zai_config_process_env(memoized, buf, &value);
break;
}
const char *cached = zai_config_sys_env_cached(id, name_index);
if (cached) {
buf.ptr = (char *)cached;
buf.len = strlen(cached);
zai_config_process_env(memoized, buf, &value);
break;
}
}
if (entry && entry->source == DDOG_LIBRARY_CONFIG_SOURCE_LOCAL_STABLE_CONFIG) {
strcpy(buf.ptr, ZSTR_VAL(entry->value));
zai_config_process_env(memoized, buf, &value);
name_index = ZAI_CONFIG_ORIGIN_LOCAL_STABLE;
memoized->config_id = (zai_str) ZAI_STR_FROM_ZSTR(entry->config_id);
break;
}
}
ZAI_ENV_BUFFER_INIT(fallback_buf, ZAI_ENV_MAX_BUFSIZ);
if (!value.len && memoized->env_config_fallback && memoized->env_config_fallback(&fallback_buf, true)) {
zai_config_process_env(memoized, fallback_buf, &value);
name_index = ZAI_CONFIG_ORIGIN_MODIFIED;
buf = fallback_buf;
}
int16_t ini_name_index = zai_config_initialize_ini_value(memoized->ini_entries, memoized->names_count, &value,
memoized->default_encoded_value, id);
zai_str value_view;
if (zai_option_str_get(value, &value_view)) {
if (value_view.ptr != buf.ptr && ini_name_index >= 0) {
name_index = ini_name_index;
}
// TODO If name_index > 0, log deprecation notice
zval tmp;
ZVAL_UNDEF(&tmp);
zai_config_decode_value(value_view, memoized->type, memoized->parser, &tmp, /* persistent */ true);
assert(Z_TYPE(tmp) > IS_NULL);
zai_json_dtor_pzval(&memoized->decoded_value);
ZVAL_COPY_VALUE(&memoized->decoded_value, &tmp);
memoized->name_index = name_index;
}
// Nothing to do; default value was already decoded at MINIT
}
static void zai_config_copy_name(zai_config_name *dest, zai_str src) {
assert((src.len < ZAI_CONFIG_NAME_BUFSIZ) && "Name length greater than the buffer size");
strncpy(dest->ptr, src.ptr, src.len);
dest->len = src.len;
}
static zai_config_memoized_entry *zai_config_memoize_entry(zai_config_entry *entry) {
assert((entry->id < ZAI_CONFIG_ENTRIES_COUNT_MAX) && "Out of bounds config entry ID");
assert((entry->aliases_count < ZAI_CONFIG_NAMES_COUNT_MAX) &&
"Number of aliases + name are greater than ZAI_CONFIG_NAMES_COUNT_MAX");
zai_config_memoized_entry *memoized = &zai_config_memoized_entries[entry->id];
zai_config_copy_name(&memoized->names[0], entry->name);
for (uint8_t i = 0; i < entry->aliases_count; i++) {
zai_config_copy_name(&memoized->names[i + 1], entry->aliases[i]);
}
memoized->names_count = entry->aliases_count + 1;
memoized->type = entry->type;
memoized->default_encoded_value = entry->default_encoded_value;
memoized->parser = entry->parser;
memoized->displayer = entry->displayer;
ZVAL_UNDEF(&memoized->decoded_value);
if (!zai_config_decode_value(entry->default_encoded_value, memoized->type, memoized->parser, &memoized->decoded_value, /* persistent */ true)) {
assert(0 && "Error decoding default value");
}
memoized->name_index = ZAI_CONFIG_ORIGIN_DEFAULT;
memoized->original_on_modify = NULL;
memoized->env_config_fallback = entry->env_config_fallback;
memoized->ini_change = entry->ini_change;
return memoized;
}
static void zai_config_entries_init(zai_config_entry entries[], zai_config_id entries_count) {
assert((entries_count <= ZAI_CONFIG_ENTRIES_COUNT_MAX) &&
"Number of config entries are greater than ZAI_CONFIG_ENTRIES_COUNT_MAX");
zai_config_memoized_entries_count = entries_count;
zend_hash_init(&zai_config_name_map, entries_count * 2, NULL, NULL, /* persistent */ 1);
for (zai_config_id i = 0; i < entries_count; i++) {
zai_config_memoize_entry(&entries[i]);
}
}
static void zai_config_store_names(void) {
for (zai_config_id i = 0; i < zai_config_memoized_entries_count; i++) {
zai_config_memoized_entry *memoized = &zai_config_memoized_entries[i];
for (uint8_t n = 0; n < memoized->names_count; n++) {
zai_config_register_config_id(&memoized->names[n], i);
}
}
}
#if PHP_VERSION_ID >= 70300 && PHP_VERSION_ID < 70400
zend_new_interned_string_func_t zai_persistent_new_interned_string;
#endif
bool zai_config_minit(zai_config_entry entries[], size_t entries_count, zai_config_env_to_ini_name env_to_ini,
int module_number) {
if (!entries || !entries_count) return false;
if (!zai_json_setup_bindings()) return false;
zai_config_entries_init(entries, entries_count);
zai_config_ini_minit(env_to_ini, module_number);
zai_config_store_names();
zai_config_stable_file_minit();
#if PHP_VERSION_ID >= 70300 && PHP_VERSION_ID < 70400
zai_persistent_new_interned_string = zend_new_interned_string;
#endif
zai_config_cache_sys_env();
return true;
}
static void zai_config_dtor_memoized_zvals(void) {
for (uint16_t i = 0; i < zai_config_memoized_entries_count; i++) {
zai_json_dtor_pzval(&zai_config_memoized_entries[i].decoded_value);
}
}
void zai_config_mshutdown(void) {
zai_config_dtor_memoized_zvals();
zai_config_clear_sys_env_cache();
zai_config_memoized_entries_count = 0;
if (zai_config_name_map.nTableSize) {
zend_hash_destroy(&zai_config_name_map);
}
zai_config_ini_mshutdown();
zai_config_stable_file_mshutdown();
}
void zai_config_runtime_config_ctor(void);
void zai_config_runtime_config_dtor(void);
#if PHP_VERSION_ID < 70300
#define GC_ADD_FLAGS(c, flag) GC_FLAGS(c) |= flag
#define GC_ADDREF(p) ++GC_REFCOUNT(p)
#endif
static void zai_config_intern_zval(zval *pzval) {
if (Z_TYPE_P(pzval) == IS_STRING) {
#if PHP_VERSION_ID >= 70400
ZVAL_INTERNED_STR(pzval, zend_new_interned_string(Z_STR_P(pzval)));
#elif PHP_VERSION_ID >= 70300
ZVAL_INTERNED_STR(pzval, zai_persistent_new_interned_string(Z_STR_P(pzval)));
#else
GC_ADD_FLAGS(Z_STR_P(pzval), IS_STR_INTERNED);
Z_TYPE_INFO_P(pzval) = IS_INTERNED_STRING_EX;
#endif
}
if (Z_TYPE_P(pzval) == IS_ARRAY) {
GC_ADDREF(Z_ARR_P(pzval));
GC_ADD_FLAGS(Z_ARR_P(pzval), IS_ARRAY_IMMUTABLE);
#if PHP_VERSION_ID < 70200
Z_TYPE_FLAGS_P(pzval) = IS_TYPE_IMMUTABLE;
#elif PHP_VERSION_ID < 70300
Z_TYPE_FLAGS_P(pzval) = IS_TYPE_COPYABLE;
#else
Z_TYPE_FLAGS_P(pzval) = 0;
#endif
#if PHP_VERSION_ID >= 80200
if (HT_IS_PACKED(Z_ARR_P(pzval))) {
zval *zv;
ZEND_HASH_FOREACH_VAL(Z_ARR_P(pzval), zv) {
zai_config_intern_zval(zv);
} ZEND_HASH_FOREACH_END();
} else
#endif
{
Bucket *bucket;
ZEND_HASH_FOREACH_BUCKET(Z_ARR_P(pzval), bucket) {
if (bucket->key) {
#if PHP_VERSION_ID >= 70400
bucket->key = zend_new_interned_string(bucket->key);
#elif PHP_VERSION_ID >= 70300
bucket->key = zai_persistent_new_interned_string(bucket->key);
#else
GC_ADD_FLAGS(bucket->key, IS_STR_INTERNED);
#endif
}
zai_config_intern_zval(&bucket->val);
} ZEND_HASH_FOREACH_END();
}
}
}
void zai_config_first_time_rinit(bool in_request) {
// On PHP 7.3 zend_interned_strings_switch_storage has undesired side effects (it calls interned_string_copy_storage); hence we collect zend_new_interned_string_permanent via zai_persistent_new_interned_string at minit.
#if PHP_VERSION_ID >= 70400
if (in_request) {
zend_interned_strings_switch_storage(0);
}
#endif
// Non-CLI SAPIs (CGI/FPM/mod_php) may inject env vars before the first
// request, so refresh the cache to pick them up.
if (in_request && strcmp(sapi_module.name, "cli") != 0) {
zai_config_clear_sys_env_cache();
zai_config_cache_sys_env();
}
for (uint16_t i = 0; i < zai_config_memoized_entries_count; i++) {
zai_config_memoized_entry *memoized = &zai_config_memoized_entries[i];
if (!in_request || memoized->ini_change != zai_config_minit_ini_change) {
zai_config_find_and_set_value(memoized, i, in_request);
}
#if PHP_VERSION_ID >= 70300
zai_config_intern_zval(&memoized->decoded_value);
#else
if (in_request) {
zai_config_intern_zval(&memoized->decoded_value);
}
#endif
}
if (in_request) {
zai_config_first_rinit_done = true;
}
#if PHP_VERSION_ID >= 70400
if (in_request) {
zend_interned_strings_switch_storage(1);
}
#endif
}
void zai_config_rinit(void) {
zai_config_runtime_config_ctor();
zai_config_ini_rinit();
}
void zai_config_rshutdown(void) { zai_config_runtime_config_dtor(); }
bool zai_config_system_ini_change(zval *old_value, zval *new_value, zend_string *new_str) {
(void)old_value;
(void)new_value;
(void)new_str;
return false;
}
bool zai_config_minit_ini_change(zval *old_value, zval *new_value, zend_string *new_str) {
return zai_config_system_ini_change(old_value, new_value, new_str);
}