Bug #77533 [Nab->Csd]: Found crash when appending element to pass-by-ref array with []

From: Date: Tue, 29 Jan 2019 02:32:48 +0000
Subject: Bug #77533 [Nab->Csd]: Found crash when appending element to pass-by-ref array with []
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-219262@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=77533&edit=1 ID: 77533 Updated by: timandes@php.net Reported by: timandes@php.net Summary: Found crash when appending element to pass-by-ref array with [] -Status: Not a bug +Status: Closed Type: Bug Package: Reproducible crash Operating System: CentOS Linux release 7.6.1810 (C PHP Version: 7.3.1 -Assigned To: +Assigned To: timandes Block user comment: N Private report: N Previous Comments: ------------------------------------------------------------------------ [2019-01-29 02:29:16] timandes@php.net I got this message when debug mode enabled: ``` php: /root/php-7.3.1/Zend/zend_hash.c:743: _zend_hash_str_add_or_update_i: Assertion `(zend_gc_refcount(&(ht)->gc) == 1) || ((ht)->u.flags & (1<<6))' failed. Aborted ``` Thank you very much. ------------------------------------------------------------------------ [2019-01-28 08:36:14] nikic@php.net You should always separate the array before modifying it, unless you know that you are the sole owner of the array (for example, because you only created it just now, already separated it, etc.) I would recommend compiling PHP with --enable-debug when developing extensions, as this will (usually) trigger assertion failures if you forget to separate something. ------------------------------------------------------------------------ [2019-01-28 08:22:43] timandes@php.net Thank you for your help. I have another question to ask: How can I know when to separate an array? ------------------------------------------------------------------------ [2019-01-28 08:14:33] nikic@php.net Should be: if (Z_TYPE_P(param) != IS_ARRAY) { zval_ptr_dtor(param); array_init(param); } else { SEPARATE_ARRAY(param); } You are trying to modify a potentially shared array without separating it first. In this case it is the empty array, which lives in read-only memory. ------------------------------------------------------------------------ [2019-01-28 02:43:12] timandes@php.net Description: ------------ Last week, I found a CI failure[1] of pecl/zookeeper. I thought it would be compatibility problem because I turned on PHP-7.3 in .travis.yml. When I looked into that issue, I found it's weird because the crash point was in the PHP src, and it only crashed when I passed an empty array to the function provided pass-by-ref var. So I wrote a small ext to reproduce that: ```c PHP_FUNCTION(caseone_test1) { zval *param; if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &param) == FAILURE) { return; } if (param) { ZVAL_DEREF(param); } if (Z_TYPE_P(param) != IS_ARRAY) { array_init(param); } add_assoc_long_ex(param, ZEND_STRL("foo"), 0); } ``` ```php $param = []; caseone_test1($param); ``` ```gdb #0 0x000056193020c64e in zend_hash_real_init_mixed_ex (ht=ht@entry=0x5619305fe220 <zend_empty_array>) at /usr/src/debug/php-7.3.1/Zend/zend_hash.c:131 #1 zend_hash_real_init_mixed (ht=ht@entry=0x5619305fe220 <zend_empty_array>) at /usr/src/debug/php-7.3.1/Zend/zend_hash.c:260 #2 0x000056193020db88 in _zend_hash_str_add_or_update_i (flag=1, pData=0x7fffbb8834d0, h=9223372037048267657, len=3, str=0x7ff29e4b7d93 "foo", ht=0x5619305fe220 <zend_empty_array>) at /usr/src/debug/php-7.3.1/Zend/zend_hash.c:746 #3 zend_hash_str_update (ht=ht@entry=0x5619305fe220 <zend_empty_array>, str=str@entry=0x7ff29e4b7d93 "foo", len=len@entry=3, pData=pData@entry=0x7fffbb8834d0) at /usr/src/debug/php-7.3.1/Zend/zend_hash.c:854 #4 0x00005619302021a8 in zend_symtable_str_update (pData=0x7fffbb8834d0, len=3, str=0x7ff29e4b7d93 "foo", ht=0x5619305fe220 <zend_empty_array>) at /usr/src/debug/php-7.3.1/Zend/zend_hash.h:498 #5 add_assoc_long_ex (arg=<optimized out>, key=key@entry=0x7ff29e4b7d93 "foo", key_len=key_len@entry=3, n=n@entry=0) at /usr/src/debug/php-7.3.1/Zend/zend_API.c:1359 #6 0x00007ff29e4b7c7c in zif_caseone_test1 (execute_data=<optimized out>, return_value=<optimized out>) at /root/php-7.3.1/ext/caseone/caseone.c:29 #7 0x000056193028b2f9 in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER () at /usr/src/debug/php-7.3.1/Zend/zend_vm_execute.h:645 #8 execute_ex (ex=0x5619305fe220 <zend_empty_array>) at /usr/src/debug/php-7.3.1/Zend/zend_vm_execute.h:55414 #9 0x000056193028f3a3 in zend_execute (op_array=op_array@entry=0x7ff2a267d2a0, return_value=0x0, return_value@entry=0x7ff2a267d3e0) at /usr/src/debug/php-7.3.1/Zend/zend_vm_execute.h:60834 #10 0x0000561930200622 in zend_execute_scripts (type=type@entry=8, retval=0x7ff2a267d3e0, retval@entry=0x0, file_count=-1570648016, file_count@entry=3) at /usr/src/debug/php-7.3.1/Zend/zend.c:1568 #11 0x00005619301a05d0 in php_execute_script (primary_file=primary_file@entry=0x7fffbb885b80) at /usr/src/debug/php-7.3.1/main/main.c:2630 #12 0x0000561930291892 in do_cli (argc=3, argv=0x561930f3f960) at /usr/src/debug/php-7.3.1/sapi/cli/php_cli.c:997 #13 0x000056193000121b in main (argc=3, argv=0x561930f3f960) at /usr/src/debug/php-7.3.1/sapi/cli/php_cli.c:1389 ``` When I changed the former PHP script to : ```php $param = ''; caseone_test1($param); ``` or ```php $param = [0]; caseone_test1($param); ``` , they worked fine. This issue can only be reproduced under Linux. I'm not sure it's a bug or not, so I turned to you guys for help. System info: ```shell uname -a Linux 93a912e38b29 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux ``` ```shell cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core) ``` [1] https://api.travis-ci.org/v3/job/484167428/log.txt ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=77533&edit=1

« previous php.bugs (#219262) next »