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
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ PHP NEWS
. It is now possible to use reference assign on WeakMap without the key
needing to be present beforehand. (ndossche)
. Added `clamp()`. (kylekatarnls, thinkverse)
. Fix OSS-Fuzz #429429090 (Failed assertion on unset() with uninitialized
container). (ilutov)
. Fixed GH-20564 (Don't call autoloaders with pending exception). (ilutov)

- Date:
. Update timelib to 2022.16. (Derick)
Expand Down
2 changes: 2 additions & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ PHP 8.6 INTERNALS UPGRADE NOTES
ZEND_ACC_USER_ARG_INFO flag was set.
. Added zend_ast_call_get_args() to fetch the argument node from any call
node.
. The zend_exception_save() and zend_exception_restore() functions were
removed.

========================
2. Build system changes
Expand Down
2 changes: 1 addition & 1 deletion Zend/Optimizer/zend_inference.c
Original file line number Diff line number Diff line change
Expand Up @@ -3840,7 +3840,7 @@ static zend_always_inline zend_result _zend_update_type_info(
tmp &= ~MAY_BE_RC1;
}
if (opline->opcode == ZEND_FETCH_STATIC_PROP_IS) {
tmp |= MAY_BE_UNDEF;
tmp |= MAY_BE_NULL;
}
}
UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
Expand Down
24 changes: 24 additions & 0 deletions Zend/tests/gh20564.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
GH-20564: Don't call autoloaders with pending exception
--CREDITS--
Viet Hoang Luu (@vi3tL0u1s)
--FILE--
<?php

class A {
function __call($method, $args) {
eval("<<<ENDOFSTRING\n Test\n ENDOFSTRING;");
spl_autoload_register('A::test');
array_map('B::test', []);
}
}

try {
(new A)->test();
} catch (Throwable $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECT--
array_map(): Argument #1 ($callback) must be a valid callback or null, class "B" not found
22 changes: 22 additions & 0 deletions Zend/tests/oss-fuzz-471486164-001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
OSS-Fuzz #471486164: get_property_ptr_ptr() on uninitialized hooked property
--FILE--
<?php

class C {
public $a {
get => $this->a;
set { $this->a = &$value; }
}
public $x = 1;
}

$proxy = (new ReflectionClass(C::class))->newLazyProxy(function ($proxy) {
$proxy->a = 1;
return new C;
});
var_dump($proxy->x);

?>
--EXPECT--
int(1)
26 changes: 26 additions & 0 deletions Zend/tests/oss-fuzz-471486164-002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
OSS-Fuzz #471486164: get_property_ptr_ptr() on uninitialized hooked property
--FILE--
<?php

class C {
public int $a {
get => $this->a;
set {
global $ref;
$this->a = &$ref;
}
}
}

$ref = 1;
$proxy = new C;
$proxy->a = 1;
var_dump($proxy->a);
$ref++;
var_dump($proxy->a);

?>
--EXPECT--
int(1)
int(2)
20 changes: 20 additions & 0 deletions Zend/tests/oss_fuzz_429429090.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
OSS-Fuzz #429429090: FETCH_OBJ_UNSET IS_UNDEF result
--FILE--
<?php

class C {
public D $x;
static D $y;
}

$c = new C();
isset($c->x[0]->prop);
unset($c->x[0]->prop);
isset(C::$y[0]->prop);
unset(C::$y[0]->prop);

?>
===DONE===
--EXPECT--
===DONE===
27 changes: 27 additions & 0 deletions Zend/tests/oss_fuzz_438780145.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
OSS-Fuzz #438780145: Nested finally with repeated return type check may uaf
--FILE--
<?php

function &test(): int {
$x = 0;
try {
return $x;
} finally {
try {
return $x;
} finally {
$x = "";
}
}
}

test();

?>
--EXPECTF--
Fatal error: Uncaught TypeError: test(): Return value must be of type int, string returned in %s:%d
Stack trace:
#0 %s(%d): test()
#1 {main}
thrown in %s on line %d
2 changes: 0 additions & 2 deletions Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -1082,7 +1082,6 @@ void zend_startup(zend_utility_functions *utility_functions) /* {{{ */
#endif

zend_enum_startup();
zend_closure_startup();
}
/* }}} */

