Skip to content

Commit 16486c5

Browse files
authored
Merge branch 'master' into brian.marks/omit-sensitive-config-telemetry
2 parents 3346be4 + 47bcde2 commit 16486c5

11 files changed

Lines changed: 122 additions & 61 deletions

File tree

.gitlab/generate-package.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,8 @@ function appsec_image_from_tag_mapping(string $tag): string
12171217
- pecl install datadog_trace.tgz
12181218
- echo "extension=ddtrace.so" | sudo tee $(php -i | awk -F"=> " '/Scan this dir for additional .ini files/ {print $2}')/ddtrace.ini
12191219
- php --ri=ddtrace
1220+
# The Fabric proxy changes network failure semantics in PECL tests.
1221+
- unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy ALL_PROXY all_proxy
12201222
- TERM=dumb HTTPBIN_HOSTNAME=httpbin-integration HTTPBIN_PORT=8080 DATADOG_HAVE_DEV_ENV=1 DD_TRACE_GIT_METADATA_ENABLED=0 pecl run-tests --showdiff --ini=" -d datadog.trace.sources_path=" -p datadog_trace
12211223
after_script:
12221224
- mkdir artifacts

.gitlab/generate-tracer.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,8 @@ function before_script_steps($with_docker_auth = false) {
571571
- make composer_tests_update
572572
- .gitlab/wait-for-service-ready.sh
573573
script:
574+
# The Fabric proxy changes network failure semantics in integration tests.
575+
- unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy ALL_PROXY all_proxy
574576
- DD_TRACE_AGENT_TIMEOUT=1000 make $MAKE_TARGET RUST_DEBUG_BUILD=1 PHPUNIT_JUNIT="artifacts/tests/results.xml" <?= ASSERT_NO_MEMLEAKS ?>
575577
<?php after_script(".", true); ?>
576578
- find tests -type f \( -name 'phpunit_error.log' -o -name 'nginx_*.log' -o -name 'apache_*.log' -o -name 'php_fpm_*.log' -o -name 'dd_php_error.log' \) -exec cp --parents '{}' artifacts \;

.gitlab/run_php_language_tests.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#!/usr/bin/env bash
22
set -eo pipefail
33

4+
# The Fabric proxy changes network failure semantics and leaks HTTP_PROXY into $_SERVER.
5+
unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy ALL_PROXY all_proxy
6+
47
# Helper to parse version strings for comparison
58
function version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
69

appsec/cmake/run-tests-wrapper.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ else
6868
set -- "${@:1:$#-1}" "${EXTRA_FLAGS[@]}" "${!#}"
6969
fi
7070

71+
# The Fabric proxy leaks HTTP_PROXY into $_SERVER as a request header.
72+
unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy ALL_PROXY all_proxy
73+
7174
set -x
7275
exec "$@"
7376

profiling/src/allocation/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,10 @@ pub fn collect_allocation(ptr: *mut c_void, len: size_t) {
199199
// Check if there's a pending time interrupt that we can handle now
200200
// instead of waiting for an interrupt handler. This is slightly more
201201
// accurate and efficient, win-win.
202-
let interrupt_count = REQUEST_LOCALS
203-
.try_with_borrow(|locals| locals.interrupt_count.swap(0, Ordering::SeqCst))
204-
.unwrap_or(0);
202+
// SAFETY: allocation samples are collected on an initialized PHP request thread.
203+
let globals = unsafe { module_globals::get_profiler_globals() };
204+
// SAFETY: the current thread's module globals are valid through GSHUTDOWN.
205+
let interrupt_count = unsafe { (*globals).interrupt_count.swap(0, Ordering::Relaxed) };
205206

206207
// SAFETY: execute_data was provided by the engine, and the profiler
207208
// doesn't mutate it.

profiling/src/capi.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ extern "C" fn ddog_php_prof_trigger_time_sample() {
4646
if locals.system_settings().profiling_enabled {
4747
// Safety: only vm interrupts are stored there, or possibly null (edges only).
4848
if let Some(vm_interrupt) = unsafe { locals.vm_interrupt_addr.as_ref() } {
49-
locals.interrupt_count.fetch_add(1, Ordering::SeqCst);
49+
// SAFETY: this callback runs on an initialized PHP request thread.
50+
let globals = unsafe { crate::module_globals::get_profiler_globals() };
51+
// SAFETY: the current thread's module globals are valid through GSHUTDOWN.
52+
unsafe { (*globals).interrupt_count.fetch_add(1, Ordering::Relaxed) };
5053
vm_interrupt.store(true, Ordering::SeqCst);
5154
}
5255
}

profiling/src/lib.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,6 @@ pub struct RequestLocals {
425425
pub system_settings: ptr::NonNull<SystemSettings>,
426426
pub profiling_experimental_heap_live_enabled: bool,
427427

428-
pub interrupt_count: AtomicU32,
429428
pub vm_interrupt_addr: *const AtomicBool,
430429
}
431430

@@ -450,7 +449,6 @@ impl Default for RequestLocals {
450449
tags: vec![],
451450
system_settings: SystemSettings::get(),
452451
profiling_experimental_heap_live_enabled: false,
453-
interrupt_count: AtomicU32::new(0),
454452
vm_interrupt_addr: ptr::null_mut(),
455453
}
456454
}
@@ -738,8 +736,11 @@ extern "C" fn rinit(_type: c_int, _module_number: c_int) -> ZendResult {
738736
}
739737

740738
if let Some(profiler) = Profiler::get() {
739+
// SAFETY: PHP module globals are initialized for this request thread.
740+
let globals = unsafe { module_globals::get_profiler_globals() };
741741
let interrupt = VmInterrupt {
742-
interrupt_count_ptr: &locals.interrupt_count as *const AtomicU32,
742+
// SAFETY: `globals` is valid until this thread's GSHUTDOWN.
743+
interrupt_count_ptr: unsafe { ptr::addr_of!((*globals).interrupt_count) },
743744
engine_ptr: locals.vm_interrupt_addr,
744745
};
745746
profiler.add_interrupt(interrupt);
@@ -795,8 +796,11 @@ extern "C" fn rshutdown(_type: c_int, _module_number: c_int) -> ZendResult {
795796
// and we don't need to optimize for that.
796797
if system_settings.profiling_enabled {
797798
if let Some(profiler) = Profiler::get() {
799+
// SAFETY: PHP module globals remain initialized through RSHUTDOWN.
800+
let globals = unsafe { module_globals::get_profiler_globals() };
798801
let interrupt = VmInterrupt {
799-
interrupt_count_ptr: &locals.interrupt_count,
802+
// SAFETY: `globals` remains valid until this thread's GSHUTDOWN.
803+
interrupt_count_ptr: unsafe { ptr::addr_of!((*globals).interrupt_count) },
800804
engine_ptr: locals.vm_interrupt_addr,
801805
};
802806
profiler.remove_interrupt(interrupt);

profiling/src/module_globals.rs

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::allocation;
22
use core::cell::Cell;
33
use core::ffi::c_void;
44
use core::ptr;
5+
use core::sync::atomic::AtomicU32;
56

67
#[cfg(php_zend_mm_set_custom_handlers_ex)]
78
use crate::allocation::allocation_ge84::ZendMMState;
@@ -13,6 +14,12 @@ pub struct ProfilerGlobals {
1314
/// Wrapped in `Cell` to prevent torn reads/writes when allocation hooks
1415
/// are called re-entrantly during `rinit()`/`rshutdown()`.
1516
pub zend_mm_state: Cell<ZendMMState>,
17+
/// Number of profiler time interrupts pending for this PHP thread.
18+
///
19+
/// The profiler timer thread updates this through a pointer registered by
20+
/// the PHP thread, so the value must remain atomic despite living in
21+
/// thread-local PHP module globals.
22+
pub interrupt_count: AtomicU32,
1623
}
1724

1825
/// We need TSRM to call into GINIT and GSHUTDOWN to observe spawning and
@@ -29,6 +36,7 @@ pub static mut GLOBALS_ID: i32 = 0;
2936
#[cfg(not(php_zts))]
3037
pub static mut GLOBALS: ProfilerGlobals = ProfilerGlobals {
3138
zend_mm_state: Cell::new(ZendMMState::new()),
39+
interrupt_count: AtomicU32::new(0),
3240
};
3341

3442
#[cfg(php_zts)]
@@ -40,9 +48,13 @@ mod zts {
4048
}
4149

4250
#[inline]
43-
pub unsafe fn tsrmg_bulk(id: i32) -> *mut c_void {
44-
let tls = tsrm_get_ls_cache() as *mut *mut *mut c_void;
45-
let storage = *tls; // void** storage
51+
pub unsafe fn get_ls_cache() -> *mut c_void {
52+
tsrm_get_ls_cache()
53+
}
54+
55+
#[inline]
56+
pub unsafe fn tsrmg_bulk(ls_cache: *mut c_void, id: i32) -> *mut c_void {
57+
let storage = *(ls_cache as *mut *mut *mut c_void); // void** storage
4658

4759
// TSRM_UNSHUFFLE_RSRC_ID(id) is just `id - 1`.
4860
let idx = (id - 1) as usize;
@@ -51,6 +63,27 @@ mod zts {
5163
}
5264
}
5365

66+
#[cfg(php_zts)]
67+
#[inline]
68+
pub unsafe fn get_tsrm_ls_cache() -> *mut c_void {
69+
zts::get_ls_cache()
70+
}
71+
72+
#[cfg(php_zts)]
73+
#[inline]
74+
pub unsafe fn get_tsrm_resource_from_cache(ls_cache: *mut c_void, id: i32) -> *mut c_void {
75+
zts::tsrmg_bulk(ls_cache, id)
76+
}
77+
78+
#[cfg(php_zts)]
79+
#[inline]
80+
pub unsafe fn get_profiler_globals_from_cache(ls_cache: *mut c_void) -> *mut ProfilerGlobals {
81+
// SAFETY: As long as this is called during the times documented by
82+
// get_profiler_globals(), GLOBALS_ID will be set by PHP.
83+
let id = ptr::addr_of!(GLOBALS_ID).read();
84+
get_tsrm_resource_from_cache(ls_cache, id).cast()
85+
}
86+
5487
/// Returns a pointer to the profiler globals for the current thread.
5588
///
5689
/// # Safety
@@ -64,10 +97,7 @@ mod zts {
6497
pub unsafe fn get_profiler_globals() -> *mut ProfilerGlobals {
6598
#[cfg(php_zts)]
6699
{
67-
// SAFETY: As long as this is called during the times documented by
68-
// our own safety requirements, GLOBALS_ID will be set by PHP.
69-
let id = ptr::addr_of!(GLOBALS_ID).read();
70-
zts::tsrmg_bulk(id).cast()
100+
get_profiler_globals_from_cache(get_tsrm_ls_cache())
71101
}
72102

73103
#[cfg(not(php_zts))]
@@ -85,12 +115,13 @@ pub unsafe extern "C" fn ginit(_globals_ptr: *mut c_void) {
85115
#[cfg(php_zts)]
86116
crate::timeline::timeline_ginit();
87117

88-
// Initialize ZendMMState in PHP globals for ZTS builds. For NTS builds,
89-
// this was already done in its const initializer.
118+
// Initialize PHP globals for ZTS builds. For NTS builds, this was already
119+
// done in its const initializer.
90120
#[cfg(php_zts)]
91121
{
92122
let globals = _globals_ptr.cast::<ProfilerGlobals>();
93123
(*globals).zend_mm_state = Cell::new(ZendMMState::new());
124+
(*globals).interrupt_count = AtomicU32::new(0);
94125
}
95126

96127
// SAFETY: this is called in thread ginit as expected, and no other places.
@@ -113,3 +144,19 @@ pub unsafe extern "C" fn gshutdown(_globals_ptr: *mut c_void) {
113144
// SAFETY: this is called in thread gshutdown as expected, no other places.
114145
allocation::gshutdown();
115146
}
147+
148+
// Unit tests are not loaded by PHP, so provide the PHP globals and TSRM symbol
149+
// needed to link code retained in the test executable.
150+
#[cfg(test)]
151+
mod test_symbols {
152+
#[cfg(not(php_zts))]
153+
#[export_name = "compiler_globals"]
154+
static mut TEST_COMPILER_GLOBALS: core::mem::MaybeUninit<crate::zend::zend_compiler_globals> =
155+
core::mem::MaybeUninit::zeroed();
156+
157+
#[cfg(php_zts)]
158+
#[no_mangle]
159+
unsafe extern "C" fn tsrm_get_ls_cache() -> *mut core::ffi::c_void {
160+
core::ptr::null_mut()
161+
}
162+
}

profiling/src/profiling/interrupts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl InterruptManager {
5050
// Reset interrupt counter to prevent sampling during `mshutdown` (PHP 8.0 bug with
5151
// userland destructors), but leave the interrupt flag unchanged as other extensions
5252
// may have raised it.
53-
(*interrupt.interrupt_count_ptr).store(0, Ordering::SeqCst);
53+
(*interrupt.interrupt_count_ptr).store(0, Ordering::Relaxed);
5454
}
5555
}
5656

@@ -62,7 +62,7 @@ impl InterruptManager {
6262
pub(super) fn trigger_interrupts(&self) {
6363
let vm_interrupts = self.vm_interrupts.lock().unwrap();
6464
vm_interrupts.iter().for_each(|obj| unsafe {
65-
(*obj.interrupt_count_ptr).fetch_add(1, Ordering::SeqCst);
65+
(*obj.interrupt_count_ptr).fetch_add(1, Ordering::Relaxed);
6666
(*obj.engine_ptr).store(true, Ordering::SeqCst);
6767
});
6868
}

profiling/src/profiling/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,7 @@ impl Profiler {
11301130

11311131
/// Collect a stack sample with elapsed wall time. Collects CPU time if
11321132
/// it's enabled and available.
1133+
#[export_name = "ddog_php_prof_collect_time"]
11331134
#[cfg_attr(feature = "tracing", tracing::instrument(skip_all, level = "debug"))]
11341135
pub fn collect_time(&self, execute_data: *mut zend_execute_data, interrupt_count: u32) {
11351136
// todo: should probably exclude the wall and CPU time used by collecting the sample.

0 commit comments

Comments
 (0)