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
28 changes: 27 additions & 1 deletion extension/meminfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@
#include "SAPI.h"
#include "zend_API.h"

#define MEMINFO_DUMP_PARAMETERS "r|b"
#define MEMINFO_OBJECT_STORE_FIRST_VALID_INDEX 1

#if PHP_VERSION_ID >= 80000
ZEND_BEGIN_ARG_INFO_EX(arginfo_meminfo_dump, 0, 0, 1)
ZEND_ARG_INFO(0, output_stream)
ZEND_ARG_INFO(0, include_unreferenced)
ZEND_END_ARG_INFO()

const zend_function_entry meminfo_functions[] = {
Expand Down Expand Up @@ -53,13 +57,14 @@ zend_module_entry meminfo_module_entry = {
PHP_FUNCTION(meminfo_dump)
{
zval *zval_stream;
zend_bool include_unreferenced = 0;

int first_element = 1;

php_stream *stream;
HashTable visited_items;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zval_stream) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), MEMINFO_DUMP_PARAMETERS, &zval_stream, &include_unreferenced) == FAILURE) {
return;
}

Expand All @@ -78,6 +83,9 @@ PHP_FUNCTION(meminfo_dump)
php_stream_printf(stream, " \"items\": {\n");
meminfo_browse_exec_frames(stream, &visited_items, &first_element);
meminfo_browse_class_static_members(stream, &visited_items, &first_element);
if (include_unreferenced) {
meminfo_browse_object_store(stream, &visited_items, &first_element);
}

php_stream_printf(stream, "\n }\n");
php_stream_printf(stream, "}\n}\n");
Expand Down Expand Up @@ -186,6 +194,24 @@ void meminfo_browse_class_static_members(php_stream *stream, HashTable *visited
}
}

void meminfo_browse_object_store(php_stream *stream, HashTable *visited_items, int *first_element)
{
zend_objects_store *object_store = &EG(objects_store);
uint32_t object_index;

for (object_index = object_store->top; object_index-- > MEMINFO_OBJECT_STORE_FIRST_VALID_INDEX;) {
zend_object *object = object_store->object_buckets[object_index];
zval object_zval;

if (!IS_OBJ_VALID(object)) {
continue;
}

ZVAL_OBJ(&object_zval, object);
meminfo_zval_dump(stream, NULL, NULL, &object_zval, visited_items, first_element);
}
}

void meminfo_browse_zvals_from_symbol_table(php_stream *stream, char* frame_label, HashTable *p_symbol_table, HashTable * visited_items, int *first_element)
{
zval *zval_to_dump;
Expand Down
1 change: 1 addition & 0 deletions extension/php_meminfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ zend_ulong meminfo_get_element_size(zval* z);
// Functions to browse memory parts to record item
void meminfo_browse_exec_frames(php_stream *stream, HashTable *visited_items, int *first_element);
void meminfo_browse_class_static_members(php_stream *stream, HashTable *visited_items, int *first_element);
void meminfo_browse_object_store(php_stream *stream, HashTable *visited_items, int *first_element);

void meminfo_zval_dump(php_stream * stream, char * frame_label, zend_string * symbol_name, zval * zv, HashTable *visited_items, int *first_element);
void meminfo_hash_dump(php_stream *stream, HashTable *ht, zend_bool is_object, HashTable *visited_items, int *first_element);
Expand Down
34 changes: 34 additions & 0 deletions extension/tests/bug-github-83_unreferenced_cycle.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
Check that unreferenced circular object references are dumped
--SKIPIF--
<?php if (!extension_loaded('meminfo')) print 'skip'; ?>
--FILE--
<?php
class CycleNode
{
public $peer;
}

$first = new CycleNode();
$second = new CycleNode();
$first->peer = $second;
$second->peer = $first;
unset($first, $second);

$dump = fopen('php://memory', 'rw');
meminfo_dump($dump, true);
rewind($dump);
$meminfoData = json_decode(stream_get_contents($dump), true);
fclose($dump);

$cycleNodeCount = 0;
foreach ($meminfoData['items'] as $item) {
if (isset($item['class']) && $item['class'] === 'CycleNode') {
$cycleNodeCount++;
}
}

echo "Unreferenced cycle objects found: ".$cycleNodeCount."\n";
?>
--EXPECT--
Unreferenced cycle objects found: 2