Skip to content

Commit e0019c6

Browse files
committed
Block remote config signals during ftp functions
These are sensitive to EINTR, so block the signal during their execution. Signed-off-by: Bob Weinand <[email protected]>
1 parent d1a8696 commit e0019c6

File tree

7 files changed

+93
-2
lines changed

7 files changed

+93
-2
lines changed

components-rs/ddtrace.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ struct ddog_RemoteConfigState *ddog_init_remote_config_state(const struct ddog_E
171171

172172
const char *ddog_remote_config_get_path(const struct ddog_RemoteConfigState *remote_config);
173173

174-
void ddog_process_remote_configs(struct ddog_RemoteConfigState *remote_config);
174+
bool ddog_process_remote_configs(struct ddog_RemoteConfigState *remote_config);
175175

176176
bool ddog_type_can_be_instrumented(const struct ddog_RemoteConfigState *remote_config,
177177
ddog_CharSlice typename_);

components-rs/remote_config.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,8 @@ pub extern "C" fn ddog_remote_config_get_path(remote_config: &RemoteConfigState)
243243
}
244244

245245
#[no_mangle]
246-
pub extern "C" fn ddog_process_remote_configs(remote_config: &mut RemoteConfigState) {
246+
pub extern "C" fn ddog_process_remote_configs(remote_config: &mut RemoteConfigState) -> bool {
247+
let mut has_updates = false;
247248
loop {
248249
match remote_config.manager.fetch_update() {
249250
RemoteConfigUpdate::None => break,
@@ -292,7 +293,9 @@ pub extern "C" fn ddog_process_remote_configs(remote_config: &mut RemoteConfigSt
292293
_ => (),
293294
},
294295
}
296+
has_updates = true
295297
}
298+
has_updates
296299
}
297300

298301
fn apply_config(

config.m4

+1
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ if test "$PHP_DDTRACE" != "no"; then
184184
ext/handlers_exception.c \
185185
ext/handlers_internal.c \
186186
ext/handlers_pcntl.c \
187+
ext/handlers_signal.c \
187188
ext/integrations/exec_integration.c \
188189
ext/integrations/integrations.c \
189190
ext/ip_extraction.c \

ext/handlers_internal.c

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ void ddtrace_free_unregistered_class(zend_class_entry *ce) {
3030
void ddtrace_curl_handlers_startup(void);
3131
void ddtrace_exception_handlers_startup(void);
3232
void ddtrace_pcntl_handlers_startup(void);
33+
void ddtrace_signal_block_handlers_startup(void);
3334

3435
#if PHP_VERSION_ID >= 80000 && PHP_VERSION_ID < 80200
3536
#include <hook/hook.h>
@@ -147,6 +148,8 @@ void ddtrace_internal_handlers_startup() {
147148
ddtrace_exception_handlers_startup();
148149

149150
ddtrace_exec_handlers_startup();
151+
// Block remote-config signals of some functions
152+
ddtrace_signal_block_handlers_startup();
150153
}
151154

152155
void ddtrace_internal_handlers_shutdown(void) {

ext/handlers_signal.c

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#include "handlers_api.h"
2+
#include "remote_config.h"
3+
#include <signal.h>
4+
#include <php.h>
5+
6+
/* We need to do signal blocking for the remote config signaling to not interfere with some PHP functions.
7+
* See e.g. https://github.com/php/php-src/issues/16800
8+
* I don't know the full problem space, so I expect there might be functions missing here, and we need to eventually expand this list.
9+
*/
10+
static void dd_handle_signal(zif_handler original_function, INTERNAL_FUNCTION_PARAMETERS) {
11+
sigset_t x;
12+
sigemptyset(&x);
13+
sigaddset(&x, SIGVTALRM);
14+
sigprocmask(SIG_BLOCK, &x, NULL);
15+
16+
original_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
17+
18+
sigprocmask(SIG_UNBLOCK, &x, NULL);
19+
ddtrace_check_for_new_config_now();
20+
}
21+
22+
#define BLOCKSIGFN(function) \
23+
static zif_handler dd_handle_signal_zif_##function;\
24+
static ZEND_FUNCTION(dd_handle_signal_##function) { \
25+
dd_handle_signal(dd_handle_signal_zif_##function, INTERNAL_FUNCTION_PARAM_PASSTHRU); \
26+
}
27+
28+
#define BLOCK(x) \
29+
x(ftp_alloc) \
30+
x(ftp_append) \
31+
x(ftp_cdup) \
32+
x(ftp_chdir) \
33+
x(ftp_chmod) \
34+
x(ftp_close) \
35+
x(ftp_connect) \
36+
x(ftp_delete) \
37+
x(ftp_exec) \
38+
x(ftp_fget) \
39+
x(ftp_fput) \
40+
x(ftp_get) \
41+
x(ftp_get_option) \
42+
x(ftp_login) \
43+
x(ftp_mdtm) \
44+
x(ftp_mkdir) \
45+
x(ftp_mlsd) \
46+
x(ftp_nb_continue) \
47+
x(ftp_nb_fget) \
48+
x(ftp_nb_fput) \
49+
x(ftp_nb_get) \
50+
x(ftp_nb_put) \
51+
x(ftp_nlist) \
52+
x(ftp_pasv) \
53+
x(ftp_put) \
54+
x(ftp_pwd) \
55+
x(ftp_quit) \
56+
x(ftp_raw) \
57+
x(ftp_rawlist) \
58+
x(ftp_rename) \
59+
x(ftp_rmdir) \
60+
x(ftp_site) \
61+
x(ftp_size) \
62+
x(ftp_ssl_connect) \
63+
x(ftp_systype) \
64+
65+
BLOCK(BLOCKSIGFN)
66+
67+
void ddtrace_signal_block_handlers_startup() {
68+
#define BLOCKFNENTRY(function) { ZEND_STRL(#function), &dd_handle_signal_zif_##function, ZEND_FN(dd_handle_signal_##function) },
69+
datadog_php_zif_handler handlers[] = { BLOCK(BLOCKFNENTRY) };
70+
71+
size_t handlers_len = sizeof handlers / sizeof handlers[0];
72+
for (size_t i = 0; i < handlers_len; ++i) {
73+
datadog_php_install_handler(handlers[i]);
74+
}
75+
}

ext/remote_config.c

+7
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ DDTRACE_PUBLIC void ddtrace_set_all_thread_vm_interrupt(void) {
5757
#endif
5858
}
5959

60+
void ddtrace_check_for_new_config_now(void) {
61+
if (DDTRACE_G(remote_config_state) && !DDTRACE_G(reread_remote_configuration) && ddog_process_remote_configs(DDTRACE_G(remote_config_state))) {
62+
// If we blocked the signal, notify the other threads too
63+
ddtrace_set_all_thread_vm_interrupt();
64+
}
65+
}
66+
6067
DDTRACE_PUBLIC const char *ddtrace_remote_config_get_path() {
6168
if (DDTRACE_G(remote_config_state)) {
6269
return ddog_remote_config_get_path(DDTRACE_G(remote_config_state));

ext/remote_config.h

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ void ddtrace_minit_remote_config(void);
77
void ddtrace_mshutdown_remote_config(void);
88
void ddtrace_rinit_remote_config(void);
99
void ddtrace_rshutdown_remote_config(void);
10+
void ddtrace_check_for_new_config_now(void);
11+
1012

1113
DDTRACE_PUBLIC void ddtrace_set_all_thread_vm_interrupt(void);
1214
DDTRACE_PUBLIC const char *ddtrace_remote_config_get_path(void);

0 commit comments

Comments
 (0)