Skip to content

JIT SEGV on OOM in dtor when creating backtrace #17727

Closed

Description

@YuanchengJiang

Description

The following code:

<?php
class DestructableObject
{
public function __destruct()
{
DestructableObject::__destruct();
}
}
class DestructorCreator
{
public function __destruct()
{
$this->test = new DestructableObject;
}
}
class Test
{
public static $mystatic;
}
Test::$mystatic = new DestructorCreator();
class B implements Serializable
{
public function serialize()
{
}
public function unserialize($data)
{
}
}

Resulted in this output:

/home/phpfuzz/WorkSpace/flowfusion/php-src/Zend/zend_builtin_functions.c:1910:9: runtime error: member access within null pointer of type 'const zend_op' (aka 'const struct _zend_op')
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /home/phpfuzz/WorkSpace/flowfusion/php-src/Zend/zend_builtin_functions.c:1910:9

To reproduce:

-d "zend_extension=/home/phpfuzz/WorkSpace/flowfusion/php-src/modules/opcache.so" -d "opcache.enable_cli=1" -d "opcache.jit=1254"

PHP Version

nightly

Operating System

No response

Activity

  1. arnaud-lb commented on Feb 7, 2025

    @arnaud-lb
    Member

    Smaller reproducer:

    class DestructableObject
    {
        public function __destruct()
        {
            DestructableObject::__destruct();
        }
    }
    $_ = new DestructableObject();

    Backtrace:

    0x000000000099c9ed in zend_fetch_debug_backtrace (return_value=0x121baf0 <executor_globals+432>, skip_last=0, options=0, limit=0) at Zend/zend_builtin_functions.c:1910
    1910				if (!ZEND_OP_IS_FRAMELESS_ICALL(opline->opcode)) {
    (gdb) bt
    #0  0x000000000099c9ed in zend_fetch_debug_backtrace (return_value=0x121baf0 <executor_globals+432>, skip_last=0, options=0, limit=0) at Zend/zend_builtin_functions.c:1910
    #1  0x0000000000af571d in zend_error_zstr_at (orig_type=1, error_filename=0x1ed8b38, error_lineno=6, message=0x7ffff7a762a0) at Zend/zend.c:1495
    #2  0x0000000000af5d6c in zend_error_va_list (orig_type=1, error_filename=0x1ed8b38, error_lineno=6, format=0xd8bc68 "Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)", args=0x7fffffffb038) at Zend/zend.c:1606
    #3  0x0000000000af6376 in zend_error_noreturn (type=1, format=0xd8bc68 "Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)") at Zend/zend.c:1714
    #4  0x000000000096cf7d in zend_mm_safe_error (heap=0x7ffff7a00040, format=0xd8bc68 "Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)", limit=2147483648, filename=0xd9ed30 "Zend/zend_execute.h", lineno=263, size=262176)
        at Zend/zend_alloc.c:413
    #5  0x000000000096de7d in zend_mm_alloc_pages (heap=0x7ffff7a00040, pages_count=65, size=262176, __zend_filename=0xd9ed30 "Zend/zend_execute.h", __zend_lineno=263, __zend_orig_filename=0x0, __zend_orig_lineno=0) at Zend/zend_alloc.c:1049
    #6  0x000000000096e16d in zend_mm_alloc_large_ex (heap=0x7ffff7a00040, size=262176, __zend_filename=0xd9ed30 "Zend/zend_execute.h", __zend_lineno=263, __zend_orig_filename=0x0, __zend_orig_lineno=0) at Zend/zend_alloc.c:1127
    #7  0x000000000096e205 in zend_mm_alloc_large (heap=0x7ffff7a00040, size=262176, __zend_filename=0xd9ed30 "Zend/zend_execute.h", __zend_lineno=263, __zend_orig_filename=0x0, __zend_orig_lineno=0) at Zend/zend_alloc.c:1144
    #8  0x000000000096ed74 in zend_mm_alloc_heap (heap=0x7ffff7a00040, size=262176, __zend_filename=0xd9ed30 "Zend/zend_execute.h", __zend_lineno=263, __zend_orig_filename=0x0, __zend_orig_lineno=0) at Zend/zend_alloc.c:1499
    #9  0x00000000009719e2 in _emalloc (size=262144, __zend_filename=0xd9ed30 "Zend/zend_execute.h", __zend_lineno=263, __zend_orig_filename=0x0, __zend_orig_lineno=0) at Zend/zend_alloc.c:2740
    #10 0x00000000009d55cb in zend_vm_stack_new_page (size=262144, prev=0x7fff69587000) at Zend/zend_execute.h:263
    #11 0x00000000009d61f4 in zend_vm_stack_extend (size=80) at Zend/zend_execute.c:227
    #12 0x00007fffe9b1dd57 in zend_vm_stack_push_call_frame_ex (used_stack=80, call_info=776, func=0x1ed8988, num_args=0, object_or_called_scope=0x7ffff7a6e730) at Zend/zend_execute.h:287
    #13 0x00007fffe9b1dee8 in zend_vm_stack_push_call_frame (call_info=776, func=0x1ed8988, num_args=0, object_or_called_scope=0x7ffff7a6e730) at Zend/zend_execute.h:312
    #14 0x00007fffe9b21f50 in zend_jit_push_this_method_call_frame (scope=0x7ffff7a6e730, fbc=0x1ed8988, num_args=0) at ext/opcache/jit/zend_jit_helpers.c:275
    #15 0x0000000009600a29 in TRACE-2$DestructableObject::__destruct$6 () at unknown:1
    #16 0x00000000009d17cf in zend_call_function (fci=0x7ffff7a04000, fci_cache=0xdda088) at Zend/zend_execute_API.c:1008
    

    We OOM in zend_vm_stack_push_call_frame(), but EG(current_execute_data)->opline is 0, so we crash when fetching the backtrace.

  2. ndossche commented on Feb 7, 2025

    @ndossche
    Member

    @arnaud-lb I don't know if you have a patch for this in the queue or looked into this, but it's just that the opline should be set prior to calling the helper. This became visible after the fatal error backtrace RFC, but technically also exists on lower branches.
    Patch would be trivial:

    diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c
    index aee2afa7a51..ddb859895bd 100644
    --- a/ext/opcache/jit/zend_jit_ir.c
    +++ b/ext/opcache/jit/zend_jit_ir.c
    @@ -9327,6 +9327,7 @@ static int zend_jit_init_static_method_call(zend_jit_ctx         *jit,
     			ir_IF_FALSE_cold(if_static);
     		}
     
    +		jit_SET_EX_OPLINE(jit, opline);
     		ref = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_this_method_call_frame),
     				scope_ref,
     				func_ref,
    
  3. arnaud-lb commented on Feb 7, 2025

    @arnaud-lb
    Member

    @nielsdos this looks right, and it mirrors the SAVE_OPLINE() in ZEND_INIT_STATIC_METHOD_CALL() as well as jit_SET_EX_OPLINE(jit, opline) calls in zend_jit_push_call_frame(). I looked into it briefly and didn't have a patch for this yet, so feel free to submit one :)

  4. changed the title [-]SEGV zend_builtin_functions.c[/-] [+]JIT SEGV on OOM in dtor when creating backtrace[/+] on Feb 7, 2025
  5. added a commit that references this issue on Feb 7, 2025
    ba5d53d
  6. ndossche commented on Feb 7, 2025

    @ndossche
    Member

    Yeah I took your test, added you to the credit section, and I can credit you in NEWS after a merge.

  7. arnaud-lb commented on Feb 10, 2025

    @arnaud-lb
    Member

    Yeah I took your test, added you to the credit section, and I can credit you in NEWS after a merge.

    Thank you, but it's not necessary :)

  8. added a commit that references this issue on Feb 17, 2025
    a54ed9e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions