php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #77922 Double release of doc comment on inherited shadow property
Submitted: 2019-04-19 06:34 UTC Modified: 2019-08-17 08:56 UTC
Votes:6
Avg. Score:4.0 ± 1.0
Reproduced:6 of 6 (100.0%)
Same Version:2 (33.3%)
Same OS:0 (0.0%)
From: enumag at gmail dot com Assigned:
Status: Closed Package: Unknown/Other Function
PHP Version: 7.3.4 OS: Ubuntu
Private report: No CVE-ID: None
 [2019-04-19 06:34 UTC] enumag at gmail dot com
Description:
------------
Since we upgraded to PHP 7.3 our phpunit tests crash with segfault. It's not one specific test though, it only happens when running the whole suite.

I tried to generate the backtrace (https://bugs.php.net/bugs-generating-backtrace.php) and I'm posting it below. Hopefully I did it correctly but it's the first time I did something like that. Let me know if it's not enough.


Actual result:
--------------
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
PHPUnit 7.5.8 by Sebastian Bergmann and contributors.

.............................................................   61 / 1036 (  5%)
.............................................................  122 / 1036 ( 11%)
.............................................................  183 / 1036 ( 17%)
.............................................................  244 / 1036 ( 23%)
.............................................................  305 / 1036 ( 29%)
.....
Program received signal SIGSEGV, Segmentation fault.
zend_mm_alloc_small (bin_num=<optimized out>, size=56, heap=0x7ffff3000040) at ./Zend/zend_alloc.c:1289
1289	./Zend/zend_alloc.c: No such file or directory.
(gdb) bt
#0  zend_mm_alloc_small (bin_num=<optimized out>, size=56, heap=0x7ffff3000040) at ./Zend/zend_alloc.c:1289
#1  zend_mm_alloc_heap (size=56, heap=0x7ffff3000040) at ./Zend/zend_alloc.c:1360
#2  _emalloc (size=size@entry=56) at ./Zend/zend_alloc.c:2500
#3  0x00005555557e4445 in zend_string_alloc (persistent=0, len=28) at ./Zend/zend_string.h:133
#4  zend_string_tolower_ex (str=0x7fffe06bb000, persistent=persistent@entry=0) at ./Zend/zend_operators.c:2677
#5  0x00005555557df85f in zend_lookup_class_ex (name=name@entry=0x7fffe06bb000, key=key@entry=0x0, use_autoload=use_autoload@entry=1) at ./Zend/zend_execute_API.c:851
#6  0x00005555557ed333 in zend_is_callable_check_class (name=<optimized out>, scope=0x7ffff30c3428, fcc=fcc@entry=0x7fffffffa2e0, strict_class=strict_class@entry=0x7fffffffa2d8, error=error@entry=0x0)
    at ./Zend/zend_API.c:2957
#7  0x00005555557f3982 in zend_is_callable_impl (error=0x0, fcc=0x7fffffffa2e0, check_flags=<optimized out>, object=0x0, callable=0x7ffff3025c90) at ./Zend/zend_API.c:3406
#8  zend_is_callable_ex (callable=0x7ffff3025c90, object=0x0, check_flags=<optimized out>, callable_name=0x0, fcc=<optimized out>, error=0x0) at ./Zend/zend_API.c:3460
#9  0x00005555558793b0 in zend_check_type (is_return_type=<optimized out>, scope=<optimized out>, default_value=<optimized out>, cache_slot=<optimized out>, ce=<optimized out>, arg=0x7ffff3000070, 
    type=<optimized out>) at ./Zend/zend_execute.c:929
#10 zend_verify_arg_type (cache_slot=<optimized out>, default_value=<optimized out>, arg=<optimized out>, arg_num=<optimized out>, zf=<optimized out>) at ./Zend/zend_execute.c:958
#11 ZEND_RECV_INIT_SPEC_CONST_HANDLER () at ./Zend/zend_vm_execute.h:2251
#12 execute_ex (ex=0x2c04b90) at ./Zend/zend_vm_execute.h:55601
#13 0x000055555587bcb3 in zend_execute (op_array=op_array@entry=0x7ffff30822a0, return_value=0x0, return_value@entry=0x7ffff30b1d20) at ./Zend/zend_vm_execute.h:60881
#14 0x00005555557ece22 in zend_execute_scripts (type=type@entry=8, retval=0x7ffff30b1d20, retval@entry=0x0, file_count=-217949136, file_count@entry=3) at ./Zend/zend.c:1568
#15 0x000055555578ce70 in php_execute_script (primary_file=0x7fffffffc9a0) at ./main/main.c:2630
#16 0x000055555587e18c in do_cli (argc=6, argv=0x555555bfa570) at ./sapi/cli/php_cli.c:997
#17 0x000055555564490b in main (argc=6, argv=0x555555bfa570) at ./sapi/cli/php_cli.c:1389


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-04-23 09:19 UTC] nikic@php.net
Would it be possible for you to run the test suite under "USE_ZEND_ALLOC=0 valgrind php" and post the resulting log?
 [2019-04-24 13:31 UTC] enumag at gmail dot com
