Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
25 changes: 25 additions & 0 deletions Zend/tests/oss_fuzz_456317305.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--TEST--
OSS-Fuzz #456317305: EG(current_execute_data) NULL pointer violation
--FILE--
<?php

class C {
public function __destruct() {
static $again = true;
if ($again) {
$again = false;
$c = new C;
}
throw new Exception;
}
}

$c = new C;

?>
--EXPECTF--
Fatal error: Uncaught Exception in %s:%d
Stack trace:
#0 [internal function]: C->__destruct()
#1 {main}
thrown in %s on line %d
12 changes: 8 additions & 4 deletions Zend/zend_generators.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,9 +312,11 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */
zend_object *old_exception = NULL;
const zend_op *old_opline_before_exception = NULL;
if (EG(exception)) {
EG(current_execute_data)->opline = EG(opline_before_exception);
if (EG(current_execute_data)) {
EG(current_execute_data)->opline = EG(opline_before_exception);
old_opline_before_exception = EG(opline_before_exception);
}
old_exception = EG(exception);
old_opline_before_exception = EG(opline_before_exception);
EG(exception) = NULL;
}

Expand All @@ -327,8 +329,10 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */
zend_generator_resume(generator);

if (old_exception) {
EG(current_execute_data)->opline = EG(exception_op);
EG(opline_before_exception) = old_opline_before_exception;
if (EG(current_execute_data)) {
EG(current_execute_data)->opline = EG(exception_op);
EG(opline_before_exception) = old_opline_before_exception;
}
if (EG(exception)) {
zend_exception_set_previous(EG(exception), old_exception);
} else {
Expand Down
21 changes: 12 additions & 9 deletions Zend/zend_objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
}

zend_object *old_exception;
const zend_op *old_opline_before_exception;
const zend_op *old_opline_before_exception = NULL;

if (destructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
if (EG(current_execute_data)) {
Expand Down Expand Up @@ -156,23 +156,26 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
if (EG(exception) == object) {
zend_error_noreturn(E_CORE_ERROR, "Attempt to destruct pending exception");
} else {
if (EG(current_execute_data)
&& EG(current_execute_data)->func
&& ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) {
zend_rethrow_exception(EG(current_execute_data));
if (EG(current_execute_data)) {
if (EG(current_execute_data)->func
&& ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) {
zend_rethrow_exception(EG(current_execute_data));
}
EG(current_execute_data)->opline = EG(opline_before_exception);
old_opline_before_exception = EG(opline_before_exception);
}
EG(current_execute_data)->opline = EG(opline_before_exception);
old_exception = EG(exception);
old_opline_before_exception = EG(opline_before_exception);
EG(exception) = NULL;
}
}

zend_call_known_instance_method_with_0_params(destructor, object, NULL);

if (old_exception) {
EG(current_execute_data)->opline = EG(exception_op);
EG(opline_before_exception) = old_opline_before_exception;
if (EG(current_execute_data)) {
EG(current_execute_data)->opline = EG(exception_op);
EG(opline_before_exception) = old_opline_before_exception;
}
if (EG(exception)) {
zend_exception_set_previous(EG(exception), old_exception);
} else {
Expand Down
21 changes: 20 additions & 1 deletion ext/opcache/zend_file_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -573,13 +573,32 @@ static void zend_file_cache_serialize_op_array(zend_op_array *op_arra
}
if (opline->op2_type == IS_CONST) {
SERIALIZE_PTR(opline->op2.zv);

/* See GH-17733. Reset Z_EXTRA_P(op2) of ZEND_INIT_FCALL, which
* is an offset into the global function table, to avoid calling
* incorrect functions when environment changes. This, and the
* equivalent code below, can be removed once proper system ID
* validation is implemented. */
if (opline->opcode == ZEND_INIT_FCALL) {
zval *op2 = opline->op2.zv;
UNSERIALIZE_PTR(op2);
Z_EXTRA_P(op2) = 0;
ZEND_VM_SET_OPCODE_HANDLER(opline);
}
}
#else
if (opline->op1_type == IS_CONST) {
opline->op1.constant = RT_CONSTANT(opline, opline->op1) - literals;
}
if (opline->op2_type == IS_CONST) {
opline->op2.constant = RT_CONSTANT(opline, opline->op2) - literals;
zval *op2 = RT_CONSTANT(opline, opline->op2);
opline->op2.constant = op2 - literals;

/* See GH-17733 and comment above. */
if (opline->opcode == ZEND_INIT_FCALL) {
Z_EXTRA_P(op2) = 0;
ZEND_VM_SET_OPCODE_HANDLER(opline);
}
}
#endif
#if ZEND_USE_ABS_JMP_ADDR
Expand Down