php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #76337 segfault when opcache enabled + extension use zend_register_class_alias
Submitted: 2018-05-13 23:45 UTC Modified: 2018-05-16 16:36 UTC
From: xKhorasan+php at gmail dot com Assigned:
Status: Closed Package: Reproducible crash
PHP Version: 7.2.5 OS: Linux (CentOS6)
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: xKhorasan+php at gmail dot com
New email:
PHP Version: OS:

 

 [2018-05-13 23:45 UTC] xKhorasan+php at gmail dot com
Description:
------------
configure option: --with-config-file-path=/etc/ --with-config-file-scan-dir=/etc/php.d/
change to php.ini: added lines below
> zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20170718/opcache.so
> opcache.enable_cli=1
> extension=couchbase.so

steps to reproduce:
1. download this file: https://gist.github.com/xKerman/a987581d3d137644460dd15c1d25c612
2: run command: docker build -t php/bug-report .
3: run command in docker container:
```
$ docker run --rm -it php/bug-report bash
[root@236b3ee9e1ec /]# php -v
```

gdb backtrace:
```
[root@236b3ee9e1ec /]# ulimit -c unlimited
[root@236b3ee9e1ec /]# php -v
[cb,WARN] (pcbc/ext L:426) igbinary serializer is not found
PHP 7.2.5 (cli) (built: May 11 2018 21:40:50) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.5, Copyright (c) 1999-2018, by Zend Technologies
Segmentation fault (core dumped)

[root@236b3ee9e1ec /]# gdb php -c core
(gdb) bt
#0  zend_string_release (ht=0x2fbbb50) at /php-7.2.5/Zend/zend_string.h:289
#1  zend_hash_destroy (ht=0x2fbbb50) at /php-7.2.5/Zend/zend_hash.c:1247
#2  0x0000000000726f91 in zend_shutdown () at /php-7.2.5/Zend/zend.c:911
#3  0x00000000006c581a in php_module_shutdown () at /php-7.2.5/main/main.c:2453
#4  0x00000000007d7225 in main (argc=2, argv=0x2fbb7a0)
    at /php-7.2.5/sapi/cli/php_cli.c:1419

(gdb) frame 2
#2  0x0000000000726f91 in zend_shutdown () at /php-7.2.5/Zend/zend.c:911
911             zend_hash_destroy(GLOBAL_CLASS_TABLE);
```


Some extesion, e.g. couchbase, calls `zend_register_class_alias()`.
https://github.com/couchbase/php-couchbase/blob/48d7f6626461c0941c4637dd93810f7556b9a387/src/couchbase/search/facet.c#L29

`zend_register_class_alias()` add alias name to `CG(class_table)`, bug does not intern the class alias name string.
https://github.com/php/php-src/blob/php-7.2.5/Zend/zend_API.c#L2774-L2795

Compared to `zend_regiser_class_alias()`, other `CG(class_table)` update operations, like `zend_register_internal_class()`, does intern string class name.
https://github.com/php/php-src/blob/php-7.2.5/Zend/zend_API.c#L2720

So, `CG(class_table)` contains interned class name string and not interned clas name string, if extension use `zend_resiger_class_alias()`.
And it seems that this causes segmentation fault on `zend_shutdown()`.

Expected result:
----------------
`php -v` return exit code 0

Actual result:
--------------
segmentation fault occur:

```
[root@236b3ee9e1ec /]# php -v
[cb,WARN] (pcbc/ext L:426) igbinary serializer is not found
PHP 7.2.5 (cli) (built: May 11 2018 21:40:50) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.5, Copyright (c) 1999-2018, by Zend Technologies
Segmentation fault
```

Patches

bug76337.patch (last revision 2018-05-13 23:47 UTC by xKhorasan+php at gmail dot com)

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-05-14 21:52 UTC] xKhorasan+php at gmail dot com
Note that this does not occur in PHP 7.1 (confirmed with 7.1.17)
 [2018-05-15 22:02 UTC] xKhorasan+php at gmail dot com
-Package: opcache +Package: Reproducible crash
 [2018-05-15 22:02 UTC] xKhorasan+php at gmail dot com
