php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #81580 SEGV (probably stack limits) while autoloading from a shutdown function
Submitted: 2021-11-01 06:49 UTC Modified: 2021-11-04 14:48 UTC
From: patrick dot schaaf at yalwa dot com Assigned:
Status: Open Package: Reproducible crash
PHP Version: 8.0.12 OS: openSUSE Tumbleweed
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: patrick dot schaaf at yalwa dot com
New email:
PHP Version: OS:

 

 [2021-11-01 06:49 UTC] patrick dot schaaf at yalwa dot com
Description:
------------
Unfortunately, reproducible, but only in the sense of running production traffic and waiting a few hundred requests for the first coredump... I encounter SEGVs quickly on our production codebase, which has been running stably on the late(st) PHP 5.6 (yeah...), in our attempts at finally making the jump to PHP 8.

System / context is openSUSE tumbleweed, pretty much latest, current apache, mod_php8 at PHP level 8.0.12. opcache disabled (not installed at all) because we saw other issues with opcache that I'll try to reoirt seoarateky.

Code context: We have a little homegrown autoloader in use there, and also pretty much each web request, registers shutdown function; one of them, was consistently implicated in 4 coredumps I got in quick succession (seconds apart) on trying 8.0.12 with our production load. Actual place there in the shutdown function, seen by a bit of gdb backtrace + data inspection, is a call to sprintf() with one of the parameters, being a class_name::method() static call for a class in all these four cases not yet autoloaded - triggering the autoloader for it and then that goes into a three-function stack eating recursive triangle of calls for a few thousand frames while walking the AST.

Emphasis on this is something we do on each request served there, same on a ton of development systems where we never saw the crashes / coredumps, weirdly. Trying to reproduce with same context (shutdown function running while that class was not autoloaded), I could not reproduce it "just so" either, unfortunately.

Test script:
---------------
Don't have a reliable reproding test script, sorry. Here is what the call in the shutdown function actually looks like, abbreviated:

apache_note('phpstat', sprintf("%s-%s:%.0f:%.0f-%.0f:%.0f-%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%.0f:%s:%s:%s:%s:%s",
  self::$page,
...
  # <-- crashes while autoloading / compiling "detect_bot" from here
  detect_bot::get_apache_logtag(),
...
));

Actual result:
--------------
gdb / backtrace info, if anything is missing that you need to know, tell me the frame # and what to look for.

