Skip to content
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
22 changes: 13 additions & 9 deletions extension/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,16 +84,13 @@ static zend_always_inline zend_string *hp_get_trace_callback(zend_string *functi
callback = (hp_trace_callback*)zend_hash_find_ptr(XHPROF_G(trace_callbacks), function_name);
if (callback) {
trace_name = (*callback)(function_name, data);
} else {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously:

  • If a callback is found, release function_name and return trace_name
  • If no callback is found, return function_name directly without releasing it

return function_name;
zend_string_release(function_name);
return trace_name;
}
} else {
return function_name;
}

zend_string_release(function_name);

return trace_name;

/* No callback found, return the original function_name */
return function_name;
}

static zend_always_inline hp_entry_t *hp_fast_alloc_hprof_entry()
Expand All @@ -114,6 +111,7 @@ static zend_always_inline void hp_fast_free_hprof_entry(hp_entry_t *p)
{
if (p->name_hprof != NULL) {
zend_string_release(p->name_hprof);
p->name_hprof = NULL; /* Prevent double-free if entry is reused */
}

/* we use/overload the prev_hprof field in the structure to link entries in
Expand Down Expand Up @@ -161,7 +159,13 @@ static zend_always_inline int begin_profiling(zend_string *root_symbol, zend_exe
} else {
#if PHP_VERSION_ID >= 80000
hp_entry_t *cur_entry = hp_fast_alloc_hprof_entry();
(cur_entry)->name_hprof = zend_string_copy((*(entries))->name_hprof);
/* Check if entries is not NULL before dereferencing */
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously assumed *(entries) is always non-NULL when creating entries for ignored functions.

if (*(entries) != NULL) {
(cur_entry)->name_hprof = zend_string_copy((*(entries))->name_hprof);
} else {
/* If this is the first call and it's ignored, use the function name */
(cur_entry)->name_hprof = zend_string_copy(function_name);
}
(cur_entry)->prev_hprof = (*(entries));
(cur_entry)->is_trace = 0;
(*(entries)) = (cur_entry);
Expand Down
2 changes: 1 addition & 1 deletion extension/xhprof.c
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,7 @@ void hp_mode_hier_endfn_cb(hp_entry_t **entries)

#if PHP_VERSION_ID >= 80000
if (top->is_trace == 0) {
XHPROF_G(func_hash_counters[top->hash_code])--;
/* For ignored functions, don't decrement hash counter since it was never incremented */
Copy link
Author

@kasparsd kasparsd Jun 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously:

  • hp_mode_common_beginfn() was never called -> hash counter never incremented
  • hp_mode_hier_endfn_cb() was always decrementing the hash counter -> counter underflow

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, this should only affect PHP 8.4?

return;
}
#endif
Expand Down