Skip to content
This repository has been archived by the owner on Oct 6, 2023. It is now read-only.

Workaround for PHP bug 84130 #109

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions tests/php_bug_84130.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
--TEST--
Workaround for PHP Bug #81430
--SKIPIF--
<?php
if (PHP_VERSION_ID < 80000) {
echo "skip requires 8 due to attributes";
}
--FILE--
<?php
include __DIR__ . "/common.php";

#[\Attribute]
class A {
private $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
}

#[A("baz")]
class B {
public function getBar($input) { return $input * 2; }
}

#[A("bar")]
function B() {}

tideways_xhprof_enable();

$foo = new A("foo");

$b = new B();
var_dump($b->getBar(4));

$r = new \ReflectionFunction("B");
var_dump($r->getAttributes(A::class)[0]->newInstance());
var_dump(call_user_func([$r->getAttributes(A::class)[0], 'newInstance']));

$output = tideways_xhprof_disable();

print_canonical($output);
--EXPECTF--
int(8)
object(A)#5 (1) {
["foo":"A":private]=>
string(3) "bar"
}
object(A)#4 (1) {
["foo":"A":private]=>
string(3) "bar"
}
call_user_func==>ReflectionAttribute::newInstance: ct= 1; wt=*;
main() : ct= 1; wt=*;
main()==>B::getBar : ct= 1; wt=*;
main()==>ReflectionAttribute::newInstance: ct= 1; wt=*;
main()==>ReflectionFunction::__construct: ct= 1; wt=*;
main()==>ReflectionFunctionAbstract::getAttributes: ct= 2; wt=*;
main()==>call_user_func : ct= 1; wt=*;
main()==>tideways_xhprof_disable : ct= 1; wt=*;
main()==>var_dump : ct= 3; wt=*;
21 changes: 21 additions & 0 deletions tideways_xhprof.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ ZEND_DLEXPORT void tideways_xhprof_execute_internal(zend_execute_data *execute_d

#if PHP_VERSION_ID >= 80000
#include "zend_observer.h"
#include "Zend/zend_attributes.h"

static void tracer_observer_begin(zend_execute_data *ex) {
if (!TXRG(enabled)) {
Expand All @@ -49,6 +50,26 @@ static void tracer_observer_end(zend_execute_data *ex, zval *return_value) {
static zend_observer_fcall_handlers tracer_observer(zend_execute_data *execute_data) {
zend_function *func = execute_data->func;

if (func->common.scope != NULL &&
func->common.scope->attributes != NULL &&
zend_get_attribute_str(func->common.scope->attributes, "attribute", sizeof("attribute")-1) != NULL) {
/*
* This condition is a workaround for PHP bug #81430
* (https://bugs.php.net/bug.php?id=81430) which was introduced in PHP
* 8.0.12. We created a pull request
* (https://github.com/php/php-src/pull/7665) which will hopefully be
* merged and fix this bug in PHP 8.0.14.
*
* In PHP 8.0.12 a new check was introduced to
* zend_observer_fcall_end() which expects the run_time_cache of
* functions to be properly initialized. However, there are dummy
* frames where the run_time_cache__ptr is simply NULL, so where the
* cache is not properly initialized. This condition ensures that
* attribute based dummy frames have no observers.
*/
return (zend_observer_fcall_handlers) {NULL, NULL};
}

if (!func->common.function_name) {
return (zend_observer_fcall_handlers){NULL, NULL};
}
Expand Down