----------------------
Core was generated by `/usr/sbin/httpd-prefork -DSYSCONFIG -DSSL -DSTATUS -C PidFile /run/httpd.pid -C'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  zend_mm_alloc_small (bin_num=24, heap=0x7f31a4e00040) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_alloc.c:1255
1255                    heap->free_slot[bin_num] = p->next_free_slot;
----------------------
(gdb) bt
#0  zend_mm_alloc_small (bin_num=24, heap=0x7f31a4e00040) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_alloc.c:1255
#1  zend_mm_alloc_heap (size=<optimized out>, heap=0x7f31a4e00040) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_alloc.c:1326
#2  _emalloc (size=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_alloc.c:2540
#3  0x00007f31a57dcc32 in zend_string_alloc (persistent=false, len=1003) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_string.h:143
#4  concat_function (result=0x7ffe8caef5c8, op1=<optimized out>, op2=<optimized out>)
    at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_operators.c:1899
#5  0x00007f31a57c9e36 in zend_try_ct_eval_binary_op (op2=0x7ffe8caef4f8, op1=0x7ffe8caef4d8, opcode=8, result=0x7ffe8caef5c8)
    at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:7918
#6  zend_try_ct_eval_binary_op (op2=0x7ffe8caef4f8, op1=0x7ffe8caef4d8, opcode=8, result=0x7ffe8caef5c8)
    at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:7911
#7  zend_compile_binary_op (ast=0x7ffe8caef4f8, result=0x7ffe8caef5c0) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:8094
#8  zend_compile_expr_inner (result=0x7ffe8caef5c0, ast=0x7ffe8caef4f8) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9538
#9  0x00007f31a57ca26c in zend_compile_expr (result=0x7ffe8caef5c0, ast=0x7f31a4f18cc8)
    at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9640
#10 0x00007f31a57c8506 in zend_compile_binary_op (ast=0x7f31a4f18cf8, result=0x7ffe8caef6b0)
    at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:8090
#11 zend_compile_expr_inner (result=0x7ffe8caef6b0, ast=0x7f31a4f18cf8) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9538
#12 0x00007f31a57ca26c in zend_compile_expr (result=0x7ffe8caef6b0, ast=0x7f31a4f18cf8)
    at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9640
#13 0x00007f31a57c8506 in zend_compile_binary_op (ast=0x7f31a4f18d28, result=0x7ffe8caef7a0)
    at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:8090

*** THESE THREE FRAMES, LIKE #11/#12/#13, then repeat over and over for a long stretch ***

#1830 0x00007f31a57ca26c in zend_compile_expr (result=0x7ffe8cb12ed0, ast=0x7f31a4f24ec0) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9640
#1831 0x00007f31a57c8506 in zend_compile_binary_op (ast=0x7f31a4f24ef0, result=0x7ffe8cb12fc0) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:8090
#1832 zend_compile_expr_inner (result=0x7ffe8cb12fc0, ast=0x7f31a4f24ef0) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9538
#1833 0x00007f31a57ba04d in zend_compile_expr (ast=0x7f31a4f24ef0, result=0x7ffe8cb12fc0) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9640
#1834 zend_compile_args (may_have_extra_named_args=<synthetic pointer>, fbc=0x5562fea7d800, ast=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:3481
#1835 zend_compile_call_common (result=<optimized out>, args_ast=<optimized out>, fbc=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:3568
#1836 0x00007f31a57cadb8 in zend_compile_call (ast=0x7f31a4f24f08, ast=0x7f31a4f24f08, type=<optimized out>, result=0x7ffe8cb131d0) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:4355
#1837 zend_compile_var_inner (by_ref=<optimized out>, type=<optimized out>, ast=0x7f31a4f24f08, result=0x7ffe8cb131d0) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9659
#1838 zend_compile_var (result=0x7ffe8cb131d0, ast=0x7f31a4f24f08, type=<optimized out>, by_ref=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9685
#1839 0x00007f31a57bfe77 in zend_compile_expr (ast=0x7f31a4f24f08, result=0x7ffe8cb131d0) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9640
#1840 zend_compile_stmt (ast=0x7f31a4f24f08) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9482
#1841 0x00007f31a57bfb7f in zend_compile_stmt_list (ast=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:5990
#1842 zend_compile_stmt (ast=0x7f31a4f16cb8) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9394
#1843 0x00007f31a57c4a6c in zend_compile_func_decl (result=<optimized out>, ast=<optimized out>, toplevel=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:6988
#1844 0x00007f31a57c015c in zend_compile_stmt (ast=0x7f31a4f24f20) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9447
#1845 0x00007f31a57bfb7f in zend_compile_stmt_list (ast=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:5990
#1846 zend_compile_stmt (ast=0x7f31a4f2fef8) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9394
#1847 0x00007f31a57c587a in zend_compile_class_decl (result=0x0, ast=0x7f31a4f30510, toplevel=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86
64/Zend/zend_compile.c:7398
#1848 0x00007f31a57c652d in zend_compile_top_stmt (ast=0x7f31a4f30510) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9369
#1849 zend_compile_top_stmt (ast=0x7f31a4efe018) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_compile.c:9358
#1850 0x00007f31a579fd16 in zend_compile (type=type@entry=2) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_language_scanner.c:630
#1851 0x00007f31a57a015a in compile_file (file_handle=0x7ffe8cb13d20, type=8) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_language_scanner.c:665
#1852 0x00007f31a279bf2a in phar_compile_file (file_handle=0x7ffe8cb13d20, type=8) at /usr/src/debug/php8-8.0.12-1.1.x86_64/ext/phar/phar.c:3364
#1853 0x00007f31a57a01d3 in compile_filename (type=8, filename=0x7f31a4e11fe0) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_language_scanner.c:721
#1854 0x00007f31a57fe277 in zend_include_or_eval (inc_filename=0x7f31a4e11fe0, type=8) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_execute.c:4274
#1855 0x00007f31a580f914 in ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HANDLER (execute_data=0x7f31a4e11f10) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_vm_execute.h:14266
#1856 0x00007f31a584d1d8 in execute_ex (ex=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_vm_execute.h:53978
#1857 0x00007f31a57d008e in zend_call_function (fci=<optimized out>, fci_cache=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_execute_API.c:895
#1858 0x00007f31a57d044a in zend_call_known_function (fn=0x7f31a4e013d8, object=<optimized out>, called_scope=<optimized out>, retval_ptr=<optimized out>, param_count=<optimized out>, params=0x7ffe8cb140d0, named_params=0x0) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_execute_API.c:985
#1859 0x00007f31a56d5c4f in spl_perform_autoload (class_name=0x7f31a4e8f870, lc_name=0x7f31a4e8f870) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/ext/spl/php_spl.c:440
#1860 0x00007f31a57cf5b0 in zend_lookup_class_ex (name=name@entry=0x7f31a4e8f870, key=0x7f31a4e8f870, flags=flags@entry=512) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_execute_API.c:1110
#1861 0x00007f31a57d49ef in zend_fetch_class_by_name (class_name=0x7f31a4e8f870, key=<optimized out>, fetch_type=512) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_execute_API.c:1521
#1862 0x00007f31a5807d48 in ZEND_INIT_STATIC_METHOD_CALL_SPEC_CONST_CONST_HANDLER (execute_data=0x7f31a4e11020) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_vm_execute.h:6570
#1863 0x00007f31a584d1d8 in execute_ex (ex=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_vm_execute.h:53978
#1864 0x00007f31a57d008e in zend_call_function (fci=<optimized out>, fci_cache=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_execute_API.c:895
#1865 0x00007f31a57ce4ce in _call_user_function_impl (object=<optimized out>, function_name=<optimized out>, retval_ptr=<optimized out>, param_count=<optimized out>, params=<optimized out>, named_params=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_execute_API.c:659
#1866 0x00007f31a570f224 in user_shutdown_function_call (zv=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/ext/standard/basic_functions.c:1693
#1867 0x00007f31a57ec7b2 in zend_hash_apply (ht=0x7f31a4e58700, apply_func=0x7f31a570f1e0 <user_shutdown_function_call>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/Zend/zend_hash.c:1837
#1868 0x00007f31a570f3d6 in php_call_shutdown_functions () at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/ext/standard/basic_functions.c:1766
#1869 0x00007f31a5776755 in php_request_shutdown (dummy=<optimized out>) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/main/main.c:1782
#1870 0x00007f31a587694f in php_apache_request_dtor (r=0x5562fed463c0) at /usr/src/debug/apache2-mod_php8-8.0.12-1.1.x86_64/sapi/apache2handler/sapi_apache2.c:54

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-11-04 14:22 UTC] nikic@php.net
Not sure this is a stack overflow, the crash location is pretty typical for memory corruption. Deeply nested zend_compile_binary_op() can occur for code containing a very large "a" . "b" . "c" style expression with many operands. Is something like that present in the detect_bot file?
 [2021-11-04 14:32 UTC] nikic@php.net
If this is due to memory corruption, then running apache under valgrind (using USE_ZEND_ALLOC=0 valgrind httpd -X I believe) may show where it originates (possibly also reliably without requiring multiple requests).
 [2021-11-04 14:46 UTC] patrick dot schaaf at yalwa dot com
Thanks for your reply, Niki.

This can't be something generally bad about our detect_bot class source / file, as we are really using that sprintf+detect_bot sequence for almost all web requests of our production codebase, and that has been active with php 8 (8.0.9, mostly, but now also 8.0.12) on several dozen web developer VMs, as well as a few internal web tools servers used every day by employees.

That specific coredump with that backtrace, only triggered on our public facing imageserver, and there, quite quickly and repeatedly. So I fear this will be some corruption elsewhere cross-interfering.

Regardless, given your hint that a long sequence of concatenations can lead to that backtrace, I can confirm that we indeed DO have something like that in the file, during define() of a few constants (building up large many-alternative regexpen). Quite needlessly so, just for readability, maybe I should reconsider that... The larger of these, actually concatenates 728 times, which times three, almost gives the depth of that backtrace.

So call me silly for that. Nevertheless, would you have any idea on how to debug this further regarding the actual SEGV seen there, or a suspicion I could followup on to try to make it reproducible?
 [2021-11-04 14:48 UTC] patrick dot schaaf at yalwa dot com
I will try that valgrind approach on my dev server, thanks for the hint.
 
PHP Copyright © 2001-2022 The PHP Group
All rights reserved.
Last updated: Fri Dec 02 00:05:55 2022 UTC