Skip to content

Commit c83e161

Browse files
morrisonleviclaude
andcommitted
test(profiling): provide test stub for zend_generator_check_placeholder_frame
`cargo test` links the profiler as a regular binary, so the Zend symbol cannot be resolved the way it is for the cdylib (lazy, at PHP load time). Add a passthrough stub under CFG_STACK_WALKING_TESTS and swap the import in stack_walking.rs the same way ddog_php_prof_function_run_time_cache is handled. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7c12d42 commit c83e161

3 files changed

Lines changed: 26 additions & 6 deletions

File tree

profiling/src/bindings/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,13 @@ extern "C" {
365365
func: &zend_function,
366366
) -> Option<&mut [usize; 2]>;
367367

368+
/// mock for testing; passthrough stub for zend_generator_check_placeholder_frame
369+
/// so `cargo test` builds don't need PHP's Zend symbols at link time.
370+
#[cfg(feature = "stack_walking_tests")]
371+
pub fn ddog_test_zend_generator_check_placeholder_frame(
372+
ptr: *mut zend_execute_data,
373+
) -> *mut zend_execute_data;
374+
368375
/// Returns the PHP_VERSION_ID of the engine at run-time, not the version
369376
/// the extension was built against at compile-time.
370377
pub fn ddog_php_prof_php_version_id() -> u32;

profiling/src/php_ffi.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,11 @@ uintptr_t *ddog_php_prof_function_run_time_cache(zend_function const *func) {
383383
}
384384

385385
#if CFG_STACK_WALKING_TESTS
386+
zend_execute_data *ddog_test_zend_generator_check_placeholder_frame(zend_execute_data *ptr) {
387+
// Tests do not construct real generator placeholder frames; pass through.
388+
return ptr;
389+
}
390+
386391
uintptr_t *ddog_test_php_prof_function_run_time_cache(zend_function const *func) {
387392
#if CFG_RUN_TIME_CACHE
388393
if (_ignore_run_time_cache) return NULL;

profiling/src/profiling/stack_walking.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ mod detail {
300300
top_execute_data: *mut zend_execute_data,
301301
string_set: &mut StringSet,
302302
) -> Result<Backtrace, CollectStackSampleError> {
303+
#[cfg(feature = "stack_walking_tests")]
304+
use crate::bindings::ddog_test_zend_generator_check_placeholder_frame as zend_generator_check_placeholder_frame;
305+
#[cfg(not(feature = "stack_walking_tests"))]
306+
use crate::bindings::zend_generator_check_placeholder_frame;
307+
303308
let max_depth = 512;
304309
let mut samples = Vec::new();
305310
let mut execute_data_ptr = top_execute_data;
@@ -312,9 +317,8 @@ mod detail {
312317
// frame the same way zend_fetch_debug_backtrace and the observer
313318
// API do.
314319
if execute_data.func.is_null() {
315-
execute_data_ptr = unsafe {
316-
crate::bindings::zend_generator_check_placeholder_frame(execute_data_ptr)
317-
};
320+
execute_data_ptr =
321+
unsafe { zend_generator_check_placeholder_frame(execute_data_ptr) };
318322
}
319323
let Some(execute_data) = (unsafe { execute_data_ptr.as_ref() }) else {
320324
break;
@@ -497,6 +501,11 @@ mod detail {
497501
pub fn collect_stack_sample(
498502
top_execute_data: *mut zend_execute_data,
499503
) -> Result<Backtrace, CollectStackSampleError> {
504+
#[cfg(feature = "stack_walking_tests")]
505+
use crate::bindings::ddog_test_zend_generator_check_placeholder_frame as zend_generator_check_placeholder_frame;
506+
#[cfg(not(feature = "stack_walking_tests"))]
507+
use crate::bindings::zend_generator_check_placeholder_frame;
508+
500509
#[cfg(feature = "tracing")]
501510
let _span = tracing::trace_span!("collect_stack_sample").entered();
502511

@@ -506,9 +515,8 @@ mod detail {
506515

507516
while let Some(execute_data) = unsafe { execute_data_ptr.as_ref() } {
508517
if execute_data.func.is_null() {
509-
execute_data_ptr = unsafe {
510-
crate::bindings::zend_generator_check_placeholder_frame(execute_data_ptr)
511-
};
518+
execute_data_ptr =
519+
unsafe { zend_generator_check_placeholder_frame(execute_data_ptr) };
512520
}
513521
let Some(execute_data) = (unsafe { execute_data_ptr.as_ref() }) else {
514522
break;

0 commit comments

Comments
 (0)