Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -8788,6 +8788,8 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF)

variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);

SAVE_OPLINE();

ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr);
if (!ht) {
ht = zend_array_dup(EX(func)->op_array.static_variables);
Expand All @@ -8797,7 +8799,6 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF)

value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));

SAVE_OPLINE();
if (opline->extended_value & ZEND_BIND_REF) {
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) {
Expand Down
3 changes: 2 additions & 1 deletion Zend/zend_vm_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -48471,6 +48471,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_UNUSED_HAN

variable_ptr = EX_VAR(opline->op1.var);

SAVE_OPLINE();

ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr);
if (!ht) {
ht = zend_array_dup(EX(func)->op_array.static_variables);
Expand All @@ -48480,7 +48482,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_UNUSED_HAN

value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));

SAVE_OPLINE();
if (opline->extended_value & ZEND_BIND_REF) {
if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) {
Expand Down
62 changes: 62 additions & 0 deletions ext/zend_test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "zend_interfaces.h"
#include "zend_weakrefs.h"
#include "Zend/Optimizer/zend_optimizer.h"
#include "Zend/zend_alloc.h"
#include "test_arginfo.h"

#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
Expand Down Expand Up @@ -364,6 +365,67 @@ static ZEND_FUNCTION(zend_test_crash)
php_printf("%s", invalid);
}

zend_mm_heap* zend_test_heap;
zend_mm_heap* zend_orig_heap;
volatile uint32_t lineno = 0;

static bool has_opline(zend_execute_data *execute_data)
{
return execute_data
&& execute_data->func
&& ZEND_USER_CODE(execute_data->func->type)
&& execute_data->opline
;
}

#pragma GCC push_options
#pragma GCC optimize("O0")
void * __attribute__((optnone)) zend_test_custom_malloc(size_t len)
{
if (has_opline(EG(current_execute_data))) {
lineno = EG(current_execute_data)->opline->lineno;
}
return _zend_mm_alloc(zend_orig_heap, len);
}

void __attribute__((optnone)) zend_test_custom_free(void *ptr)
{
if (has_opline(EG(current_execute_data))) {
lineno = EG(current_execute_data)->opline->lineno;
}
_zend_mm_free(zend_orig_heap, ptr);
}

void * __attribute__((optnone)) zend_test_custom_realloc(void * ptr, size_t len)
{
if (has_opline(EG(current_execute_data))) {
lineno = EG(current_execute_data)->opline->lineno;
}
return _zend_mm_realloc(zend_orig_heap, ptr, len);
}
#pragma GCC pop_options

static ZEND_FUNCTION(zend_test_observe_opline_in_zendmm)
{
zend_test_heap = malloc(4096);
memset(zend_test_heap, 0, 4096);
zend_mm_set_custom_handlers(
zend_test_heap,
zend_test_custom_malloc,
zend_test_custom_free,
zend_test_custom_realloc
);
zend_orig_heap = zend_mm_get_heap();
zend_mm_set_heap(zend_test_heap);
}

static ZEND_FUNCTION(zend_test_unobserve_opline_in_zendmm)
{
free(zend_test_heap);
zend_test_heap = NULL;
zend_mm_set_heap(zend_orig_heap);
}

static ZEND_FUNCTION(zend_test_is_pcre_bundled)
{
ZEND_PARSE_PARAMETERS_NONE();
Expand Down
4 changes: 4 additions & 0 deletions ext/zend_test/test.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ function zend_get_map_ptr_last(): int {}

function zend_test_crash(?string $message = null): void {}

function zend_test_observe_opline_in_zendmm(): void {}

function zend_test_unobserve_opline_in_zendmm(): void {}

#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
function zend_test_override_libxml_global_state(): void {}
#endif
Expand Down
10 changes: 9 additions & 1 deletion ext/zend_test/test_arginfo.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: ae75eda2b4b40224858d680c3fcf3d7cd2056bb6 */
* Stub hash: a57c9d1fc85dbea853f4cc910b9495a7a0c72eb3 */

ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
Expand Down Expand Up @@ -86,6 +86,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_crash, 0, 0, IS_VOID,
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()

#define arginfo_zend_test_observe_opline_in_zendmm arginfo_zend_test_void_return

#define arginfo_zend_test_unobserve_opline_in_zendmm arginfo_zend_test_void_return

#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_override_libxml_global_state, 0, 0, IS_VOID, 0)
ZEND_END_ARG_INFO()
Expand Down Expand Up @@ -155,6 +159,8 @@ static ZEND_FUNCTION(zend_get_current_func_name);
static ZEND_FUNCTION(zend_call_method);
static ZEND_FUNCTION(zend_get_map_ptr_last);
static ZEND_FUNCTION(zend_test_crash);
static ZEND_FUNCTION(zend_test_observe_opline_in_zendmm);
static ZEND_FUNCTION(zend_test_unobserve_opline_in_zendmm);
#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
static ZEND_FUNCTION(zend_test_override_libxml_global_state);
#endif
Expand Down Expand Up @@ -199,6 +205,8 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(zend_call_method, arginfo_zend_call_method)
ZEND_FE(zend_get_map_ptr_last, arginfo_zend_get_map_ptr_last)
ZEND_FE(zend_test_crash, arginfo_zend_test_crash)
ZEND_FE(zend_test_observe_opline_in_zendmm, arginfo_zend_test_observe_opline_in_zendmm)
ZEND_FE(zend_test_unobserve_opline_in_zendmm, arginfo_zend_test_unobserve_opline_in_zendmm)
#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
ZEND_FE(zend_test_override_libxml_global_state, arginfo_zend_test_override_libxml_global_state)
#endif
Expand Down
35 changes: 35 additions & 0 deletions ext/zend_test/tests/opline_dangling.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
--TEST--
possible segfault in `ZEND_BIND_STATIC`
--DESCRIPTION--
https://github.com/php/php-src/pull/12758
--EXTENSIONS--
zend_test
--FILE--
<?php

function &ref() {
static $a = 5;
return $a;
}

class Foo {
public static int $i;
public static string $s = "x";
}

zend_test_observe_opline_in_zendmm();

var_dump(Foo::$i = "1");
var_dump(Foo::$s, Foo::$i);
var_dump(ref());

zend_test_unobserve_opline_in_zendmm();

echo 'Done.';
?>
--EXPECT--
int(1)
string(1) "x"
int(1)
int(5)
Done.