diff --git a/profiling/src/allocation/allocation_ge84.rs b/profiling/src/allocation/allocation_ge84.rs index bc527e12bb1..817645f7ad1 100644 --- a/profiling/src/allocation/allocation_ge84.rs +++ b/profiling/src/allocation/allocation_ge84.rs @@ -3,8 +3,9 @@ use crate::allocation::ALLOCATION_PROFILING_SIZE; use crate::allocation::ALLOCATION_PROFILING_STATS; use crate::bindings::{self as zend}; use crate::PROFILER_NAME; +use lazy_static::lazy_static; use libc::{c_char, c_void, size_t}; -use log::{debug, trace, warn}; +use log::{debug, error, trace, warn}; use std::cell::UnsafeCell; use std::ptr; use std::sync::atomic::Ordering::SeqCst; @@ -95,12 +96,26 @@ macro_rules! tls_zend_mm_state { }; } +lazy_static! { + static ref JIT_ENABLED: bool = unsafe { zend::ddog_php_jit_enabled() }; +} + +pub fn first_rinit_should_disable_due_to_jit() -> bool { + if *JIT_ENABLED && zend::PHP_VERSION_ID >= 80400 { + error!("Memory allocation profiling will be disabled as long as JIT is active. To enable allocation profiling disable JIT. See https://github.com/DataDog/dd-trace-php/pull/3199"); + true + } else { + false + } +} + /// This initializes the thread locale variable `ZEND_MM_STATE` with respect to the currently /// installed `zend_mm_heap` in ZendMM. It guarantees compliance with the safety guarantees /// described in the `ZendMMState` structure, specifically for `ZendMMState::alloc`, /// `ZendMMState::realloc`, `ZendMMState::free`, `ZendMMState::gc` and `ZendMMState::shutdown`. /// This function may panic if called out of order! pub fn alloc_prof_ginit() { + unsafe { zend::ddog_php_opcache_init_handle() }; ZEND_MM_STATE.with(|cell| { let zend_mm_state = cell.get(); diff --git a/profiling/src/allocation/mod.rs b/profiling/src/allocation/mod.rs index f20e2e31be2..9e991a0a314 100644 --- a/profiling/src/allocation/mod.rs +++ b/profiling/src/allocation/mod.rs @@ -9,7 +9,7 @@ use std::cell::RefCell; use std::sync::atomic::AtomicU64; #[cfg(php_zend_mm_set_custom_handlers_ex)] -mod allocation_ge84; +pub mod allocation_ge84; #[cfg(not(php_zend_mm_set_custom_handlers_ex))] pub mod allocation_le83; diff --git a/profiling/src/config.rs b/profiling/src/config.rs index 03e5d3f44aa..f43882417da 100644 --- a/profiling/src/config.rs +++ b/profiling/src/config.rs @@ -1,4 +1,3 @@ -#[cfg(not(php_zend_mm_set_custom_handlers_ex))] use crate::allocation; use crate::bindings::zai_config_type::*; use crate::bindings::{ @@ -113,6 +112,10 @@ impl SystemSettings { if allocation::allocation_le83::first_rinit_should_disable_due_to_jit() { system_settings.profiling_allocation_enabled = false; } + #[cfg(php_zend_mm_set_custom_handlers_ex)] + if allocation::allocation_ge84::first_rinit_should_disable_due_to_jit() { + system_settings.profiling_allocation_enabled = false; + } swap(&mut system_settings, SYSTEM_SETTINGS.assume_init_mut()); } diff --git a/profiling/src/lib.rs b/profiling/src/lib.rs index 8efabf7d928..6ab33fd9476 100644 --- a/profiling/src/lib.rs +++ b/profiling/src/lib.rs @@ -791,7 +791,12 @@ unsafe extern "C" fn minfo(module_ptr: *mut zend::ModuleEntry) { if system_settings.profiling_allocation_enabled { yes } else if zend::ddog_php_jit_enabled() { - b"Not available due to JIT being active, see https://github.com/DataDog/dd-trace-php/pull/2088 for more information.\0" + // Work around version-specific issues. + if cfg!(not(php_zend_mm_set_custom_handlers_ex)) { + b"Not available due to JIT being active, see https://github.com/DataDog/dd-trace-php/pull/2088 for more information.\0" + } else { + b"Not available due to JIT being active, see https://github.com/DataDog/dd-trace-php/pull/3199 for more information.\0" + } } else if system_settings.profiling_enabled { no } else { diff --git a/profiling/tests/phpt/jit_01.phpt b/profiling/tests/phpt/jit_01.phpt index 60fce7135b1..e9cfa0cfd55 100644 --- a/profiling/tests/phpt/jit_01.phpt +++ b/profiling/tests/phpt/jit_01.phpt @@ -10,6 +10,8 @@ if (PHP_VERSION_ID >= 80208 || PHP_VERSION_ID >= 80121 && PHP_VERSION_ID < 80200 echo "skip: PHP Version >= 8.1.21 and >= 8.2.8 have a fix for this"; if (PHP_VERSION_ID < 80000) echo "skip: JIT requires PHP >= 8.0", PHP_EOL; +if (PHP_VERSION_ID >= 80300) + echo "skip: not affected version", PHP_EOL; if (!extension_loaded('datadog-profiling')) echo "skip: test requires datadog-profiling", PHP_EOL; $arch = php_uname('m'); diff --git a/profiling/tests/phpt/jit_02.phpt b/profiling/tests/phpt/jit_02.phpt index c23ae845812..18ce815356d 100644 --- a/profiling/tests/phpt/jit_02.phpt +++ b/profiling/tests/phpt/jit_02.phpt @@ -9,6 +9,8 @@ if (PHP_VERSION_ID < 80120 || PHP_VERSION_ID >= 80200 && PHP_VERSION_ID < 80207) echo "skip: unpatched PHP version, so JIT should be inactive"; if (PHP_VERSION_ID < 80000) echo "skip: JIT requires PHP >= 8.0", PHP_EOL; +if (PHP_VERSION_ID >= 80300) + echo "skip: not affected version", PHP_EOL; if (!extension_loaded('datadog-profiling')) echo "skip: test requires datadog-profiling", PHP_EOL; $arch = php_uname('m'); diff --git a/profiling/tests/phpt/jit_03.phpt b/profiling/tests/phpt/jit_03.phpt new file mode 100644 index 00000000000..52ad2da1fdc --- /dev/null +++ b/profiling/tests/phpt/jit_03.phpt @@ -0,0 +1,29 @@ +--TEST-- +[profiling] Allocation profiling should be disabled when JIT is active on PHP 8.4 +--DESCRIPTION-- +We did find a crash in PHP when collecting a stack sample in allocation +profiling when JIT is activated while a function becomes hot. For the time being +we make sure to disable allocation profiling when we detect the JIT is enabled. +--SKIPIF-- + +--INI-- +datadog.profiling.enabled=yes +datadog.profiling.log_level=debug +datadog.profiling.allocation_enabled=yes +datadog.profiling.experimental_cpu_time_enabled=no +zend_extension=opcache +opcache.enable_cli=1 +opcache.jit=tracing +opcache.jit_buffer_size=4M +--FILE-- + +--EXPECTF-- +%aMemory allocation profiling will be disabled as long as JIT is active. To enable allocation profiling disable JIT. See https://github.com/DataDog/dd-trace-php/pull/3199 +%ADone.%a diff --git a/profiling/tests/phpt/phpinfo_04.phpt b/profiling/tests/phpt/phpinfo_04.phpt index 12f9c42978d..c34aa5e6ca6 100644 --- a/profiling/tests/phpt/phpinfo_04.phpt +++ b/profiling/tests/phpt/phpinfo_04.phpt @@ -5,7 +5,7 @@ The profiler's phpinfo section contains important debugging information. This test verifies that certain information is present. --SKIPIF-- = 80200 && PHP_VERSION_ID < 80207) +if (PHP_VERSION_ID < 80120 || PHP_VERSION_ID >= 80200 && PHP_VERSION_ID < 80207 || PHP_VERSION_ID >= 80400) echo "skip: unpatched PHP version, so JIT should be inactive"; if (PHP_VERSION_ID < 80000) echo "skip: JIT requires PHP >= 8.0", PHP_EOL;