Skip to content

Potential crash in enum tryFrom() with observers #10346

@rioderelfte

Description

@rioderelfte

Description

When zend observers are enabled, calling the tryFrom() method of enums might cause a crash. I was not yet able to create a small test case which actually does crash. However address sanitizer reports an issue for this test:

--TEST--
Observer: enum tryFrom()
--EXTENSIONS--
zend_test
--INI--
zend_test.observer.enabled=1
zend_test.observer.observe_all=1
--FILE--
<?php
enum Card : string
{
    case HEART = 'H';
}

var_dump(Card::tryFrom('H'));
?>
--EXPECTF--
<!-- init '%s' -->
<file '%s'>
  <!-- init Card::tryFrom() -->
  <Card::tryFrom>
  </Card::tryFrom>
  <!-- init var_dump() -->
  <var_dump>
enum(Card::HEART)
  </var_dump>
</file '%s'>

On the current PHP 8.2 branch (commit 757e269) I get the following output when running that test with address sanitizer on a Mac:

<!-- init '/Users/florian/projects/php/php-src/ext/zend_test/tests/observer_enum_01.php' -->
<file '/Users/florian/projects/php/php-src/ext/zend_test/tests/observer_enum_01.php'>
AddressSanitizer:DEADLYSIGNAL
=================================================================
==2220==ERROR: AddressSanitizer: BUS on unknown address (pc 0x000108208150 bp 0x00016d1bf6d0 sp 0x00016d1bf570 T0)
==2220==The signal is caused by a UNKNOWN memory access.
==2220==Hint: this fault was caused by a dereference of a high value address (see register values below).  Disassemble the provided pc to learn which register was used.
    #0 0x108208150  (<unknown module>)
    #1 0x103ad09a0 in zend_observer_fcall_begin zend_observer.c:258
    #2 0x103888018 in ZEND_DO_FCALL_SPEC_OBSERVER_HANDLER zend_vm_execute.h:2058
    #3 0x1037acb6c in execute_ex zend_vm_execute.h:55811
    #4 0x1037ad468 in zend_execute zend_vm_execute.h:60384
    #5 0x1036f6f70 in zend_execute_scripts zend.c:1780
    #6 0x1034fb868 in php_execute_script main.c:2540
    #7 0x103cb34c0 in do_cli php_cli.c:964
    #8 0x103cb1260 in main php_cli.c:1333
    #9 0x18e00fe4c  (<unknown module>)

==2220==Register values:
 x[0] = 0x000000010820b110   x[1] = 0x000000010820b110   x[2] = 0x000000010825d3c0   x[3] = 0x0000000000000001  
 x[4] = 0x000000010828e000   x[5] = 0x0000000000000000   x[6] = 0x74735f7465735f5f   x[7] = 0x0000000000000000  
 x[8] = 0x0000000108208150   x[9] = 0x0000000108208120  x[10] = 0x0000000000000001  x[11] = 0x000000010820b110  
x[12] = 0x000000016d1bf748  x[13] = 0x000000016d1bf740  x[14] = 0x000000016d1bda80  x[15] = 0x0000000000000000  
x[16] = 0x000000018e367c00  x[17] = 0x0000000104de85e0  x[18] = 0x0000000000000000  x[19] = 0x000000016d1bf780  
x[20] = 0x0000000103cb095c  x[21] = 0x00000001049a9c50  x[22] = 0x000000016d1c1d70  x[23] = 0x000000018e085000  
x[24] = 0x00000001e9f0c3c0  x[25] = 0x0000000000000000  x[26] = 0x0000000000000000  x[27] = 0x0000000000000000  
x[28] = 0x0000000000000000     fp = 0x000000016d1bf6d0     lr = 0x0000000103ad07f8     sp = 0x000000016d1bf570  
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: BUS (<unknown module>) 
==2220==ABORTING

Termsig=6

The handler pointer of the tryFrom() method seems not to be properly initialized as NULL, so zend_observer_fcall_install is never called for that method:

if (!*handler) {
zend_observer_fcall_install(execute_data);
}

PHP Version

PHP 8.2.1

Operating System

Mac OS 13.0.1

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions