Bug #78379 [Csd->ReO]: Cast to object confuses GC, causes crash
| From: | dmitry@php.net | Date: | Thu, 08 Aug 2019 08:03:25 +0000 |
| Subject: | Bug #78379 [Csd->ReO]: Cast to object confuses GC, causes crash | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-222134@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=78379&edit=1
ID: 78379
Updated by: dmitry@php.net
Reported by: tstarling@php.net
Summary: Cast to object confuses GC, causes crash
-Status: Closed
+Status: Re-Opened
Type: Bug
Package: Reproducible crash
Operating System: Linux
PHP Version: 7.2Git-2019-08-06 (Git)
Block user comment: N
Private report: N
New Comment:
The committed patch https://github.com/php/php-src/commit/358379be22c4e20f4942737e0e90422977355c63
doesn't fix the second problem.
Previous Comments:
------------------------------------------------------------------------
[2019-08-08 07:09:12] dmitry@php.net
Automatic comment on behalf of dmitry@zend.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=358379be22c4e20f4942737e0e90422977355c63
Log: Fixed bug #78379 (Cast to object confuses GC, causes crash)
------------------------------------------------------------------------
[2019-08-08 03:13:37] tstarling@php.net
Your patch prevents the array being freed, but it doesn't stop its reference count from going
negative, since gc_mark_grey() is still the same, and it won't collect cycles that include the
shared array as part of the loop. Both issues can be seen in this test case:
class E {}
function f() {
$e1 = new E;
$e2 = new E;
$a = ['e2' => $e2];
$e1->a = (object)$a;
$e2->e1 = $e1;
$e2->a = (object)$a;
}
f();
gc_collect_cycles();
echo "End\n";
With ZEND_GC_DEBUG=2 you can see it report rc=-1 for object(E)#2, then it says there is
"Nothing to free".
It's just a memory leak rather than a crash, but I'm considering doing a patch of my own
along the lines of the third paragraph of the bug description, so we can see if that looks better.
------------------------------------------------------------------------
[2019-08-07 11:36:23] dmitry@php.net
This patch seems to fix the problem, but it may be incomplete.
https://gist.github.com/dstogov/43a992d481f65ac16c454e1a292be38e
------------------------------------------------------------------------
[2019-08-07 07:48:46] dmitry@php.net
Confirmed. With [1] instead of [], valgrind reports use-after-free problem on PHP-7.2/master (only
without opcache).
==13484== Invalid read of size 4
==13484== at 0x85ED763: php_var_dump (var.c:130)
==13484== by 0x85ED5A6: php_object_property_dump (var.c:87)
==13484== by 0x85EDADE: php_var_dump (var.c:179)
==13484== by 0x85ED5A6: php_object_property_dump (var.c:87)
==13484== by 0x85EDADE: php_var_dump (var.c:179)
==13484== by 0x85EDDAA: zif_var_dump (var.c:223)
==13484== by 0x8765BEA: ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1268)
==13484== by 0x87B8966: execute_ex (zend_vm_execute.h:54223)
==13484== by 0x87BC23A: zend_execute (zend_vm_execute.h:58327)
==13484== by 0x871039F: zend_execute_scripts (zend.c:1631)
==13484== by 0x869EFFE: php_execute_script (main.c:2585)
==13484== by 0x87BE502: do_cli (php_cli.c:962)
==13484== Address 0xa61718c is 4 bytes inside a block of size 44 free'd
==13484== at 0x4036729: free (vg_replace_malloc.c:540)
==13484== by 0x86E5407: _efree_custom (zend_alloc.c:2411)
==13484== by 0x86E5504: _efree (zend_alloc.c:2531)
==13484== by 0x873B0EA: zend_gc_collect_cycles (zend_gc.c:1560)
==13484== by 0x87256B1: zif_gc_collect_cycles (zend_builtin_functions.c:362)
==13484== by 0x8765BEA: ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:1268)
==13484== by 0x87B8966: execute_ex (zend_vm_execute.h:54223)
==13484== by 0x87BC23A: zend_execute (zend_vm_execute.h:58327)
==13484== by 0x871039F: zend_execute_scripts (zend.c:1631)
==13484== by 0x869EFFE: php_execute_script (main.c:2585)
==13484== by 0x87BE502: do_cli (php_cli.c:962)
==13484== by 0x87BF11F: main (php_cli.c:1352)
==13484== Block was alloc'd at
==13484== at 0x40356A4: malloc (vg_replace_malloc.c:309)
==13484== by 0x86E60DC: __zend_malloc (zend_alloc.c:2961)
==13484== by 0x86E53B1: _malloc_custom (zend_alloc.c:2402)
==13484== by 0x86E54A3: _emalloc (zend_alloc.c:2521)
==13484== by 0x871CC8D: _zend_new_array (zend_hash.c:256)
==13484== by 0x86F66FB: zend_try_ct_eval_array (zend_compile.c:6965)
==13484== by 0x86FAD01: zend_eval_const_expr (zend_compile.c:8774)
------------------------------------------------------------------------
[2019-08-07 00:59:30] tstarling@php.net
Changing the empty array in the test case to a non-empty compile-time constant like [1] allows it to
be reproduced in PHP 7.3 and git master. It was just the immutable empty array that stopped the test
from working.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=78379
--
Edit this bug report at https://bugs.php.net/bug.php?id=78379&edit=1