From cf63541ef72573d57c76e38b25fbcc8e7301f7f3 Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Tue, 8 Jul 2025 14:34:36 +1000 Subject: [PATCH 1/5] provide access to return_value, function's type, filename, line number When observing a function via observer API or zend_execute_*, these additional functions allow looking up the function's type and the filename (for user functions and eval'd code). From ExecuteData we can also retrieve the return value in a number of ways. --- phper/src/functions.rs | 22 +++++++++++++++++++++ phper/src/values.rs | 44 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/phper/src/functions.rs b/phper/src/functions.rs index 4bf4cca..4fbd13c 100644 --- a/phper/src/functions.rs +++ b/phper/src/functions.rs @@ -647,6 +647,28 @@ impl ZFunc { } } + /// Get the type of the function (ZEND_USER_FUNCTION, ZEND_INTERNAL_FUNCTION, etc). + pub fn get_type(&self) -> u8 { + unsafe { self.inner.type_ as u8 } + } + + /// For a user function or eval'd code, get the filename from op_array. + pub fn get_filename(&self) -> Option<&ZStr> { + unsafe { + match u32::from(self.inner.type_) { + ZEND_USER_FUNCTION | ZEND_EVAL_CODE => { + let filename_ptr = self.inner.op_array.filename; + if !filename_ptr.is_null() { + ZStr::try_from_ptr(filename_ptr) + } else { + None + } + } + _ => None, + } + } + } + /// Get the function or method fully-qualified name. pub fn get_function_or_method_name(&self) -> ZString { unsafe { diff --git a/phper/src/values.rs b/phper/src/values.rs index 8fa32df..bf3d526 100644 --- a/phper/src/values.rs +++ b/phper/src/values.rs @@ -130,6 +130,50 @@ impl ExecuteData { unsafe { ZFunc::from_mut_ptr(self.inner.func) } } + /// Gets the current opline line number if available. This represents the + /// line number in the source code where the current operation is being executed. + pub fn get_lineno(&self) -> Option { + unsafe { + match u32::from((*self.inner.func).type_) { + ZEND_USER_FUNCTION | ZEND_EVAL_CODE => { + let opline = self.inner.opline; + if !opline.is_null() { + Some((*opline).lineno as u32) + } else { + None + } + } + _ => None, + } + } + } + + /// Gets associated return value. + pub fn get_return_value(&self) -> Option<&ZVal> { + unsafe { + let val = self.inner.return_value; + ZVal::try_from_ptr(val) + } + } + + /// Gets associated return value. + pub fn get_return_value_mut(&mut self) -> Option<&mut ZVal> { + unsafe { + let val = self.inner.return_value; + ZVal::try_from_mut_ptr(val) + } + } + + /// Gets associated return value pointer. + pub fn get_return_value_mut_ptr(&mut self) -> *mut ZVal { + self.inner.return_value as *mut ZVal + } + + /// Gets associated return value pointer. + pub fn get_return_value_ptr(&self) -> *const ZVal { + self.inner.return_value as *const ZVal + } + /// Gets associated `$this` object if exists. pub fn get_this(&mut self) -> Option<&ZObj> { unsafe { From 8447e838299f56b09ec29f6e9212d3fa01aad2c4 Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Thu, 21 Aug 2025 14:38:55 +1000 Subject: [PATCH 2/5] format --- phper/src/functions.rs | 3 ++- phper/src/values.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/phper/src/functions.rs b/phper/src/functions.rs index 4fbd13c..e8881ee 100644 --- a/phper/src/functions.rs +++ b/phper/src/functions.rs @@ -647,7 +647,8 @@ impl ZFunc { } } - /// Get the type of the function (ZEND_USER_FUNCTION, ZEND_INTERNAL_FUNCTION, etc). + /// Get the type of the function (ZEND_USER_FUNCTION, + /// ZEND_INTERNAL_FUNCTION, etc). pub fn get_type(&self) -> u8 { unsafe { self.inner.type_ as u8 } } diff --git a/phper/src/values.rs b/phper/src/values.rs index bf3d526..92009ed 100644 --- a/phper/src/values.rs +++ b/phper/src/values.rs @@ -131,7 +131,8 @@ impl ExecuteData { } /// Gets the current opline line number if available. This represents the - /// line number in the source code where the current operation is being executed. + /// line number in the source code where the current operation is being + /// executed. pub fn get_lineno(&self) -> Option { unsafe { match u32::from((*self.inner.func).type_) { From a28927236c14143ea966b25e85757cb22a2cd483 Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Thu, 21 Aug 2025 14:45:47 +1000 Subject: [PATCH 3/5] clippy --- phper/src/functions.rs | 2 +- phper/src/values.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/phper/src/functions.rs b/phper/src/functions.rs index e8881ee..e3da965 100644 --- a/phper/src/functions.rs +++ b/phper/src/functions.rs @@ -650,7 +650,7 @@ impl ZFunc { /// Get the type of the function (ZEND_USER_FUNCTION, /// ZEND_INTERNAL_FUNCTION, etc). pub fn get_type(&self) -> u8 { - unsafe { self.inner.type_ as u8 } + unsafe { self.inner.type_ } } /// For a user function or eval'd code, get the filename from op_array. diff --git a/phper/src/values.rs b/phper/src/values.rs index 92009ed..c9cfbcc 100644 --- a/phper/src/values.rs +++ b/phper/src/values.rs @@ -139,7 +139,7 @@ impl ExecuteData { ZEND_USER_FUNCTION | ZEND_EVAL_CODE => { let opline = self.inner.opline; if !opline.is_null() { - Some((*opline).lineno as u32) + Some((*opline).lineno) } else { None } From 4521bbc4e668869c925372239ef2274d12c7a400 Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Thu, 21 Aug 2025 15:09:52 +1000 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- phper/src/values.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phper/src/values.rs b/phper/src/values.rs index c9cfbcc..4d2696c 100644 --- a/phper/src/values.rs +++ b/phper/src/values.rs @@ -157,7 +157,7 @@ impl ExecuteData { } } - /// Gets associated return value. + /// Gets mutable reference to associated return value. pub fn get_return_value_mut(&mut self) -> Option<&mut ZVal> { unsafe { let val = self.inner.return_value; @@ -170,7 +170,7 @@ impl ExecuteData { self.inner.return_value as *mut ZVal } - /// Gets associated return value pointer. + /// Gets immutable pointer to associated return value. pub fn get_return_value_ptr(&self) -> *const ZVal { self.inner.return_value as *const ZVal } From 7c905f3e55d36927e0ca4ea7127aef4d3dbf5d9e Mon Sep 17 00:00:00 2001 From: Brett McBride Date: Fri, 22 Aug 2025 11:33:18 +1000 Subject: [PATCH 5/5] update comment and switch if logic to match other code --- phper/src/functions.rs | 16 ++++++++-------- phper/src/values.rs | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/phper/src/functions.rs b/phper/src/functions.rs index e3da965..1180903 100644 --- a/phper/src/functions.rs +++ b/phper/src/functions.rs @@ -647,10 +647,10 @@ impl ZFunc { } } - /// Get the type of the function (ZEND_USER_FUNCTION, - /// ZEND_INTERNAL_FUNCTION, etc). - pub fn get_type(&self) -> u8 { - unsafe { self.inner.type_ } + /// Get the type of the function (sys::ZEND_USER_FUNCTION, + /// sys::ZEND_INTERNAL_FUNCTION, or sys::ZEND_EVAL_CODE). + pub fn get_type(&self) -> u32 { + unsafe { self.inner.type_ as u32 } } /// For a user function or eval'd code, get the filename from op_array. @@ -658,11 +658,11 @@ impl ZFunc { unsafe { match u32::from(self.inner.type_) { ZEND_USER_FUNCTION | ZEND_EVAL_CODE => { - let filename_ptr = self.inner.op_array.filename; - if !filename_ptr.is_null() { - ZStr::try_from_ptr(filename_ptr) - } else { + let ptr = self.inner.op_array.filename; + if ptr.is_null() { None + } else { + ZStr::try_from_ptr(ptr) } } _ => None, diff --git a/phper/src/values.rs b/phper/src/values.rs index c9cfbcc..76a8506 100644 --- a/phper/src/values.rs +++ b/phper/src/values.rs @@ -138,10 +138,10 @@ impl ExecuteData { match u32::from((*self.inner.func).type_) { ZEND_USER_FUNCTION | ZEND_EVAL_CODE => { let opline = self.inner.opline; - if !opline.is_null() { - Some((*opline).lineno) - } else { + if opline.is_null() { None + } else { + Some((*opline).lineno) } } _ => None,