Confirmed that this still occur in PHP 7.2.6 rc1 ( https://downloads.php.net/~pollita/ ).
 [2018-05-15 22:17 UTC] xKhorasan+php at gmail dot com
created pull request in https://github.com/php/php-src/pull/3241
(cannot add the pull request with "Add a Pull Request")
 [2018-05-16 16:36 UTC] xKhorasan+php at gmail dot com
Detail explanation:

When PHP start running, `accel_use_shm_interned_strings()` is called and interned strings are copied to opcache shared memory space.
https://github.com/php/php-src/blob/php-7.2.6RC1/ext/opcache/ZendAccelerator.c#L642
In this operation, the entry key in `CG(class_table)` are copied to the opcache shared memory space.
Each address of class name string changes to point to shared memory space.
```
(gdb) source .gdbinit
(gdb) b accel_use_shm_interned_strings
(gdb) run -v
Starting program: /usr/local/bin/php -v
[Thread debugging using libthread_db enabled]

Breakpoint 1, accel_use_shm_interned_strings ()
    at /php-7.2.6RC1/ext/opcache/ZendAccelerator.c:643
643     {

(gdb) print_zstr compiler_globals->class_table->arData[155]->key
string(14) "_zendtestclass"
(gdb) p compiler_globals->class_table->arData[155]->key
$1 = (zend_string *) 0x1219f80

(gdb) print_zstr compiler_globals->class_table->arData[157]->key
string(19) "_zendtestclassalias"
(gdb) p compiler_globals->class_table->arData[157]->key
$2 = (zend_string *) 0x121a710

(gdb) fin
(gdb) p compiler_globals->class_table->arData[155]->key
$3 = (zend_string *) 0x7fffee783ac0
(gdb) p compiler_globals->class_table->arData[157]->key
$4 = (zend_string *) 0x7fffee783bd8
```


on PHP shutdown, `accel_shutdown()` is called, and in the function, `accel_use_permanent_interned_strings()` is called.
https://github.com/php/php-src/blob/php-7.2.6RC1/ext/opcache/ZendAccelerator.c#L2796
In this operation, interned strings are replaced using `accel_replace_string_by_process_permanent()`.
https://github.com/php/php-src/blob/php-7.2.6RC1/ext/opcache/ZendAccelerator.c#L629
So each entry key in `CG(class_table)` is replaced by original interned string.
However, since the class name created by `zend_regiser_class_alias()` is not an interned string,
(see: https://github.com/php/php-src/blob/php-7.2.6RC1/Zend/zend_API.c#L2774-L2795 )
its address still points to the shared memory, not an original interned string.
```
(gdb) b accel_shutdown
(gdb) c
(gdb) b accel_reset_pcre_cache
(gdb) c
(gdb) p compiler_globals->class_table->arData[155]->key
$20 = (zend_string *) 0x1219f80
(gdb) p compiler_globals->class_table->arData[157]->key
$21 = (zend_string *) 0x7fffee783bd8
```


After `accel_use_permanent_interned_strings()`, `zend_shared_alloc_shutdown()` is called, and the shared memory space is removed.
So the class alias name in `CG(class_table)`, still points to the shared memory, becomes a dangling pointer.
```
(gdb) b zend_shared_alloc_shutdown
(gdb) print_zstr compiler_globals->class_table->arData[157]->key
string(19) "_zendtestclassalias"

(gdb) n
(gdb) fin
(gdb) print_zstr compiler_globals->class_table->arData[157]->key
Cannot access memory at address 0x7fffee783be8
```


After that, `zend_hash_destroy(GLOBAL_CLASS_TABLE)` is called in `zend_shutdown()`,
But as noted adove, `CG(class_table)` contains dangling pointer, so this operation cause segmentation fault.
```
(gdb) c
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
zend_hash_destroy (ht=0x10ffbb0) at /php-7.2.6RC1/Zend/zend_hash.c:1247
1247                                                    zend_string_release(p->key);

(gdb) bt
#0  zend_hash_destroy (ht=0x10ffbb0) at /php-7.2.6RC1/Zend/zend_hash.c:1247
#1  0x00000000007279f1 in zend_shutdown () at /php-7.2.6RC1/Zend/zend.c:911
#2  0x00000000006c626a in php_module_shutdown () at /php-7.2.6RC1/main/main.c:2453
#3  0x00000000007d7cb5 in main (argc=2, argv=0x10ff800)
    at /php-7.2.6RC1/sapi/cli/php_cli.c:1419

(gdb) frame 1
#1  0x00000000007279f1 in zend_shutdown () at /php-7.2.6RC1/Zend/zend.c:911
911             zend_hash_destroy(GLOBAL_CLASS_TABLE);
```
 [2018-05-20 11:34 UTC] ab@php.net
Automatic comment on behalf of xKhorasan@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=5681f6523bb36d6b49ab802ddba75e53d8d45268
Log: Fixed bug #76337
 [2018-05-20 11:34 UTC] ab@php.net
-Status: Open +Status: Closed
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Oct 27 16:01:27 2024 UTC