Here you go: https://gist.github.com/enumag/639017e964036e5a5576962ce0934a8b
 [2019-04-24 13:46 UTC] nikic@php.net
Thanks! The first non-spurious warning is:


==32207== Invalid read of size 4
==32207==    at 0x3C7A2E: gc_mark_grey (zend_gc.c:901)
==32207==    by 0x3C7A2E: gc_mark_roots (zend_gc.c:960)
==32207==    by 0x3C7A2E: zend_gc_collect_cycles (zend_gc.c:1443)
==32207==    by 0x3C68B7: gc_possible_root_when_full (zend_gc.c:577)
==32207==    by 0x42C233: zend_object_release (zend_objects_API.h:79)
==32207==    by 0x42C233: execute_ex (zend_vm_execute.h:55359)
==32207==    by 0x42FCB2: zend_execute (zend_vm_execute.h:60881)
==32207==    by 0x3A0E21: zend_execute_scripts (zend.c:1568)
==32207==    by 0x340E6F: php_execute_script (main.c:2630)
==32207==    by 0x43218B: do_cli (php_cli.c:997)
==32207==    by 0x1F890A: main (php_cli.c:1389)
==32207==  Address 0x1d757ae4 is 4 bytes inside a block of size 40 free'd
==32207==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32207==    by 0x3CA5F0: zend_string_release (zend_string.h:277)
==32207==    by 0x3CA5F0: zend_new_interned_string_request (zend_string.c:232)
==32207==    by 0x3827D1: zend_begin_method_decl (zend_compile.c:5817)
==32207==    by 0x38F3B5: zend_compile_func_decl (zend_compile.c:6037)
==32207==    by 0x38D109: zend_compile_stmt (zend_compile.c:8277)
==32207==    by 0x38E326: zend_compile_stmt_list (zend_compile.c:5434)
==32207==    by 0x38CFF1: zend_compile_stmt (zend_compile.c:8221)
==32207==    by 0x38E681: zend_compile_class_decl (zend_compile.c:6491)
==32207==    by 0x38D117: zend_compile_stmt (zend_compile.c:8289)
==32207==    by 0x38FED4: zend_compile_top_stmt (zend_compile.c:8195)
==32207==    by 0x38FEC0: zend_compile_top_stmt (zend_compile.c:8190)
==32207==    by 0x368558: zend_compile (zend_language_scanner.l:602)
==32207==  Block was alloc'd at
==32207==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==32207==    by 0x377168: __zend_malloc (zend_alloc.c:2903)
==32207==    by 0x398444: zend_string_alloc (zend_string.h:133)
==32207==    by 0x398444: zend_string_tolower_ex (zend_operators.c:2677)
==32207==    by 0x3827C5: zend_begin_method_decl (zend_compile.c:5816)
==32207==    by 0x38F3B5: zend_compile_func_decl (zend_compile.c:6037)
==32207==    by 0x38D109: zend_compile_stmt (zend_compile.c:8277)
==32207==    by 0x38E326: zend_compile_stmt_list (zend_compile.c:5434)
==32207==    by 0x38CFF1: zend_compile_stmt (zend_compile.c:8221)
==32207==    by 0x38E681: zend_compile_class_decl (zend_compile.c:6491)
==32207==    by 0x38D117: zend_compile_stmt (zend_compile.c:8289)
==32207==    by 0x38FED4: zend_compile_top_stmt (zend_compile.c:8195)
==32207== by 0x38FEC0: zend_compile_top_stmt (zend_compile.c:8190)

The warning indicates a use-after-free of https://github.com/php/php-src/blob/191e15309fce3df7839e52b1f488b0be83fa8561/Zend/zend_compile.c#L5816. That seems rather unlikely, so it's probably hitting that piece of memory by coincidence :/
 [2019-04-24 18:59 UTC] enumag at gmail dot com
