phpv8 / v8js

V8 Javascript Engine for PHP — This PHP extension embeds the Google V8 Javascript Engine
http://pecl.php.net/package/v8js
MIT License
1.83k stars 200 forks source link

V8js is reading invalid memory (and possibly segfaulting) on module shutdown on non-ZTS builds if registerExtension is called #247

Closed TysonAndre closed 8 years ago

TysonAndre commented 8 years ago

PHP version: 7.0.9 (Debug enabled, no zts, opcache enabled for cli)

$ php --version
PHP 7.0.9 (cli) (built: Jul 29 2016 21:51:34) ( NTS DEBUG )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.9, Copyright (c) 1999-2016, by Zend Technologies

(Segfaults on module shutdown, not request shutdown).

I believe that the reason is because on request shutdown, all non-interned strings are freed. After request shutdown, those strings are accessed in module shutdown.

Command to reproduce:

$ make test TESTS='-m tests/extensions_basic.phpt --show-out' 

Valgrind output, in tests/extensions_basic.mem

==15370== Invalid read of size 1
==15370==    at 0xB8698D1: zend_string_release (zend_string.h:269)
==15370==    by 0xB86B045: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:273)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==    by 0x82840C: zend_destroy_modules (zend_API.c:1984)
==15370==    by 0x81EF54: zend_shutdown (zend.c:840)
==15370==  Address 0xb800565 is 5 bytes inside a block of size 32 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
==15370== Invalid read of size 4
==15370==    at 0xB8698E3: zend_string_release (zend_string.h:270)
==15370==    by 0xB86B045: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:273)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==    by 0x82840C: zend_destroy_modules (zend_API.c:1984)
==15370==    by 0x81EF54: zend_shutdown (zend.c:840)
==15370==  Address 0xb800560 is 0 bytes inside a block of size 32 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
==15370== Invalid write of size 4
==15370==    at 0xB8698EC: zend_string_release (zend_string.h:270)
==15370==    by 0xB86B045: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:273)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==    by 0x82840C: zend_destroy_modules (zend_API.c:1984)
==15370==    by 0x81EF54: zend_shutdown (zend.c:840)
==15370==  Address 0xb800560 is 0 bytes inside a block of size 32 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
==15370== Invalid read of size 4
==15370==    at 0xB8698F2: zend_string_release (zend_string.h:270)
==15370==    by 0xB86B045: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:273)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==    by 0x82840C: zend_destroy_modules (zend_API.c:1984)
==15370==    by 0x81EF54: zend_shutdown (zend.c:840)
==15370==  Address 0xb800560 is 0 bytes inside a block of size 32 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
==15370== Invalid read of size 1
==15370==    at 0xB869901: zend_string_release (zend_string.h:271)
==15370==    by 0xB86B045: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:273)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==    by 0x82840C: zend_destroy_modules (zend_API.c:1984)
==15370==    by 0x81EF54: zend_shutdown (zend.c:840)
==15370==  Address 0xb800565 is 5 bytes inside a block of size 32 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
==15370== Invalid free() / delete / delete[] / realloc()
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0xB86993F: zend_string_release (zend_string.h:271)
==15370==    by 0xB86B045: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:273)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==  Address 0xb800560 is 0 bytes inside a block of size 32 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
==15370== Invalid read of size 1
==15370==    at 0xB8698D1: zend_string_release (zend_string.h:269)
==15370==    by 0xB86B055: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:274)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==    by 0x82840C: zend_destroy_modules (zend_API.c:1984)
==15370==    by 0x81EF54: zend_shutdown (zend.c:840)
==15370==  Address 0xb8005c5 is 5 bytes inside a block of size 48 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
==15370== Invalid read of size 4
==15370==    at 0xB8698E3: zend_string_release (zend_string.h:270)
==15370==    by 0xB86B055: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:274)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==    by 0x82840C: zend_destroy_modules (zend_API.c:1984)
==15370==    by 0x81EF54: zend_shutdown (zend.c:840)
==15370==  Address 0xb8005c0 is 0 bytes inside a block of size 48 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
==15370== Invalid write of size 4
==15370==    at 0xB8698EC: zend_string_release (zend_string.h:270)
==15370==    by 0xB86B055: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:274)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==    by 0x82840C: zend_destroy_modules (zend_API.c:1984)
==15370==    by 0x81EF54: zend_shutdown (zend.c:840)
==15370==  Address 0xb8005c0 is 0 bytes inside a block of size 48 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
==15370== Invalid read of size 4
==15370==    at 0xB8698F2: zend_string_release (zend_string.h:270)
==15370==    by 0xB86B055: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:274)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==    by 0x82840C: zend_destroy_modules (zend_API.c:1984)
==15370==    by 0x81EF54: zend_shutdown (zend.c:840)
==15370==  Address 0xb8005c0 is 0 bytes inside a block of size 48 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
==15370== Invalid read of size 1
==15370==    at 0xB869901: zend_string_release (zend_string.h:271)
==15370==    by 0xB86B055: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:274)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==    by 0x82840C: zend_destroy_modules (zend_API.c:1984)
==15370==    by 0x81EF54: zend_shutdown (zend.c:840)
==15370==  Address 0xb8005c5 is 5 bytes inside a block of size 48 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
==15370== Invalid free() / delete / delete[] / realloc()
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0xB86993F: zend_string_release (zend_string.h:271)
==15370==    by 0xB86B055: v8js_jsext_free_storage(v8js_jsext*) (v8js_class.cc:274)
==15370==    by 0xB86B07E: v8js_jsext_dtor(_zval_struct*) (v8js_class.cc:282)
==15370==    by 0x834E91: zend_hash_destroy (zend_hash.c:1265)
==15370==    by 0xB868A60: zm_shutdown_v8js(int, int) (v8js.cc:167)
==15370==    by 0x82A451: module_destructor (zend_API.c:2505)
==15370==    by 0x81E8F6: module_destructor_zval (zend.c:615)
==15370==    by 0x83454D: _zend_hash_del_el_ex (zend_hash.c:1026)
==15370==    by 0x834645: _zend_hash_del_el (zend_hash.c:1050)
==15370==    by 0x835906: zend_hash_graceful_reverse_destroy (zend_hash.c:1502)
==15370==  Address 0xb8005c0 is 0 bytes inside a block of size 48 free'd
==15370==    at 0x4C273F0: free (vg_replace_malloc.c:446)
==15370==    by 0x7ED63F: _efree (zend_alloc.c:2461)
==15370==    by 0x856291: zend_string_free (zend_string.h:263)
==15370==    by 0x856D91: zend_interned_strings_restore_int (zend_string.c:185)
==15370==    by 0x791E8A: php_request_shutdown (main.c:1854)
==15370==    by 0x8E176E: do_cli (php_cli.c:1141)
==15370==    by 0x8E1E57: main (php_cli.c:1344)
==15370== 
TysonAndre commented 8 years ago

Note that builds with ZTS enabled, such as those used by travis CI, are completely unaffected (zend_interned_strings_restore_int does nothing with ZTS enabled)

168 static void zend_interned_strings_restore_int(void)
169 {
170 #ifndef ZTS
171     uint nIndex;
172     uint idx;
173     Bucket *p;