Expand Down Expand Up @@ -1979,7 +1978,6 @@ ZEND_API zend_result zend_execute_script(int type, zval *retval, zend_file_handl
zend_result ret = SUCCESS;
if (op_array) {
zend_execute(op_array, retval);
zend_exception_restore();
if (UNEXPECTED(EG(exception))) {
if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
zend_user_exception_handler();
Expand Down
14 changes: 1 addition & 13 deletions Zend/zend_closures.c
Original file line number Diff line number Diff line change
Expand Up @@ -878,8 +878,6 @@ ZEND_API void zend_create_fake_closure(zval *res, zend_function *func, zend_clas
}
/* }}} */

static zend_arg_info trampoline_arg_info[1];

void zend_closure_from_frame(zval *return_value, const zend_execute_data *call) { /* {{{ */
zval instance;
zend_internal_function trampoline;
Expand All @@ -904,9 +902,7 @@ void zend_closure_from_frame(zval *return_value, const zend_execute_data *call)
trampoline.function_name = mptr->common.function_name;
trampoline.scope = mptr->common.scope;
trampoline.doc_comment = NULL;
if (trampoline.fn_flags & ZEND_ACC_VARIADIC) {
trampoline.arg_info = trampoline_arg_info;
}
trampoline.arg_info = mptr->common.arg_info;
trampoline.attributes = mptr->common.attributes;

zend_free_trampoline(mptr);
Expand Down Expand Up @@ -943,11 +939,3 @@ void zend_closure_bind_var_ex(zval *closure_zv, uint32_t offset, zval *val) /* {
ZVAL_COPY_VALUE(var, val);
}
/* }}} */

void zend_closure_startup(void)
{
/* __call and __callStatic name the arguments "$arguments" in the docs. */
trampoline_arg_info[0].name = zend_string_init_interned("arguments", strlen("arguments"), true);
trampoline_arg_info[0].type = (zend_type)ZEND_TYPE_INIT_CODE(IS_MIXED, false, _ZEND_ARG_INFO_FLAGS(false, 1, 0));
trampoline_arg_info[0].default_value = NULL;
}
1 change: 0 additions & 1 deletion Zend/zend_closures.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ BEGIN_EXTERN_C()
#define ZEND_CLOSURE_OBJECT(op_array) \
((zend_object*)((char*)(op_array) - sizeof(zend_object)))

void zend_closure_startup(void);
void zend_register_closure_ce(void);
void zend_closure_bind_var(zval *closure_zv, zend_string *var_name, zval *var);
void zend_closure_bind_var_ex(zval *closure_zv, uint32_t offset, zval *val);
Expand Down
29 changes: 0 additions & 29 deletions Zend/zend_exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,31 +145,6 @@ void zend_exception_set_previous(zend_object *exception, zend_object *add_previo
}
/* }}} */

void zend_exception_save(void) /* {{{ */
{
if (EG(prev_exception)) {
zend_exception_set_previous(EG(exception), EG(prev_exception));
}
if (EG(exception)) {
EG(prev_exception) = EG(exception);
}
EG(exception) = NULL;
}
/* }}} */

void zend_exception_restore(void) /* {{{ */
{
if (EG(prev_exception)) {
if (EG(exception)) {
zend_exception_set_previous(EG(exception), EG(prev_exception));
} else {
EG(exception) = EG(prev_exception);
}
EG(prev_exception) = NULL;
}
}
/* }}} */

static zend_always_inline bool is_handle_exception_set(void) {
zend_execute_data *execute_data = EG(current_execute_data);
return !execute_data
Expand Down Expand Up @@ -241,10 +216,6 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /*
ZEND_API void zend_clear_exception(void) /* {{{ */
{
zend_object *exception;
if (EG(prev_exception)) {
OBJ_RELEASE(EG(prev_exception));
EG(prev_exception) = NULL;
}
if (!EG(exception)) {
return;
}
Expand Down
2 changes: 0 additions & 2 deletions Zend/zend_exceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ extern ZEND_API zend_class_entry *zend_ce_unhandled_match_error;
extern ZEND_API zend_class_entry *zend_ce_request_parse_body_exception;

ZEND_API void zend_exception_set_previous(zend_object *exception, zend_object *add_previous);
ZEND_API void zend_exception_save(void);
ZEND_API void zend_exception_restore(void);

ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception);

Expand Down
9 changes: 9 additions & 0 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,7 @@ ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_exe

if ((fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) &&
!zend_verify_internal_arg_types(fbc, call)) {
zend_clear_exception();
return 1;
}

Expand Down Expand Up @@ -3626,6 +3627,9 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
} else if (UNEXPECTED(Z_ISERROR_P(ptr))) {
ZVAL_ERROR(result);
goto end;
} else if (type == BP_VAR_UNSET && UNEXPECTED(Z_TYPE_P(ptr) == IS_UNDEF)) {
ZVAL_NULL(result);
goto end;
}

ZVAL_INDIRECT(result, ptr);
Expand Down Expand Up @@ -3777,6 +3781,11 @@ static zend_never_inline zval* zend_fetch_static_property_address_ex(zend_proper
return NULL;
}

if (UNEXPECTED(Z_TYPE_P(result) == IS_UNDEF)
&& (fetch_type == BP_VAR_IS || fetch_type == BP_VAR_UNSET)) {
return NULL;
}

*prop_info = property_info;

if (EXPECTED(op1_type == IS_CONST)
Expand Down
3 changes: 0 additions & 3 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ void init_executor(void) /* {{{ */
ZEND_ATOMIC_BOOL_INIT(&EG(timed_out), false);

EG(exception) = NULL;
EG(prev_exception) = NULL;

EG(fake_scope) = NULL;
EG(trampoline).common.function_name = NULL;
Expand Down Expand Up @@ -1268,9 +1267,7 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
zend_long previous_lineno = EG(lineno_override);
EG(filename_override) = NULL;
EG(lineno_override) = -1;
zend_exception_save();
ce = zend_autoload(autoload_name, lc_name);
zend_exception_restore();
EG(filename_override) = previous_filename;
EG(lineno_override) = previous_lineno;

Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ struct _zend_executor_globals {

zend_objects_store objects_store;
zend_lazy_objects_store lazy_objects_store;
zend_object *exception, *prev_exception;
zend_object *exception;
const zend_op *opline_before_exception;
zend_op exception_op[3];

Expand Down
5 changes: 3 additions & 2 deletions Zend/zend_language_scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -2765,7 +2765,8 @@ skip_escape_conversion:
zend_ptr_stack_reverse_apply(&current_state.heredoc_label_stack, copy_heredoc_label_stack);
zend_exception_save();
zend_object *prev_exception = EG(exception);
EG(exception) = NULL;
while (heredoc_nesting_level) {
zval zv;
int retval;
Expand Down Expand Up @@ -2794,7 +2795,7 @@ skip_escape_conversion:
heredoc_nesting_level = 0;
}
}
zend_exception_restore();
EG(exception) = prev_exception;
if (
(first_token == T_VARIABLE
Expand Down
17 changes: 13 additions & 4 deletions Zend/zend_object_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,7 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam
property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__get != NULL), cache_slot, &prop_info);

if (EXPECTED(IS_VALID_PROPERTY_OFFSET(property_offset))) {
try_again:
retval = OBJ_PROP(zobj, property_offset);
if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
if (EXPECTED(!zobj->ce->__get) ||
Expand Down Expand Up @@ -1477,7 +1478,15 @@ ZEND_API zval *zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *nam
}
retval = zend_hash_add(zobj->properties, name, &EG(uninitialized_zval));
}
} else if (!IS_HOOKED_PROPERTY_OFFSET(property_offset) && zobj->ce->__get == NULL) {
} else if (IS_HOOKED_PROPERTY_OFFSET(property_offset)) {
if (!(prop_info->flags & ZEND_ACC_VIRTUAL) && !zend_should_call_hook(prop_info, zobj)) {
property_offset = prop_info->offset;
if (!ZEND_TYPE_IS_SET(prop_info->type)) {
prop_info = NULL;
}
goto try_again;
}
} else if (zobj->ce->__get == NULL) {
retval = &EG(error_zval);
}

Expand Down Expand Up @@ -1685,7 +1694,6 @@ ZEND_API ZEND_ATTRIBUTE_NONNULL zend_function *zend_get_call_trampoline_func(
* The low bit must be zero, to not be interpreted as a MAP_PTR offset.
*/
static const void *dummy = (void*)(intptr_t)2;
static const zend_arg_info arg_info[1] = {{0}};

if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
func = &EG(trampoline).op_array;
Expand Down Expand Up @@ -1732,7 +1740,7 @@ ZEND_API ZEND_ATTRIBUTE_NONNULL zend_function *zend_get_call_trampoline_func(
func->prop_info = NULL;
func->num_args = 0;
func->required_num_args = 0;
func->arg_info = (zend_arg_info *) arg_info;
func->arg_info = zend_call_trampoline_arginfo;

return (zend_function*)func;
}
Expand Down Expand Up @@ -2576,6 +2584,7 @@ ZEND_API const zend_object_handlers std_object_handlers = {
};

void zend_object_handlers_startup(void) {
zend_call_trampoline_arginfo[0].name = ZSTR_KNOWN(ZEND_STR_ARGS);
zend_call_trampoline_arginfo[0].name = ZSTR_KNOWN(ZEND_STR_ARGUMENTS);
zend_call_trampoline_arginfo[0].type = (zend_type)ZEND_TYPE_INIT_CODE(IS_MIXED, false, _ZEND_ARG_INFO_FLAGS(false, 1, 0));
zend_property_hook_arginfo[0].name = ZSTR_KNOWN(ZEND_STR_VALUE);
}
1 change: 1 addition & 0 deletions Zend/zend_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ EMPTY_SWITCH_DEFAULT_CASE()
_(ZEND_STR_OBJECT_OPERATOR, "->") \
_(ZEND_STR_PAAMAYIM_NEKUDOTAYIM, "::") \
_(ZEND_STR_ARGS, "args") \
_(ZEND_STR_ARGUMENTS, "arguments") \
_(ZEND_STR_UNKNOWN, "unknown") \
_(ZEND_STR_UNKNOWN_CAPITALIZED, "Unknown") \
_(ZEND_STR_EXIT, "exit") \
Expand Down
Loading