How do we fix it then? Is there anything else I can do to help? This is currently blocking us from upgrading to PHP 7.3.
 [2019-05-04 09:21 UTC] enumag at gmail dot com
Note: This bug still exists in PHP 7.3.5.
 [2019-05-21 10:09 UTC] wskorodecki at gmail dot com
I'm facing the same problem on PHP 7.3.5 on Archlinux but my stacktrace is different. Interesting here is that the error does not occur when I execute "phpunit -v" outside our Symfony-based project, that has a "tests" directory containing several tests based on PHPUnit.

$ php -v
PHP 7.3.5 (cli) (built: Apr 30 2019 21:05:09) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.5, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.5, Copyright (c) 1999-2018, by Zend Technologies

$ phpunit --version
PHPUnit 8.0.1 by Sebastian Bergmann and contributors.

$ php -m
[PHP Modules]
Core
ctype
curl
date
dom
ds
fileinfo
filter
ftp
gd
hash
iconv
igbinary
intl
json
libxml
mbstring
mysqlnd
odbc
openssl
pcntl
pcre
PDO
pdo_mysql
pdo_sqlite
Phar
posix
readline
redis
Reflection
session
SimpleXML
soap
SPL
standard
tokenizer
xml
xmlreader
xmlwriter
Zend OPcache
zip
zlib

[Zend Modules]
Zend OPcache

$ phpunit -v
Segmentation fault (core dumped)

$ coredumpctl info 20528
           PID: 20528 (php)
           UID: 1000 (wojtek)
           GID: 985 (users)
        Signal: 11 (SEGV)
     Timestamp: Tue 2019-05-21 08:26:09 CEST (42s ago)
  Command Line: php /usr/local/bin/phpunit -v
    Executable: /usr/bin/php
 Control Group: /user.slice/user-1000.slice/session-2.scope
          Unit: session-2.scope
         Slice: user-1000.slice
       Session: 2
     Owner UID: 1000 (wojtek)
       Boot ID: 526298d71d1a4cb6bf2294d12eea5611
    Machine ID: f372dea6fef44dc1ad344b6b92e63878
      Hostname: archlinux-ws
       Storage: /var/lib/systemd/coredump/core.php.1000.526298d71d1a4cb6bf2294d12eea5611.20528.1558419969000000.lz4
       Message: Process 20528 (php) of user 1000 dumped core.
                
                Stack trace of thread 20528:
                #0  0x000055e6a0409bd0 n/a (php)
                #1  0x000055e6a05857c5 execute_ex (php)
                #2  0x000055e6a058b836 zend_execute (php)
                #3  0x000055e6a050455a zend_execute_scripts (php)
                #4  0x000055e6a04a4489 php_execute_script (php)
                #5  0x000055e6a058de36 n/a (php)
                #6  0x000055e6a028f067 n/a (php)
                #7  0x00007f51c5576ce3 __libc_start_main (libc.so.6)
                #8  0x000055e6a028f74e _start (php)
 [2019-06-03 14:29 UTC] stronk7 at moodle dot com
Just for the records, we are also facing a similar problem with PHP 7.3 and our phpunit tests.The very same stuff passes without problems with 7.1 and 7.2.

Have been able to consistently reproduce the problem both with debian9 (dockerized) and macos x mojave.

