diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index 4145bc2b6154..5f9f06ec0749 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -598,6 +598,8 @@ static zend_result php_json_encode_serializable_object(smart_str *buf, zval *val ZEND_GUARD_PROTECT_RECURSION(guard, JSON); + GC_ADDREF(obj); + ZVAL_STRING(&fname, "jsonSerialize"); if (FAILURE == call_user_function(NULL, val, &fname, &retval, 0, NULL) || Z_TYPE(retval) == IS_UNDEF) { @@ -610,6 +612,7 @@ static zend_result php_json_encode_serializable_object(smart_str *buf, zval *val smart_str_appendl(buf, "null", 4); } ZEND_GUARD_UNPROTECT_RECURSION(guard, JSON); + OBJ_RELEASE(obj); return FAILURE; } @@ -622,6 +625,7 @@ static zend_result php_json_encode_serializable_object(smart_str *buf, zval *val smart_str_appendl(buf, "null", 4); } ZEND_GUARD_UNPROTECT_RECURSION(guard, JSON); + OBJ_RELEASE(obj); return FAILURE; } @@ -638,6 +642,7 @@ static zend_result php_json_encode_serializable_object(smart_str *buf, zval *val zval_ptr_dtor(&retval); zval_ptr_dtor(&fname); + OBJ_RELEASE(obj); return return_code; } diff --git a/ext/json/tests/gh21024.phpt b/ext/json/tests/gh21024.phpt new file mode 100644 index 000000000000..c31359aaeeab --- /dev/null +++ b/ext/json/tests/gh21024.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-21024 (UAF in json_encode() when jsonSerialize()'s error handler frees the object) +--EXTENSIONS-- +json +--FILE-- + 1]; + } +} +$arr = [new Bar]; +$ref = &$arr[0]; +set_error_handler(function () use (&$ref) { $ref = null; }); +var_dump(json_encode($arr)); +echo "survived\n"; +?> +--EXPECT-- +string(9) "[{"k":1}]" +survived