Skip to content

Commit 50ef567

Browse files
authored
Merge pull request #28 from drefixs/fix-memory-leak-bug
Fix memory leak bug
2 parents d2f837f + 2364479 commit 50ef567

File tree

4 files changed

+217
-10
lines changed

4 files changed

+217
-10
lines changed

extension/meminfo.c

+23-10
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ int meminfo_visit_item(const char * item_label, HashTable *visited_items)
380380
void meminfo_hash_dump(php_stream *stream, HashTable *ht, zend_bool is_object, HashTable *visited_items, int *first_element)
381381
{
382382
zval **zval;
383-
char *key;
383+
char *key, *char_buf;;
384384

385385
HashPosition pos;
386386
ulong num_key;
@@ -406,10 +406,13 @@ void meminfo_hash_dump(php_stream *stream, HashTable *ht, zend_bool is_object, H
406406
if (is_object) {
407407
const char *property_name, *class_name;
408408
int mangled = zend_unmangle_property_name(key, key_len - 1, &class_name, &property_name);
409-
410-
php_stream_printf(stream TSRMLS_CC, " \"%s\":\"%p\"", meminfo_escape_for_json(property_name), *zval );
409+
char_buf = meminfo_escape_for_json(property_name);
410+
php_stream_printf(stream TSRMLS_CC, " \"%s\":\"%p\"", char_buf, *zval );
411+
efree(char_buf);
411412
} else {
412-
php_stream_printf(stream TSRMLS_CC, " \"%s\":\"%p\"", meminfo_escape_for_json(key), *zval );
413+
char_buf = meminfo_escape_for_json(key);
414+
php_stream_printf(stream TSRMLS_CC, " \"%s\":\"%p\"", char_buf, *zval );
415+
efree(char_buf);
413416
}
414417

415418
break;
@@ -432,6 +435,7 @@ void meminfo_hash_dump(php_stream *stream, HashTable *ht, zend_bool is_object, H
432435
void meminfo_zval_dump(php_stream * stream, char * frame_label, char * symbol_name, zval * zv, HashTable *visited_items, int *first_element)
433436
{
434437
char zval_id[16];
438+
char *char_buf;
435439
sprintf(zval_id, "%p", zv);
436440

437441
if (meminfo_visit_item(zval_id, visited_items)) {
@@ -450,10 +454,14 @@ void meminfo_zval_dump(php_stream * stream, char * frame_label, char * symbol_na
450454

451455
if (frame_label) {
452456
if (symbol_name) {
453-
php_stream_printf(stream TSRMLS_CC, " \"symbol_name\" : \"%s\",\n", meminfo_escape_for_json(symbol_name));
457+
char_buf = meminfo_escape_for_json(symbol_name);
458+
php_stream_printf(stream TSRMLS_CC, " \"symbol_name\" : \"%s\",\n", char_buf);
459+
efree(char_buf);
454460
}
455461
php_stream_printf(stream TSRMLS_CC, " \"is_root\" : true,\n");
456-
php_stream_printf(stream TSRMLS_CC, " \"frame\" : \"%s\"\n", meminfo_escape_for_json(frame_label));
462+
char_buf = meminfo_escape_for_json(frame_label);
463+
php_stream_printf(stream TSRMLS_CC, " \"frame\" : \"%s\"\n", char_buf);
464+
efree(char_buf);
457465
} else {
458466
php_stream_printf(stream TSRMLS_CC, " \"is_root\" : false\n");
459467
}
@@ -466,7 +474,9 @@ void meminfo_zval_dump(php_stream * stream, char * frame_label, char * symbol_na
466474
int is_temp;
467475

468476
php_stream_printf(stream TSRMLS_CC, ",\n");
469-
php_stream_printf(stream TSRMLS_CC, " \"class\" : \"%s\",\n", meminfo_escape_for_json(meminfo_get_classname(zv->value.obj.handle)));
477+
char_buf = meminfo_escape_for_json(meminfo_get_classname(zv->value.obj.handle));
478+
php_stream_printf(stream TSRMLS_CC, " \"class\" : \"%s\",\n", char_buf);
479+
efree(char_buf);
470480
php_stream_printf(stream TSRMLS_CC, " \"object_handle\" : \"%d\",\n", zv->value.obj.handle);
471481

472482
properties = Z_OBJDEBUG_P(zv, is_temp);
@@ -486,6 +496,7 @@ void meminfo_zval_dump(php_stream * stream, char * frame_label, char * symbol_na
486496
php_stream_printf(stream TSRMLS_CC, "\n");
487497
}
488498
}
499+
489500
/**
490501
* Get size of an element
491502
*
@@ -522,11 +533,13 @@ zend_ulong meminfo_get_element_size(zval *zv)
522533
char * meminfo_escape_for_json(const char *s)
523534
{
524535
int new_str_len;
525-
char *s1;
536+
char *s1, *s2;
537+
s1 = php_str_to_str((char*)s, strlen(s), "\\", 1, "\\\\", 2, &new_str_len);
538+
s2 = php_str_to_str(s1, strlen(s1), "\"", 1, "\\\"", 2, &new_str_len);
526539

527-
s1 = php_str_to_str(s, strlen(s), "\\", 1, "\\\\", 2, &new_str_len);
540+
efree(s1);
528541

529-
return php_str_to_str(s1, strlen(s1), "\"", 1, "\\\"", 2, &new_str_len);
542+
return s2;
530543
}
531544

532545
/**

extension/tests/fixture/book.xml

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
3+
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
4+
]>
5+
<book id="listing">
6+
<title>My lists</title>
7+
<chapter id="books">
8+
<title>My books</title>
9+
<para>
10+
<informaltable>
11+
<tgroup cols="4">
12+
<thead>
13+
<row>
14+
<entry>Title</entry>
15+
<entry>Author</entry>
16+
<entry>Language</entry>
17+
<entry>ISBN</entry>
18+
</row>
19+
</thead>
20+
<tbody>
21+
<row>
22+
<entry>The Grapes of Wrath</entry>
23+
<entry>John Steinbeck</entry>
24+
<entry>en</entry>
25+
<entry>0140186409</entry>
26+
</row>
27+
<row>
28+
<entry>The Pearl</entry>
29+
<entry>John Steinbeck</entry>
30+
<entry>en</entry>
31+
<entry>014017737X</entry>
32+
</row>
33+
<row>
34+
<entry>Samarcande</entry>
35+
<entry>Amine Maalouf</entry>
36+
<entry>fr</entry>
37+
<entry>2253051209</entry>
38+
</row>
39+
<!-- TODO: I have a lot of remaining books to add.. -->
40+
</tbody>
41+
</tgroup>
42+
</informaltable>
43+
</para>
44+
</chapter>
45+
</book>

extension/tests/info_dump.phpt

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
--TEST--
2+
meminfo_objects_list with some objects
3+
--FILE--
4+
<?php
5+
$docTest = new DOMDocument();
6+
$docTest->load(__DIR__.'/fixture/book.xml');
7+
8+
$rFilePointer = fopen('php://memory', 'rw');
9+
10+
$arrayTest = [
11+
'itemBool' => true,
12+
'itemInteger' => 23,
13+
'itemDoubles' => 1.2e3,
14+
'itemNull' => null,
15+
'itemString' => 'hello',
16+
'itemObject' => $docTest,
17+
'itemArray' => (array) $docTest,
18+
'itemResource' => $rFilePointer,
19+
];
20+
21+
meminfo_info_dump($rFilePointer);
22+
23+
rewind($rFilePointer);
24+
$jsonO = json_decode(stream_get_contents($rFilePointer), true);
25+
fclose($rFilePointer);
26+
if (is_array($jsonO)) {
27+
$items = $jsonO['items'];
28+
printf(
29+
"meminfo_info_dump JSON decode ok\nz_val_count:%d\n",
30+
count($items)
31+
);
32+
uasort($items, function ($itemA, $itemB) {
33+
return $itemA['type'] > $itemB['type']
34+
|| ($itemA['type'] == $itemB['type'] && $itemA['size'] > $itemB['size']);
35+
});
36+
37+
foreach($items as $item){
38+
printf(
39+
"item type:%s size:%d\n",
40+
$item['type'],
41+
$item['size']
42+
);
43+
}
44+
} else {
45+
echo 'meminfo_info_dump JSON decode fail';
46+
}
47+
?>
48+
--EXPECT--
49+
meminfo_info_dump JSON decode ok
50+
z_val_count:62
51+
item type:array size:96
52+
item type:array size:96
53+
item type:array size:96
54+
item type:array size:96
55+
item type:array size:96
56+
item type:array size:96
57+
item type:array size:96
58+
item type:array size:96
59+
item type:boolean size:24
60+
item type:boolean size:24
61+
item type:boolean size:24
62+
item type:boolean size:24
63+
item type:boolean size:24
64+
item type:boolean size:24
65+
item type:boolean size:24
66+
item type:boolean size:24
67+
item type:boolean size:24
68+
item type:boolean size:24
69+
item type:double size:24
70+
item type:double size:24
71+
item type:integer size:24
72+
item type:integer size:24
73+
item type:integer size:24
74+
item type:integer size:24
75+
item type:null size:24
76+
item type:null size:24
77+
item type:null size:24
78+
item type:null size:24
79+
item type:null size:24
80+
item type:null size:24
81+
item type:null size:24
82+
item type:null size:24
83+
item type:null size:24
84+
item type:object size:56
85+
item type:resource size:24
86+
item type:string size:24
87+
item type:string size:24
88+
item type:string size:25
89+
item type:string size:25
90+
item type:string size:25
91+
item type:string size:25
92+
item type:string size:27
93+
item type:string size:27
94+
item type:string size:27
95+
item type:string size:29
96+
item type:string size:29
97+
item type:string size:29
98+
item type:string size:29
99+
item type:string size:33
100+
item type:string size:37
101+
item type:string size:46
102+
item type:string size:64
103+
item type:string size:64
104+
item type:string size:64
105+
item type:string size:84
106+
item type:string size:84
107+
item type:string size:84
108+
item type:string size:84
109+
item type:string size:84
110+
item type:string size:87
111+
item type:string size:87
112+
item type:string size:1054
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
meminfo_objects_list with some objects
3+
--FILE--
4+
<?php
5+
$docTest = new DOMDocument();
6+
$docTest->load(__DIR__.'/fixture/book.xml');
7+
8+
$rFilePointer = fopen('/dev/null', 'rw');
9+
10+
$arrayTest = [
11+
'itemBool' => true,
12+
'itemInteger' => 23,
13+
'itemDoubles' => 1.2e3,
14+
'itemNull' => null,
15+
'itemString' => 'hello',
16+
'itemObject' => $docTest,
17+
'itemArray' => (array) $docTest,
18+
'itemResource' => $rFilePointer,
19+
];
20+
$attemptCount = 1000;
21+
gc_collect_cycles();
22+
$startM = memory_get_usage(true);
23+
while ($attemptCount-- > 0) {
24+
meminfo_info_dump($rFilePointer);
25+
}
26+
fclose($rFilePointer);
27+
gc_collect_cycles();
28+
$endM = memory_get_usage(true);
29+
if ($endM / $startM < 2) {
30+
echo 'Memory leak test was successful';
31+
} else {
32+
echo "Memory leak test was failed\n";
33+
printf("Memory leak:%s bytes",$endM - $startM);
34+
}
35+
?>
36+
--EXPECT--
37+
Memory leak test was successful

0 commit comments

Comments
 (0)