php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78698 Memory Leak in realpath_cache when using ZTS Embed SAPI
Submitted: 2019-10-19 20:14 UTC Modified: 2019-11-07 13:53 UTC
From: maroszek at gmx dot net Assigned:
Status: Closed Package: *General Issues
PHP Version: 7.3.10 OS: Ubuntu
Private report: No CVE-ID: None
 [2019-10-19 20:14 UTC] maroszek at gmx dot net
Description:
------------
Description:
------------
PHP 7.3.10 is current stable
PHP 7.3.10 is build as a static library

./configure '--disable-fpm' '--disable-cgi' '--disable-cli' '--enable-embed=static' '--enable-maintainer-zts' '--without-iconv'

g++ --version
> g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0

I build a simple example to demonstrate the leak.

Sourcecode: https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7

Copy leak.cpp into your php7 folder.

Compile with: g++ leak.cpp -Imain -ITSRM -IZend -I. --std=c++11 -Llibs -lphp7 -lxml2 -lresolv

test.php:
<?

Start it using valgrind: USE_ZEND_ALLOC=0 valgrind --leak-check=full ./a.out


Expected result:
----------------
No leak.

Actual result:
--------------

==25026== 
==25026== HEAP SUMMARY:
==25026==     in use at exit: 62,694 bytes in 570 blocks
==25026==   total heap usage: 311,182 allocs, 310,612 frees, 2,130,600,706 bytes allocated
==25026== 
==25026== 1,200 bytes in 50 blocks are definitely lost in loss record 21 of 31
==25026==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25026==    by 0x229A58: __zend_malloc (zend_alloc.c:2903)
==25026==    by 0x531B42: php_pcre2_general_context_create (pcre2_context.c:121)
==25026==    by 0x31E87C: php_pcre_init_pcre2 (php_pcre.c:170)
==25026==    by 0x31E941: zm_globals_ctor_pcre (php_pcre.c:266)
==25026==    by 0x1F01EB: allocate_new_resource (TSRM.c:317)
==25026==    by 0x1F07A0: ts_resource_ex (TSRM.c:375)
==25026==    by 0x1EDF5F: main::{lambda()#1}::operator()() const (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EE9EA: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EE805: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(std::__invoke_result&&, (main::{lambda()#1}&&)...) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EEC55: decltype (__invoke((_S_declval<0ul>)())) std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EEC11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026== 
==25026== 2,700 bytes in 50 blocks are definitely lost in loss record 24 of 31
==25026==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25026==    by 0x285EF2: realpath_cache_add (zend_virtual_cwd.c:645)
==25026==    by 0x285EF2: tsrm_realpath_r (zend_virtual_cwd.c:1213)
==25026==    by 0x285D62: tsrm_realpath_r (zend_virtual_cwd.c:1172)
==25026==    by 0x285D62: tsrm_realpath_r (zend_virtual_cwd.c:1172)
==25026==    by 0x285D62: tsrm_realpath_r (zend_virtual_cwd.c:1172)
==25026==    by 0x285D62: tsrm_realpath_r (zend_virtual_cwd.c:1172)
==25026==    by 0x286EE1: virtual_file_ex (zend_virtual_cwd.c:1353)
==25026==    by 0x288536: tsrm_realpath (zend_virtual_cwd.c:1943)
==25026==    by 0x1F8A8B: php_resolve_path (fopen_wrappers.c:568)
==25026==    by 0x583CCC: phar_find_in_include_path (util.c:282)
==25026==    by 0x20EEA2: _php_stream_open_wrapper_ex (streams.c:2006)
==25026==    by 0x1F2248: php_stream_open_for_zend_ex (main.c:1580)
==25026== 
==25026== 3,050 bytes in 50 blocks are definitely lost in loss record 25 of 31
==25026==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25026==    by 0x285EF2: realpath_cache_add (zend_virtual_cwd.c:645)
==25026==    by 0x285EF2: tsrm_realpath_r (zend_virtual_cwd.c:1213)
==25026==    by 0x285D62: tsrm_realpath_r (zend_virtual_cwd.c:1172)
==25026==    by 0x285D62: tsrm_realpath_r (zend_virtual_cwd.c:1172)
==25026==    by 0x285D62: tsrm_realpath_r (zend_virtual_cwd.c:1172)
==25026==    by 0x286EE1: virtual_file_ex (zend_virtual_cwd.c:1353)
==25026==    by 0x288536: tsrm_realpath (zend_virtual_cwd.c:1943)
==25026==    by 0x1F8A8B: php_resolve_path (fopen_wrappers.c:568)
==25026==    by 0x583CCC: phar_find_in_include_path (util.c:282)
==25026==    by 0x20EEA2: _php_stream_open_wrapper_ex (streams.c:2006)
==25026==    by 0x1F2248: php_stream_open_for_zend_ex (main.c:1580)
==25026==    by 0x27437B: zend_stream_fixup (zend_stream.c:174)
==25026== 
==25026== 3,500 bytes in 50 blocks are definitely lost in loss record 26 of 31
==25026==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25026==    by 0x285EF2: realpath_cache_add (zend_virtual_cwd.c:645)
==25026==    by 0x285EF2: tsrm_realpath_r (zend_virtual_cwd.c:1213)
==25026==    by 0x285D62: tsrm_realpath_r (zend_virtual_cwd.c:1172)
==25026==    by 0x285D62: tsrm_realpath_r (zend_virtual_cwd.c:1172)
==25026==    by 0x286EE1: virtual_file_ex (zend_virtual_cwd.c:1353)
==25026==    by 0x288536: tsrm_realpath (zend_virtual_cwd.c:1943)
==25026==    by 0x1F8A8B: php_resolve_path (fopen_wrappers.c:568)
==25026==    by 0x583CCC: phar_find_in_include_path (util.c:282)
==25026==    by 0x20EEA2: _php_stream_open_wrapper_ex (streams.c:2006)
==25026==    by 0x1F2248: php_stream_open_for_zend_ex (main.c:1580)
==25026==    by 0x27437B: zend_stream_fixup (zend_stream.c:174)
==25026==    by 0x218198: open_file_for_scanning (zend_language_scanner.l:515)
==25026== 
==25026== 3,600 bytes in 50 blocks are definitely lost in loss record 27 of 31
==25026==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25026==    by 0x229A58: __zend_malloc (zend_alloc.c:2903)
==25026==    by 0x531ABE: _pcre2_memctl_malloc_8 (pcre2_context.c:89)
==25026==    by 0x531B70: php_pcre2_compile_context_create (pcre2_context.c:150)
==25026==    by 0x31E84D: php_pcre_init_pcre2 (php_pcre.c:178)
==25026==    by 0x31E941: zm_globals_ctor_pcre (php_pcre.c:266)
==25026==    by 0x1F01EB: allocate_new_resource (TSRM.c:317)
==25026==    by 0x1F07A0: ts_resource_ex (TSRM.c:375)
==25026==    by 0x1EDF5F: main::{lambda()#1}::operator()() const (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EE9EA: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EE805: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(std::__invoke_result&&, (main::{lambda()#1}&&)...) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EEC55: decltype (__invoke((_S_declval<0ul>)())) std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026== 
==25026== 4,050 bytes in 50 blocks are definitely lost in loss record 28 of 31
==25026==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25026==    by 0x285EF2: realpath_cache_add (zend_virtual_cwd.c:645)
==25026==    by 0x285EF2: tsrm_realpath_r (zend_virtual_cwd.c:1213)
==25026==    by 0x285D62: tsrm_realpath_r (zend_virtual_cwd.c:1172)
==25026==    by 0x286EE1: virtual_file_ex (zend_virtual_cwd.c:1353)
==25026==    by 0x288536: tsrm_realpath (zend_virtual_cwd.c:1943)
==25026==    by 0x1F8A8B: php_resolve_path (fopen_wrappers.c:568)
==25026==    by 0x583CCC: phar_find_in_include_path (util.c:282)
==25026==    by 0x20EEA2: _php_stream_open_wrapper_ex (streams.c:2006)
==25026==    by 0x1F2248: php_stream_open_for_zend_ex (main.c:1580)
==25026==    by 0x27437B: zend_stream_fixup (zend_stream.c:174)
==25026==    by 0x218198: open_file_for_scanning (zend_language_scanner.l:515)
==25026==    by 0x218586: compile_file (zend_language_scanner.l:629)
==25026== 
==25026== 6,700 bytes in 50 blocks are definitely lost in loss record 29 of 31
==25026==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25026==    by 0x285EF2: realpath_cache_add (zend_virtual_cwd.c:645)
==25026==    by 0x285EF2: tsrm_realpath_r (zend_virtual_cwd.c:1213)
==25026==    by 0x286EE1: virtual_file_ex (zend_virtual_cwd.c:1353)
==25026==    by 0x288536: tsrm_realpath (zend_virtual_cwd.c:1943)
==25026==    by 0x1F8A8B: php_resolve_path (fopen_wrappers.c:568)
==25026==    by 0x583CCC: phar_find_in_include_path (util.c:282)
==25026==    by 0x20EEA2: _php_stream_open_wrapper_ex (streams.c:2006)
==25026==    by 0x1F2248: php_stream_open_for_zend_ex (main.c:1580)
==25026==    by 0x27437B: zend_stream_fixup (zend_stream.c:174)
==25026==    by 0x218198: open_file_for_scanning (zend_language_scanner.l:515)
==25026==    by 0x218586: compile_file (zend_language_scanner.l:629)
==25026==    by 0x437E10: phar_compile_file (phar.c:3347)
==25026== 
==25026== 7,200 (4,000 direct, 3,200 indirect) bytes in 50 blocks are definitely lost in loss record 30 of 31
==25026==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25026==    by 0x229A58: __zend_malloc (zend_alloc.c:2903)
==25026==    by 0x531ABE: _pcre2_memctl_malloc_8 (pcre2_context.c:89)
==25026==    by 0x531C00: php_pcre2_match_context_create (pcre2_context.c:182)
==25026==    by 0x31E8A5: php_pcre_init_pcre2 (php_pcre.c:192)
==25026==    by 0x31E941: zm_globals_ctor_pcre (php_pcre.c:266)
==25026==    by 0x1F01EB: allocate_new_resource (TSRM.c:317)
==25026==    by 0x1F07A0: ts_resource_ex (TSRM.c:375)
==25026==    by 0x1EDF5F: main::{lambda()#1}::operator()() const (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EE9EA: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EE805: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(std::__invoke_result&&, (main::{lambda()#1}&&)...) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EEC55: decltype (__invoke((_S_declval<0ul>)())) std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026== 
==25026== 29,600 bytes in 50 blocks are definitely lost in loss record 31 of 31
==25026==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==25026==    by 0x229A58: __zend_malloc (zend_alloc.c:2903)
==25026==    by 0x531ABE: _pcre2_memctl_malloc_8 (pcre2_context.c:89)
==25026==    by 0x571376: php_pcre2_match_data_create (pcre2_match_data.c:61)
==25026==    by 0x31E8D2: php_pcre_init_pcre2 (php_pcre.c:210)
==25026==    by 0x31E941: zm_globals_ctor_pcre (php_pcre.c:266)
==25026==    by 0x1F01EB: allocate_new_resource (TSRM.c:317)
==25026==    by 0x1F07A0: ts_resource_ex (TSRM.c:375)
==25026==    by 0x1EDF5F: main::{lambda()#1}::operator()() const (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EE9EA: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EE805: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(std::__invoke_result&&, (main::{lambda()#1}&&)...) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026==    by 0x1EEC55: decltype (__invoke((_S_declval<0ul>)())) std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/symcon/php-leak/php-7.3.10/a.out)
==25026== 
==25026== LEAK SUMMARY:
==25026==    definitely lost: 58,400 bytes in 450 blocks
==25026==    indirectly lost: 3,200 bytes in 100 blocks
==25026==      possibly lost: 0 bytes in 0 blocks
==25026==    still reachable: 1,094 bytes in 20 blocks
==25026==         suppressed: 0 bytes in 0 blocks
==25026== Reachable blocks (those to which a pointer was found) are not shown.
==25026== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==25026== 
==25026== For counts of detected and suppressed errors, rerun with: -v
==25026== ERROR SUMMARY: 9 errors from 9 contexts (suppressed: 0 from 0)


Test script:
---------------
<?php

//Leave it empty


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-11-07 11:03 UTC] maroszek at gmx dot net
I there anything i can provide or help to fix this issue?

Thanks!
 [2019-11-07 13:28 UTC] nikic@php.net
-Status: Open +Status: Feedback
 [2019-11-07 13:28 UTC] nikic@php.net
I believe you are just missing a ts_free_thread() at the end of your closure.

With that the only leak I get is:

==24486== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==24486==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==24486==    by 0x51D0DEA: tsrm_mutex_alloc (TSRM.c:672)
==24486==    by 0x50232F3: zm_globals_ctor_pcre (php_pcre.c:262)
==24486==    by 0x51CFF36: tsrm_update_active_threads (TSRM.c:284)
==24486==    by 0x51D012F: ts_allocate_id (TSRM.c:325)
==24486==    by 0x529B96C: zend_startup_module_ex (zend_API.c:1850)
==24486==    by 0x529BA49: zend_startup_module_zval (zend_API.c:1874)
==24486==    by 0x52ACD10: zend_hash_apply (zend_hash.c:1812)
==24486==    by 0x529C0CD: zend_startup_modules (zend_API.c:1985)
==24486==    by 0x51D7CA3: php_module_startup (main.c:2330)
==24486==    by 0x537BEC0: php_embed_startup (php_embed.c:108)
==24486==    by 0x537C024: php_embed_init (php_embed.c:198)
 [2019-11-07 13:33 UTC] nikic@php.net
I've fixed the remaining leak mentioned in my last comment in https://github.com/php/php-src/commit/6dcc0b859f5f31729ab3f1e776b067fb338b1978, so now I don't get any leaks anymore.
 [2019-11-07 13:53 UTC] maroszek at gmx dot net
-Status: Feedback +Status: Closed
 [2019-11-07 13:53 UTC] maroszek at gmx dot net
Thanks again! That did it. And thanks for fixing the last one.
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Thu Jul 09 11:01:24 2020 UTC