...........................................................  7906 / 13354 ( 59%)
...Segmentation fault: 11 (`core' generado)

In our case, it's curious because the problem is only reproducible when we are using the sqlsrv extension (tests are passing perfectly with any other db), but this maybe a factor, not the cause, as far as our backtrace is pretty similar the originally reported here (mac one follows):

(lldb) bt all
* thread #1, stop reason = signal SIGSTOP
  * frame #0: 0x0000000109da5ade php`zend_mm_alloc_small + 206
    frame #1: 0x0000000109da304d php`zend_mm_alloc_heap + 301
    frame #2: 0x0000000109da3fe6 php`_emalloc + 182
    frame #3: 0x0000000109d9481c php`zend_string_alloc + 124
    frame #4: 0x0000000109d7fecf php`zend_string_init + 31
    frame #5: 0x0000000109d82488 php`lex_scan + 3000
    frame #6: 0x0000000109dab4c4 php`zendlex + 68
    frame #7: 0x0000000109d787ee php`zendparse + 878
    frame #8: 0x0000000109d8090c php`zend_compile + 92
    frame #9: 0x0000000109d80882 php`compile_file + 146
    frame #10: 0x0000000109ad1fa4 php`phar_compile_file + 1204
    frame #11: 0x0000000109d80b6a php`compile_filename + 218
    frame #12: 0x0000000109ee7484 php`zend_include_or_eval + 884
    frame #13: 0x0000000109e80a6f php`ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER + 63
    frame #14: 0x0000000109e54434 php`execute_ex + 100
    frame #15: 0x0000000109dc956a php`zend_call_function + 2826
    frame #16: 0x0000000109e435d7 php`zend_std_call_getter + 247
    frame #17: 0x0000000109e42cb6 php`zend_std_read_property + 1350
    frame #18: 0x0000000109e89268 php`ZEND_FETCH_OBJ_R_SPEC_CV_CONST_HANDLER + 1928
    frame #19: 0x0000000109e54434 php`execute_ex + 100
    frame #20: 0x0000000109e5463a php`zend_execute + 234
    frame #21: 0x0000000109de6fa2 php`zend_execute_scripts + 594
    frame #22: 0x0000000109d39103 php`php_execute_script + 1139
    frame #23: 0x0000000109ef5440 php`do_cli + 3440
    frame #24: 0x0000000109ef4401 php`main + 1633
    frame #25: 0x00007fff785543d5 libdyld.dylib`start + 1
    frame #26: 0x00007fff785543d5 libdyld.dylib`start + 1

Also, like the original reporter... the fault only happens when we run all the tests, running only the "breaking" one doesn't break. And taking rid of the "breaking" one makes the whole run to pass.

So, we know it only happens for us with sqlsrv, we know which exact test case causes it (pretty innocent one, I'd say) and it's only reproducible running all tests.

Not sure if all the above helps, but that's what we have been able to find till now, so far.

Ciao :-)
 [2019-07-30 23:27 UTC] andrew at nicols dot co dot uk
We are still seeing this in a repeatable fashion on PHP 7.3.7, only it has now progressed from hitting just SQLServer to MySQLi too.

Have a coredump, and will generate valgrind if it's useful.
As others have said, only happens on a full run.
Moodle (same as stronk7)
 [2019-08-12 23:36 UTC] andrew at nicols dot co dot uk
We're now seeing this on every full phpunit run with MySQL on PHP 7.2 and PHP 7.3 (using latest apache docker images).

What can we do to help this issue get some attention?
 [2019-08-13 08:45 UTC] nikic@php.net
A valgrind trace would be pretty useful. It's pretty likely that this is unrelated to the original issue here (pretty much any form of memory corruption is likely to end up crashing in the allocator...)
 [2019-08-13 09:28 UTC] enumag at gmail dot com
For the original issue, would it help if we provide a repository where the issue can be reproduced every time?
 [2019-08-13 10:00 UTC] nikic@php.net
@enumag: That would be useful, yes.
 [2019-08-16 13:46 UTC] enumag at gmail dot com
@nikic Sent you an email to nikic@php.net with an archive to reproduce the segfault.
 [2019-08-16 21:50 UTC] nikic@php.net
-Status: Open +Status: Analyzed
 [2019-08-16 21:50 UTC] nikic@php.net
@enumag: Thanks for providing the reproducer!

I think that part of your problem is already fixed in the upcoming release, at least most of the valgrind warnings that I could reproduce on earlier versions no longer do on current 7.3 HEAD. Quite likely one of the recent GC fixes applied to your case.

However, there is still a double-free happening during shutdown. I was able to reduce it to the following embarrassingly simple reproducer:

<?php
class A {
    /** Foo */
    private $prop;
}
class B extends A {
}
class C extends B {
}

The issue is that we free the doc comment either if the property was declared on the class, or it is a SHADOW property, because those get copied. However, this does not consider the case where a SHADOW property is inherited, in which case no copy occurs.

This is fixed in 7.4 already because the SHADOW property concept was removed.
 [2019-08-17 08:56 UTC] nikic@php.net
-Summary: Segmentation fault in PHP 7.3.4 when running phpunit +Summary: Double release of doc comment on inherited shadow property
 [2019-08-17 09:00 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=be7e819068985859f92e4af21e49b4f647dd0467
Log: Fixed bug #77922
 [2019-08-17 09:00 UTC] nikic@php.net
-Status: Analyzed +Status: Closed
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Tue Oct 22 14:01:27 2019 UTC