From 88b9149fc95ead287e91adc44e0c75553169a0b9 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Mon, 29 Jun 2020 02:07:08 +0200 Subject: [PATCH 1/6] Add throw_on_error declare This declare promotes warnings automatically to Exceptions --- .../declare_off_must_not_promote_warning.phpt | 10 ++++ .../declare_on_must_promote_warning.phpt | 30 ++++++++++++ .../declare_statement_isolated.phpt | 20 ++++++++ .../exception_or_warning-docref_001.phpt | 20 ++++++++ .../exception_or_warning-docref_002.phpt | 16 +++++++ .../exception_or_warning-docref_003.phpt | 15 ++++++ .../throw_on_error/fixture/declare_off.inc | 4 ++ .../throw_on_error/fixture/declare_on.inc | 4 ++ .../throw_on_error/fixture/no_declare.inc | 2 + .../ignore_error_reporting.phpt | 30 ++++++++++++ .../ignore_suppress_operator.phpt | 30 ++++++++++++ .../no_declare_must_not_promote_warning.phpt | 17 +++++++ .../play_nice_with_strict_types_after.phpt | 10 ++++ .../play_nice_with_strict_types_before.phpt | 10 ++++ .../promote_warning_in_internal_function.phpt | 44 ++++++++++++++++++ .../promote_warning_in_user_function.phpt | 46 +++++++++++++++++++ .../statement_must_be_the_first_one.phpt | 10 ++++ .../throw_on_error_declare_statement.phpt | 9 ++++ Zend/zend.c | 17 +++++++ Zend/zend_compile.c | 25 ++++++++++ Zend/zend_compile.h | 3 ++ ext/zend_test/test.c | 8 ++++ ext/zend_test/test.stub.php | 3 ++ ext/zend_test/test_arginfo.h | 6 ++- main/main.c | 29 ++++++++++++ main/php.h | 2 + 26 files changed, 419 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/throw_on_error/declare_off_must_not_promote_warning.phpt create mode 100644 Zend/tests/throw_on_error/declare_on_must_promote_warning.phpt create mode 100644 Zend/tests/throw_on_error/declare_statement_isolated.phpt create mode 100644 Zend/tests/throw_on_error/exception_or_warning-docref_001.phpt create mode 100644 Zend/tests/throw_on_error/exception_or_warning-docref_002.phpt create mode 100644 Zend/tests/throw_on_error/exception_or_warning-docref_003.phpt create mode 100644 Zend/tests/throw_on_error/fixture/declare_off.inc create mode 100644 Zend/tests/throw_on_error/fixture/declare_on.inc create mode 100644 Zend/tests/throw_on_error/fixture/no_declare.inc create mode 100644 Zend/tests/throw_on_error/ignore_error_reporting.phpt create mode 100644 Zend/tests/throw_on_error/ignore_suppress_operator.phpt create mode 100644 Zend/tests/throw_on_error/no_declare_must_not_promote_warning.phpt create mode 100644 Zend/tests/throw_on_error/play_nice_with_strict_types_after.phpt create mode 100644 Zend/tests/throw_on_error/play_nice_with_strict_types_before.phpt create mode 100644 Zend/tests/throw_on_error/promote_warning_in_internal_function.phpt create mode 100644 Zend/tests/throw_on_error/promote_warning_in_user_function.phpt create mode 100644 Zend/tests/throw_on_error/statement_must_be_the_first_one.phpt create mode 100644 Zend/tests/throw_on_error/throw_on_error_declare_statement.phpt diff --git a/Zend/tests/throw_on_error/declare_off_must_not_promote_warning.phpt b/Zend/tests/throw_on_error/declare_off_must_not_promote_warning.phpt new file mode 100644 index 0000000000000..96ef96660d60b --- /dev/null +++ b/Zend/tests/throw_on_error/declare_off_must_not_promote_warning.phpt @@ -0,0 +1,10 @@ +--TEST-- +If throw_on_error declare statement is explicitly turned off do not promote warning +--FILE-- + + string(25) "Undefined variable $undef" + ["string":"Exception":private]=> + string(0) "" + ["code":protected]=> + int(2) + ["file":protected]=> + string(%d) "%s" + ["line":protected]=> + int(5) + ["trace":"Exception":private]=> + array(0) { + } + ["previous":"Exception":private]=> + NULL +} diff --git a/Zend/tests/throw_on_error/declare_statement_isolated.phpt b/Zend/tests/throw_on_error/declare_statement_isolated.phpt new file mode 100644 index 0000000000000..cd6f548f145a7 --- /dev/null +++ b/Zend/tests/throw_on_error/declare_statement_isolated.phpt @@ -0,0 +1,20 @@ +--TEST-- +Test throw_on_error declare statement is isolated to file +--FILE-- + +DONE +--EXPECTF-- +Warning: Undefined variable $undef in %sno_declare.inc on line 2 +Warning caught + +Warning: Undefined variable $undef in %sdeclare_off.inc on line 4 +DONE diff --git a/Zend/tests/throw_on_error/exception_or_warning-docref_001.phpt b/Zend/tests/throw_on_error/exception_or_warning-docref_001.phpt new file mode 100644 index 0000000000000..af6cf317096fd --- /dev/null +++ b/Zend/tests/throw_on_error/exception_or_warning-docref_001.phpt @@ -0,0 +1,20 @@ +--TEST-- +php_exception_or_warning_docref test when declare enabled +--SKIPIF-- + +--FILE-- +getMessage() . \PHP_EOL; +} + +echo "OK"; +--EXPECT-- +Context dependent +OK diff --git a/Zend/tests/throw_on_error/exception_or_warning-docref_002.phpt b/Zend/tests/throw_on_error/exception_or_warning-docref_002.phpt new file mode 100644 index 0000000000000..54efd51f24717 --- /dev/null +++ b/Zend/tests/throw_on_error/exception_or_warning-docref_002.phpt @@ -0,0 +1,16 @@ +--TEST-- +php_exception_or_warning_docref test when declare explicitly disable +--SKIPIF-- + +--FILE-- + +--FILE-- + + string(25) "Undefined variable $undef" + ["string":"Exception":private]=> + string(0) "" + ["code":protected]=> + int(2) + ["file":protected]=> + string(%d) "%s" + ["line":protected]=> + int(5) + ["trace":"Exception":private]=> + array(0) { + } + ["previous":"Exception":private]=> + NULL +} diff --git a/Zend/tests/throw_on_error/ignore_suppress_operator.phpt b/Zend/tests/throw_on_error/ignore_suppress_operator.phpt new file mode 100644 index 0000000000000..59a164fccca64 --- /dev/null +++ b/Zend/tests/throw_on_error/ignore_suppress_operator.phpt @@ -0,0 +1,30 @@ +--TEST-- +Promoted warning by throw_on_error must ignore @ operator +--FILE-- + + string(25) "Undefined variable $undef" + ["string":"Exception":private]=> + string(0) "" + ["code":protected]=> + int(2) + ["file":protected]=> + string(%d) "%s" + ["line":protected]=> + int(5) + ["trace":"Exception":private]=> + array(0) { + } + ["previous":"Exception":private]=> + NULL +} diff --git a/Zend/tests/throw_on_error/no_declare_must_not_promote_warning.phpt b/Zend/tests/throw_on_error/no_declare_must_not_promote_warning.phpt new file mode 100644 index 0000000000000..44dd899d09cbb --- /dev/null +++ b/Zend/tests/throw_on_error/no_declare_must_not_promote_warning.phpt @@ -0,0 +1,17 @@ +--TEST-- +If throw_on_error declare statement is missing do not promote warning +--FILE-- + + string(82) "file_get_contents(not_found.txt): Failed to open stream: No such file or directory" + ["string":"Exception":private]=> + string(0) "" + ["code":protected]=> + int(2) + ["file":protected]=> + string(%d) "%s" + ["line":protected]=> + int(5) + ["trace":"Exception":private]=> + array(1) { + [0]=> + array(4) { + ["file"]=> + string(%d) "%s" + ["line"]=> + int(5) + ["function"]=> + string(17) "file_get_contents" + ["args"]=> + array(1) { + [0]=> + string(13) "not_found.txt" + } + } + } + ["previous":"Exception":private]=> + NULL +} diff --git a/Zend/tests/throw_on_error/promote_warning_in_user_function.phpt b/Zend/tests/throw_on_error/promote_warning_in_user_function.phpt new file mode 100644 index 0000000000000..9e521851f6a5c --- /dev/null +++ b/Zend/tests/throw_on_error/promote_warning_in_user_function.phpt @@ -0,0 +1,46 @@ +--TEST-- +throw_on_error declare statement must promote warning emit in user defined function +--FILE-- + + string(25) "Undefined variable $undef" + ["string":"Exception":private]=> + string(0) "" + ["code":protected]=> + int(2) + ["file":protected]=> + string(%d) "%s" + ["line":protected]=> + int(5) + ["trace":"Exception":private]=> + array(1) { + [0]=> + array(4) { + ["file"]=> + string(%d) "%s" + ["line"]=> + int(9) + ["function"]=> + string(3) "foo" + ["args"]=> + array(0) { + } + } + } + ["previous":"Exception":private]=> + NULL +} diff --git a/Zend/tests/throw_on_error/statement_must_be_the_first_one.phpt b/Zend/tests/throw_on_error/statement_must_be_the_first_one.phpt new file mode 100644 index 0000000000000..065c8dd40cf50 --- /dev/null +++ b/Zend/tests/throw_on_error/statement_must_be_the_first_one.phpt @@ -0,0 +1,10 @@ +--TEST-- +throw_on_error declare statement must be before anything else +--FILE-- +func || !ZEND_USER_CODE(ex->func->type))) { + ex = ex->prev_execute_data; + } + if (ex->func == NULL) { + goto normal; + } + if ((ex->func->common.fn_flags & ZEND_ACC_THROW_WARNING) != 0) { + zend_throw_exception(NULL, ZSTR_VAL(message), E_WARNING); + return; + } + } + normal: + /* Report about uncaught exception in case of fatal errors */ if (EG(exception)) { zend_execute_data *ex; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index cfe44d3f3766f..2aa5c17457061 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6064,6 +6064,28 @@ static void zend_compile_declare(zend_ast *ast) /* {{{ */ CG(active_op_array)->fn_flags |= ZEND_ACC_STRICT_TYPES; } + } else if (zend_string_equals_literal_ci(name, "throw_on_error")) { + zval value_zv; + + if (FAILURE == zend_is_first_statement(ast, /* allow_nop */ 0)) { + zend_error_noreturn(E_COMPILE_ERROR, "throw_on_error declaration must be " + "the very first statement in the script"); + } + + if (ast->child[1] != NULL) { + zend_error_noreturn(E_COMPILE_ERROR, "throw_on_error declaration must not " + "use block mode"); + } + + zend_const_expr_to_zval(&value_zv, value_ast_ptr, /* allow_dynamic */ false); + + if (Z_TYPE(value_zv) != IS_LONG || (Z_LVAL(value_zv) != 0 && Z_LVAL(value_zv) != 1)) { + zend_error_noreturn(E_COMPILE_ERROR, "throw_on_error declaration must have 0 or 1 as its value"); + } + + if (Z_LVAL(value_zv) == 1) { + CG(active_op_array)->fn_flags |= ZEND_ACC_THROW_WARNING; + } } else { zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", ZSTR_VAL(name)); } @@ -7127,6 +7149,9 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel) op_array->fn_flags |= ZEND_ACC_PRELOADED; } + op_array->fn_flags |= (orig_op_array->fn_flags & ZEND_ACC_THROW_WARNING); + op_array->fn_flags |= decl->flags; + op_array->fn_flags |= (orig_op_array->fn_flags & ZEND_ACC_STRICT_TYPES); op_array->fn_flags |= decl->flags; op_array->line_start = decl->start_lineno; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index b3e2d62737d51..36a03045463a0 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -360,6 +360,9 @@ typedef struct _zend_oparray_context { /* supports opcache compile-time evaluation (funcs) | | | */ #define ZEND_ACC_COMPILE_TIME_EVAL (1 << 27) /* | X | | */ /* | | | */ +/* op_array uses throw_on_error mode | | | */ +#define ZEND_ACC_THROW_WARNING (1U << 30) /* | X | | */ +/* | | | */ /* op_array uses strict mode types | | | */ #define ZEND_ACC_STRICT_TYPES (1U << 31) /* | X | | */ diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 63a141e15057a..4100ef9ad5cfc 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -238,6 +238,14 @@ static ZEND_FUNCTION(zend_test_compile_string) return; } +/* Tests php_exception_or_warning_docref */ +ZEND_FUNCTION(zend_throw_on_error_declare_exception_or_warning) +{ + zend_parse_parameters_none(); + php_exception_or_warning_docref(NULL, NULL, "Context dependent"); +} +/* }}} */ + /* Tests Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL */ static ZEND_FUNCTION(zend_string_or_stdclass_or_null) { diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 9361d81c267d8..0173cd357651f 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -109,6 +109,9 @@ function zend_weakmap_dump(): array {} function zend_get_unit_enum(): ZendTestUnitEnum {} function zend_test_parameter_with_attribute(string $parameter): int {} + + function zend_throw_on_error_declare_exception_or_warning(): void {} + } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 22290c580d059..c37fb4065e29d 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: bf10c37919483ac04bc1f788ac6e59b5edab295e */ + * Stub hash: f9f5282198f015f875780f3e5bb13c621aa37b15 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -75,6 +75,8 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_parameter_with_attribu ZEND_ARG_TYPE_INFO(0, parameter, IS_STRING, 0) ZEND_END_ARG_INFO() +#define arginfo_zend_throw_on_error_declare_exception_or_warning arginfo_zend_test_void_return + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ZendTestNS2_ZendSubNS_namespaced_func, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() @@ -131,6 +133,7 @@ static ZEND_FUNCTION(zend_weakmap_remove); static ZEND_FUNCTION(zend_weakmap_dump); static ZEND_FUNCTION(zend_get_unit_enum); static ZEND_FUNCTION(zend_test_parameter_with_attribute); +static ZEND_FUNCTION(zend_throw_on_error_declare_exception_or_warning); static ZEND_FUNCTION(namespaced_func); static ZEND_METHOD(_ZendTestClass, is_object); static ZEND_METHOD(_ZendTestClass, __toString); @@ -167,6 +170,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_weakmap_dump, arginfo_zend_weakmap_dump) ZEND_FE(zend_get_unit_enum, arginfo_zend_get_unit_enum) ZEND_FE(zend_test_parameter_with_attribute, arginfo_zend_test_parameter_with_attribute) + ZEND_FE(zend_throw_on_error_declare_exception_or_warning, arginfo_zend_throw_on_error_declare_exception_or_warning) ZEND_NS_FE("ZendTestNS2\\ZendSubNS", namespaced_func, arginfo_ZendTestNS2_ZendSubNS_namespaced_func) ZEND_FE_END }; diff --git a/main/main.c b/main/main.c index 2a417987f3148..357580ff4ade0 100644 --- a/main/main.c +++ b/main/main.c @@ -1158,6 +1158,35 @@ PHPAPI ZEND_COLD void php_win32_docref2_from_error(DWORD error, const char *para } #endif + +/* {{{ php_exception_or_warning_docref */ +/* Throw an Exception corresponding to exception_ce class if throw_on_error declare statement is present + * otherwise fallback to a traditional docref warning. */ +PHPAPI ZEND_COLD void php_exception_or_warning_docref(const char *docref, + zend_class_entry *exception_ce, const char *format, ...) +{ + va_list args; + zend_execute_data *ex = EG(current_execute_data); + + va_start(args, format); + + /* Find first non internal execute_data */ + while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) { + ex = ex->prev_execute_data; + } + if ((ex->func->common.fn_flags & ZEND_ACC_THROW_WARNING) != 0) { + char *message = NULL; + + zend_vspprintf(&message, 0, format, args); + zend_throw_exception(exception_ce, message, E_WARNING); + efree(message); + } else { + php_verror(docref, "", E_WARNING, format, args); + } + va_end(args); +} +/* }}} */ + /* {{{ php_html_puts */ PHPAPI void php_html_puts(const char *str, size_t size) { diff --git a/main/php.h b/main/php.h index e8fcea5b6f607..1b4e927a845a4 100644 --- a/main/php.h +++ b/main/php.h @@ -334,6 +334,8 @@ PHPAPI ZEND_COLD void php_error_docref2(const char *docref, const char *param1, PHPAPI ZEND_COLD void php_win32_docref1_from_error(DWORD error, const char *param1); PHPAPI ZEND_COLD void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2); #endif +PHPAPI ZEND_COLD void php_exception_or_warning_docref(const char *docref, zend_class_entry *exception_ce, const char *format, ...) + PHP_ATTRIBUTE_FORMAT(printf, 3, 4); END_EXTERN_C() #define zenderror phperror From 5b674449fd0377d8b0e498c07ea39144bc7efa63 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Mon, 29 Jun 2020 03:25:28 +0200 Subject: [PATCH 2/6] JSON throw exception when throw_on_error declare is enabled --- ext/json/json.c | 19 ++++--- ...on_decode_with_throw_on_error_declare.phpt | 49 +++++++++++++++++ ...on_encode_with_throw_on_error_declare.phpt | 53 +++++++++++++++++++ 3 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 ext/json/tests/json_decode_with_throw_on_error_declare.phpt create mode 100644 ext/json/tests/json_encode_with_throw_on_error_declare.phpt diff --git a/ext/json/json.c b/ext/json/json.c index c66a48c49ea88..e0f071203ab73 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -204,7 +204,8 @@ PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, if (php_json_yyparse(&parser)) { php_json_error_code error_code = php_json_parser_error_code(&parser); - if (!(options & PHP_JSON_THROW_ON_ERROR)) { + if (!(options & PHP_JSON_THROW_ON_ERROR) && + (EG(current_execute_data)->prev_execute_data->func->common.fn_flags & ZEND_ACC_THROW_WARNING) == 0) { JSON_G(error_code) = error_code; } else { zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(error_code), error_code); @@ -237,7 +238,9 @@ PHP_FUNCTION(json_encode) encoder.max_depth = (int)depth; php_json_encode_zval(&buf, parameter, (int)options, &encoder); - if (!(options & PHP_JSON_THROW_ON_ERROR) || (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) { + if ((!(options & PHP_JSON_THROW_ON_ERROR) && + (EX(prev_execute_data)->func->common.fn_flags & ZEND_ACC_THROW_WARNING) == 0) + || (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) { JSON_G(error_code) = encoder.error_code; if (encoder.error_code != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) { smart_str_free(&buf); @@ -277,17 +280,19 @@ PHP_FUNCTION(json_decode) Z_PARAM_LONG(options) ZEND_PARSE_PARAMETERS_END(); - if (!(options & PHP_JSON_THROW_ON_ERROR)) { + if (!(options & PHP_JSON_THROW_ON_ERROR) && + (EX(prev_execute_data)->func->common.fn_flags & ZEND_ACC_THROW_WARNING) == 0) { JSON_G(error_code) = PHP_JSON_ERROR_NONE; } if (!str_len) { - if (!(options & PHP_JSON_THROW_ON_ERROR)) { + if (!(options & PHP_JSON_THROW_ON_ERROR) && + (EX(prev_execute_data)->func->common.fn_flags & ZEND_ACC_THROW_WARNING) == 0) { JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; - } else { - zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(PHP_JSON_ERROR_SYNTAX), PHP_JSON_ERROR_SYNTAX); + RETURN_NULL(); } - RETURN_NULL(); + zend_throw_exception(php_json_exception_ce, php_json_get_error_msg(PHP_JSON_ERROR_SYNTAX), PHP_JSON_ERROR_SYNTAX); + RETURN_THROWS(); } if (depth <= 0) { diff --git a/ext/json/tests/json_decode_with_throw_on_error_declare.phpt b/ext/json/tests/json_decode_with_throw_on_error_declare.phpt new file mode 100644 index 0000000000000..8c1fbffdab5da --- /dev/null +++ b/ext/json/tests/json_decode_with_throw_on_error_declare.phpt @@ -0,0 +1,49 @@ +--TEST-- +Test json_decode() function when throw_on_error declare is present +--FILE-- + +--EXPECTF-- +object(JsonException)#1 (7) { + ["message":protected]=> + string(12) "Syntax error" + ["string":"Exception":private]=> + string(0) "" + ["code":protected]=> + int(4) + ["file":protected]=> + string(%d) "%s" + ["line":protected]=> + int(%d) + ["trace":"Exception":private]=> + array(1) { + [0]=> + array(4) { + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) + ["function"]=> + string(11) "json_decode" + ["args"]=> + array(3) { + [0]=> + string(1) "{" + [1]=> + bool(false) + [2]=> + int(512) + } + } + } + ["previous":"Exception":private]=> + NULL +} diff --git a/ext/json/tests/json_encode_with_throw_on_error_declare.phpt b/ext/json/tests/json_encode_with_throw_on_error_declare.phpt new file mode 100644 index 0000000000000..f2d42d077e820 --- /dev/null +++ b/ext/json/tests/json_encode_with_throw_on_error_declare.phpt @@ -0,0 +1,53 @@ +--TEST-- +Test json_encode() function when throw_on_error declare is present +--FILE-- + +--EXPECTF-- +object(JsonException)#1 (7) { + ["message":protected]=> + string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" + ["string":"Exception":private]=> + string(0) "" + ["code":protected]=> + int(5) + ["file":protected]=> + string(%d) "%s" + ["line":protected]=> + int(%d) + ["trace":"Exception":private]=> + array(1) { + [0]=> + array(4) { + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) + ["function"]=> + string(11) "json_encode" + ["args"]=> + array(1) { + [0]=> + string(1) "%s" + } + } + } + ["previous":"Exception":private]=> + NULL +} +string(4) "null" +int(5) +string(56) "Malformed UTF-8 characters, possibly incorrectly encoded" From 4d292ae5a3c85ef2819bb531795c16051a54f6f9 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Mon, 27 Jul 2020 15:35:36 +0100 Subject: [PATCH 3/6] Add dedicated IO exceptions --- Zend/zend_exceptions.c | 3 ++ Zend/zend_exceptions.stub.php | 3 ++ Zend/zend_exceptions_arginfo.h | 18 ++++++- ...flectionExtension_getClassNames_basic.phpt | 18 ++++++- ext/standard/basic_functions.c | 3 ++ ext/standard/config.m4 | 3 +- ext/standard/config.w32 | 2 +- ext/standard/io_exceptions.c | 54 +++++++++++++++++++ ext/standard/io_exceptions.h | 32 +++++++++++ ext/standard/io_exceptions.stub.php | 14 +++++ ext/standard/io_exceptions_arginfo.h | 29 ++++++++++ 11 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 ext/standard/io_exceptions.c create mode 100644 ext/standard/io_exceptions.h create mode 100644 ext/standard/io_exceptions.stub.php create mode 100644 ext/standard/io_exceptions_arginfo.h diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 85e21c64a037b..9b03aa9ad7490 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -42,6 +42,7 @@ ZEND_API zend_class_entry *zend_ce_value_error; ZEND_API zend_class_entry *zend_ce_arithmetic_error; ZEND_API zend_class_entry *zend_ce_division_by_zero_error; ZEND_API zend_class_entry *zend_ce_unhandled_match_error; +ZEND_API zend_class_entry *zend_ce_io; /* Internal pseudo-exception that is not exposed to userland. Throwing this exception *does not* execute finally blocks. */ static zend_class_entry zend_ce_unwind_exit; @@ -788,6 +789,8 @@ void zend_register_default_exception(void) /* {{{ */ INIT_CLASS_ENTRY(zend_ce_unwind_exit, "UnwindExit", NULL); INIT_CLASS_ENTRY(zend_ce_graceful_exit, "GracefulExit", NULL); + + zend_ce_io = register_class_IO(zend_ce_throwable); } /* }}} */ diff --git a/Zend/zend_exceptions.stub.php b/Zend/zend_exceptions.stub.php index d2de356dee1d4..f27d3e03932ea 100644 --- a/Zend/zend_exceptions.stub.php +++ b/Zend/zend_exceptions.stub.php @@ -168,3 +168,6 @@ class DivisionByZeroError extends ArithmeticError class UnhandledMatchError extends Error { } + +interface IO extends Throwable {} + diff --git a/Zend/zend_exceptions_arginfo.h b/Zend/zend_exceptions_arginfo.h index 48e668b110dd3..d5f06d28813ef 100644 --- a/Zend/zend_exceptions_arginfo.h +++ b/Zend/zend_exceptions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 9d1c2027ebd14e621d9b5b79056ba7300a455be8 */ + * Stub hash: 452f9d6f9dfbfab81da1334c921f1b8326f310aa */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Throwable_getMessage, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -187,6 +187,11 @@ static const zend_function_entry class_UnhandledMatchError_methods[] = { ZEND_FE_END }; + +static const zend_function_entry class_IO_methods[] = { + ZEND_FE_END +}; + static zend_class_entry *register_class_Throwable(zend_class_entry *class_entry_Stringable) { zend_class_entry ce, *class_entry; @@ -395,3 +400,14 @@ static zend_class_entry *register_class_UnhandledMatchError(zend_class_entry *cl return class_entry; } + +static zend_class_entry *register_class_IO(zend_class_entry *class_entry_Throwable) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "IO", class_IO_methods); + class_entry = zend_register_internal_interface(&ce); + zend_class_implements(class_entry, 1, class_entry_Throwable); + + return class_entry; +} diff --git a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt index 5c4d1cb87f1d7..d42bca9513076 100644 --- a/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt +++ b/ext/reflection/tests/ReflectionExtension_getClassNames_basic.phpt @@ -8,13 +8,27 @@ $standard = new ReflectionExtension('standard'); var_dump($standard->getClassNames()); ?> --EXPECT-- -array(4) { +array(11) { [0]=> string(22) "__PHP_Incomplete_Class" [1]=> string(14) "AssertionError" [2]=> - string(15) "php_user_filter" + string(10) "FileSystem" [3]=> + string(7) "Network" + [4]=> + string(15) "FileSystemError" + [5]=> + string(12) "FileNotFound" + [6]=> + string(12) "NotDirectory" + [7]=> + string(23) "InsufficientPermissions" + [8]=> + string(16) "TemporaryFailure" + [9]=> + string(15) "php_user_filter" + [10]=> string(9) "Directory" } diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 09f67b2e3f60b..cc5dfaaee09f9 100755 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -30,6 +30,7 @@ #include "ext/session/php_session.h" #include "zend_exceptions.h" #include "zend_operators.h" +#include "io_exceptions.h" #include "ext/standard/php_dns.h" #include "ext/standard/php_uuencode.h" #include "ext/standard/php_mt_rand.h" @@ -355,6 +356,8 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */ register_html_constants(INIT_FUNC_ARGS_PASSTHRU); register_string_constants(INIT_FUNC_ARGS_PASSTHRU); + BASIC_MINIT_SUBMODULE(io_exceptions) + BASIC_MINIT_SUBMODULE(var) BASIC_MINIT_SUBMODULE(file) BASIC_MINIT_SUBMODULE(pack) diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index 2e78b2df01888..29cc54f029b93 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -460,7 +460,8 @@ PHP_NEW_EXTENSION(standard, array.c base64.c basic_functions.c browscap.c crc32. http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \ filters.c proc_open.c streamsfuncs.c http.c password.c \ - random.c net.c hrtime.c crc32_x86.c libavifinfo/avifinfo.c,,, + random.c net.c hrtime.c crc32_x86.c libavifinfo/avifinfo.c \ + io_exceptions.c,,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_ADD_BUILD_DIR($ext_builddir/libavifinfo) diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index 1813210849344..a091f1e86de53 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -35,7 +35,7 @@ EXTENSION("standard", "array.c base64.c basic_functions.c browscap.c \ url_scanner_ex.c ftp_fopen_wrapper.c http_fopen_wrapper.c \ php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \ user_filters.c uuencode.c filters.c proc_open.c password.c \ - streamsfuncs.c http.c flock_compat.c random.c hrtime.c", false /* never shared */, + streamsfuncs.c http.c flock_compat.c random.c hrtime.c io_exceptions.c", false /* never shared */, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); ADD_SOURCES("ext/standard/libavifinfo", "avifinfo.c", "standard"); PHP_STANDARD = "yes"; diff --git a/ext/standard/io_exceptions.c b/ext/standard/io_exceptions.c new file mode 100644 index 0000000000000..a86e9b4cbe5b7 --- /dev/null +++ b/ext/standard/io_exceptions.c @@ -0,0 +1,54 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: George Peter Banyard | + +----------------------------------------------------------------------+ + */ + +/* {{{ includes */ +#include "php.h" +#include "zend_exceptions.h" +#include "io_exceptions.h" +#include "io_exceptions_arginfo.h" + +/* Class entry pointers */ +PHPAPI zend_class_entry *zend_ce_filesystem; +PHPAPI zend_class_entry *zend_ce_network; +PHPAPI zend_class_entry *zend_ce_filesystem_error; +PHPAPI zend_class_entry *zend_ce_insufficient_permissions; +PHPAPI zend_class_entry *zend_ce_temporary_failure; + +PHP_MINIT_FUNCTION(io_exceptions) { + zend_class_entry ce; + + /* Register interfaces */ + INIT_CLASS_ENTRY(ce, "FileSystem", class_FileSystem_methods); + zend_ce_filesystem = zend_register_internal_interface(&ce); + + INIT_CLASS_ENTRY(ce, "Network", class_Network_methods); + zend_ce_network = zend_register_internal_interface(&ce); + + /* Register exceptions */ + INIT_CLASS_ENTRY(ce, "FileSystemError", class_FileSystemError_methods); + zend_ce_filesystem_error = zend_register_internal_class_ex(&ce, zend_ce_exception); + zend_class_implements(zend_ce_filesystem_error, 1, zend_ce_filesystem); + + INIT_CLASS_ENTRY(ce, "InsufficientPermissions", class_InsufficientPermissions_methods); + zend_ce_insufficient_permissions = zend_register_internal_class_ex(&ce, zend_ce_exception); + zend_class_implements(zend_ce_insufficient_permissions, 1, zend_ce_filesystem); + + INIT_CLASS_ENTRY(ce, "TemporaryFailure", class_TemporaryFailure_methods); + zend_ce_temporary_failure = zend_register_internal_class_ex(&ce, zend_ce_exception); + zend_class_implements(zend_ce_temporary_failure, 1, zend_ce_network); + + return SUCCESS; +} diff --git a/ext/standard/io_exceptions.h b/ext/standard/io_exceptions.h new file mode 100644 index 0000000000000..ab653b2253277 --- /dev/null +++ b/ext/standard/io_exceptions.h @@ -0,0 +1,32 @@ +/* + +----------------------------------------------------------------------+ + | Copyright (c) The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: George Peter Banyard | + +----------------------------------------------------------------------+ + */ + +#ifndef PHP_IO_EXCEPTION +#define PHP_IO_EXCEPTION + +PHP_MINIT_FUNCTION(io_exceptions); + +BEGIN_EXTERN_C() + +extern PHPAPI zend_class_entry *zend_ce_filesystem; +extern PHPAPI zend_class_entry *zend_ce_network; +extern PHPAPI zend_class_entry *zend_ce_filesystem_error; +extern PHPAPI zend_class_entry *zend_ce_insufficient_permissions; +extern PHPAPI zend_class_entry *zend_ce_temporary_failure; + +END_EXTERN_C() + +#endif /* PHP_IO_EXCEPTION */ diff --git a/ext/standard/io_exceptions.stub.php b/ext/standard/io_exceptions.stub.php new file mode 100644 index 0000000000000..8e93b24c66af9 --- /dev/null +++ b/ext/standard/io_exceptions.stub.php @@ -0,0 +1,14 @@ + Date: Mon, 27 Jul 2020 16:15:16 +0100 Subject: [PATCH 4/6] Example case with dir functions --- ext/standard/dir.c | 13 ++++--- ...scandir_error2_throw_on_error_declare.phpt | 38 +++++++++++++++++++ 2 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 ext/standard/tests/dir/scandir_error2_throw_on_error_declare.phpt diff --git a/ext/standard/dir.c b/ext/standard/dir.c index 7c9012cb6b198..5dec20c948f19 100644 --- a/ext/standard/dir.c +++ b/ext/standard/dir.c @@ -23,6 +23,7 @@ #include "php_string.h" #include "php_scandir.h" #include "basic_functions.h" +#include "io_exceptions.h" #include "dir_arginfo.h" #if HAVE_UNISTD_H @@ -282,7 +283,7 @@ PHP_FUNCTION(chroot) ret = chroot(str); if (ret != 0) { - php_error_docref(NULL, E_WARNING, "%s (errno %d)", strerror(errno), errno); + php_exception_or_warning_docref(NULL, zend_ce_filesystem_error, "%s (errno %d)", strerror(errno), errno); RETURN_FALSE; } @@ -291,7 +292,7 @@ PHP_FUNCTION(chroot) ret = chdir("/"); if (ret != 0) { - php_error_docref(NULL, E_WARNING, "%s (errno %d)", strerror(errno), errno); + php_exception_or_warning_docref(NULL, zend_ce_filesystem_error, "%s (errno %d)", strerror(errno), errno); RETURN_FALSE; } @@ -317,7 +318,7 @@ PHP_FUNCTION(chdir) ret = VCWD_CHDIR(str); if (ret != 0) { - php_error_docref(NULL, E_WARNING, "%s (errno %d)", strerror(errno), errno); + php_exception_or_warning_docref(NULL, zend_ce_filesystem_error, "%s (errno %d)", strerror(errno), errno); RETURN_FALSE; } @@ -420,12 +421,12 @@ PHP_FUNCTION(glob) ZEND_PARSE_PARAMETERS_END(); if (pattern_len >= MAXPATHLEN) { - php_error_docref(NULL, E_WARNING, "Pattern exceeds the maximum allowed length of %d characters", MAXPATHLEN); + php_exception_or_warning_docref(NULL, zend_ce_filesystem_error, "Pattern exceeds the maximum allowed length of %d characters", MAXPATHLEN); RETURN_FALSE; } if ((GLOB_AVAILABLE_FLAGS & flags) != flags) { - php_error_docref(NULL, E_WARNING, "At least one of the passed flags is invalid or not supported on this platform"); + php_exception_or_warning_docref(NULL, zend_ce_filesystem_error, "At least one of the passed flags is invalid or not supported on this platform"); RETURN_FALSE; } @@ -564,7 +565,7 @@ PHP_FUNCTION(scandir) n = php_stream_scandir(dirn, &namelist, context, (void *) php_stream_dirent_alphasortr); } if (n < 0) { - php_error_docref(NULL, E_WARNING, "(errno %d): %s", errno, strerror(errno)); + php_exception_or_warning_docref(NULL, zend_ce_filesystem_error, "(errno %d): %s", errno, strerror(errno)); RETURN_FALSE; } diff --git a/ext/standard/tests/dir/scandir_error2_throw_on_error_declare.phpt b/ext/standard/tests/dir/scandir_error2_throw_on_error_declare.phpt new file mode 100644 index 0000000000000..0e24aa54ce6ac --- /dev/null +++ b/ext/standard/tests/dir/scandir_error2_throw_on_error_declare.phpt @@ -0,0 +1,38 @@ +--TEST-- +Test scandir() function error conditions with throw on error declare enabled - Non-existent directory +--SKIPIF-- + +--FILE-- +getMessage() . \PHP_EOL; +} + +echo "\n-- Pass scandir() a relative path that does not exist --\n"; +try { + var_dump(scandir('/idonotexist')); +} catch (\FileSystem $e) { + echo $e->getMessage() . \PHP_EOL; +} +?> +--EXPECT-- +*** Testing scandir() : error conditions *** + +-- Pass scandir() an absolute path that does not exist -- +(errno 2): No such file or directory + +-- Pass scandir() a relative path that does not exist -- +(errno 2): No such file or directory From e77efd37dd9391110a53814ffaaf8500767acc6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Thu, 30 Jul 2020 15:57:01 +0200 Subject: [PATCH 5/6] Throw specific exceptions depending on the errno in IO. Merges #3 --- ext/standard/dir.c | 2 +- ext/standard/io_exceptions.c | 27 +++++++++++++++ ext/standard/io_exceptions.h | 4 +++ ext/standard/io_exceptions.stub.php | 4 +++ ext/standard/io_exceptions_arginfo.h | 12 ++++++- .../tests/dir/chroot_throw_on_error.phpt | 33 +++++++++++++++++++ .../chroot_throw_on_error_file_in_path.phpt | 33 +++++++++++++++++++ 7 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 ext/standard/tests/dir/chroot_throw_on_error.phpt create mode 100644 ext/standard/tests/dir/chroot_throw_on_error_file_in_path.phpt diff --git a/ext/standard/dir.c b/ext/standard/dir.c index 5dec20c948f19..8d14aeb40d430 100644 --- a/ext/standard/dir.c +++ b/ext/standard/dir.c @@ -283,7 +283,7 @@ PHP_FUNCTION(chroot) ret = chroot(str); if (ret != 0) { - php_exception_or_warning_docref(NULL, zend_ce_filesystem_error, "%s (errno %d)", strerror(errno), errno); + handle_io_error(errno, str); RETURN_FALSE; } diff --git a/ext/standard/io_exceptions.c b/ext/standard/io_exceptions.c index a86e9b4cbe5b7..1a4e5f70e0c53 100644 --- a/ext/standard/io_exceptions.c +++ b/ext/standard/io_exceptions.c @@ -24,6 +24,8 @@ PHPAPI zend_class_entry *zend_ce_filesystem; PHPAPI zend_class_entry *zend_ce_network; PHPAPI zend_class_entry *zend_ce_filesystem_error; +PHPAPI zend_class_entry *zend_ce_file_not_found; +PHPAPI zend_class_entry *zend_ce_not_directory; PHPAPI zend_class_entry *zend_ce_insufficient_permissions; PHPAPI zend_class_entry *zend_ce_temporary_failure; @@ -42,6 +44,14 @@ PHP_MINIT_FUNCTION(io_exceptions) { zend_ce_filesystem_error = zend_register_internal_class_ex(&ce, zend_ce_exception); zend_class_implements(zend_ce_filesystem_error, 1, zend_ce_filesystem); + INIT_CLASS_ENTRY(ce, "FileNotFound", class_FileNotFound_methods); + zend_ce_file_not_found = zend_register_internal_class_ex(&ce, zend_ce_exception); + zend_class_implements(zend_ce_file_not_found, 1, zend_ce_filesystem); + + INIT_CLASS_ENTRY(ce, "NotDirectory", class_FileNotFound_methods); + zend_ce_not_directory = zend_register_internal_class_ex(&ce, zend_ce_exception); + zend_class_implements(zend_ce_not_directory, 1, zend_ce_filesystem); + INIT_CLASS_ENTRY(ce, "InsufficientPermissions", class_InsufficientPermissions_methods); zend_ce_insufficient_permissions = zend_register_internal_class_ex(&ce, zend_ce_exception); zend_class_implements(zend_ce_insufficient_permissions, 1, zend_ce_filesystem); @@ -52,3 +62,20 @@ PHP_MINIT_FUNCTION(io_exceptions) { return SUCCESS; } + +PHPAPI void handle_io_error(int error, const char *path) { + if (path == NULL) { + path = "[unknown]"; + } + switch (error) { + case ENOENT: + php_exception_or_warning_docref(NULL, zend_ce_file_not_found, "File not found: \"%s\"", path); + break; + case ENOTDIR: + php_exception_or_warning_docref(NULL, zend_ce_not_directory, "\"%s\" is not a directory", path); + break; + default: + php_exception_or_warning_docref(NULL, zend_ce_filesystem_error, "%s (path: \"%s\", errno %d)", strerror(errno), path, errno); + break; + } +} diff --git a/ext/standard/io_exceptions.h b/ext/standard/io_exceptions.h index ab653b2253277..1f4c36b8400b7 100644 --- a/ext/standard/io_exceptions.h +++ b/ext/standard/io_exceptions.h @@ -24,9 +24,13 @@ BEGIN_EXTERN_C() extern PHPAPI zend_class_entry *zend_ce_filesystem; extern PHPAPI zend_class_entry *zend_ce_network; extern PHPAPI zend_class_entry *zend_ce_filesystem_error; +extern PHPAPI zend_class_entry *zend_ce_file_not_found; +extern PHPAPI zend_class_entry *zend_ce_not_directory; extern PHPAPI zend_class_entry *zend_ce_insufficient_permissions; extern PHPAPI zend_class_entry *zend_ce_temporary_failure; END_EXTERN_C() +PHPAPI void handle_io_error(int error, const char *path); + #endif /* PHP_IO_EXCEPTION */ diff --git a/ext/standard/io_exceptions.stub.php b/ext/standard/io_exceptions.stub.php index 8e93b24c66af9..06dae6d317e14 100644 --- a/ext/standard/io_exceptions.stub.php +++ b/ext/standard/io_exceptions.stub.php @@ -9,6 +9,10 @@ interface Network extends IO {} /* Should use more specialized ones instead but for PoC will use this instead */ class FileSystemError extends Exception implements FileSystem {} +class FileNotFound extends Exception implements FileSystem {} + +class NotDirectory extends Exception implements FileSystem {} + class InsufficientPermissions extends Exception implements FileSystem {} class TemporaryFailure extends Exception implements Network {} diff --git a/ext/standard/io_exceptions_arginfo.h b/ext/standard/io_exceptions_arginfo.h index afc77e11761e5..2b8acb4bdbebf 100644 --- a/ext/standard/io_exceptions_arginfo.h +++ b/ext/standard/io_exceptions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 68880a94d8393c0d367cee9e9c18c8ac6d16d9f2 */ + * Stub hash: c4ecc9d6fb58a424dc63d5c5a039843b89273142 */ @@ -19,6 +19,16 @@ static const zend_function_entry class_FileSystemError_methods[] = { }; +static const zend_function_entry class_FileNotFound_methods[] = { + ZEND_FE_END +}; + + +static const zend_function_entry class_NotDirectory_methods[] = { + ZEND_FE_END +}; + + static const zend_function_entry class_InsufficientPermissions_methods[] = { ZEND_FE_END }; diff --git a/ext/standard/tests/dir/chroot_throw_on_error.phpt b/ext/standard/tests/dir/chroot_throw_on_error.phpt new file mode 100644 index 0000000000000..27b8ac373c590 --- /dev/null +++ b/ext/standard/tests/dir/chroot_throw_on_error.phpt @@ -0,0 +1,33 @@ +--TEST-- +Test chroot() function error conditions with throw on error declare enabled - Non-existent directory +--SKIPIF-- + +--FILE-- +getMessage() . \PHP_EOL; +} + +?> +--EXPECTF-- +*** Testing chroot() : error conditions *** + +-- Pass chroot() an absolute path that does not exist -- +File not found: "%sidonotexist" diff --git a/ext/standard/tests/dir/chroot_throw_on_error_file_in_path.phpt b/ext/standard/tests/dir/chroot_throw_on_error_file_in_path.phpt new file mode 100644 index 0000000000000..4dc2f72ec5704 --- /dev/null +++ b/ext/standard/tests/dir/chroot_throw_on_error_file_in_path.phpt @@ -0,0 +1,33 @@ +--TEST-- +Test chroot() function error conditions with throw on error declare enabled - Non-existent directory +--SKIPIF-- + +--FILE-- +getMessage() . \PHP_EOL; +} + +?> +--EXPECTF-- +*** Testing chroot() : error conditions *** + +-- Pass chroot() a non directory -- +"%schroot_throw_on_error_file_in_path.php" is not a directory From 776f58d76f833ae9f7b0387b81df8bf3053f107c Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Thu, 4 Mar 2021 14:07:21 +0000 Subject: [PATCH 6/6] Generate class entries via stubs --- Zend/zend_exceptions.h | 1 + ext/standard/io_exceptions.c | 32 +++-------- ext/standard/io_exceptions.stub.php | 2 +- ext/standard/io_exceptions_arginfo.h | 79 +++++++++++++++++++++++++++- 4 files changed, 87 insertions(+), 27 deletions(-) diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index f61b5ecb304e2..09fd0374ab1c6 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -36,6 +36,7 @@ extern ZEND_API zend_class_entry *zend_ce_value_error; extern ZEND_API zend_class_entry *zend_ce_arithmetic_error; extern ZEND_API zend_class_entry *zend_ce_division_by_zero_error; extern ZEND_API zend_class_entry *zend_ce_unhandled_match_error; +extern ZEND_API zend_class_entry *zend_ce_io; ZEND_API void zend_exception_set_previous(zend_object *exception, zend_object *add_previous); ZEND_API void zend_exception_save(void); diff --git a/ext/standard/io_exceptions.c b/ext/standard/io_exceptions.c index 1a4e5f70e0c53..d34e2093dc84b 100644 --- a/ext/standard/io_exceptions.c +++ b/ext/standard/io_exceptions.c @@ -30,35 +30,17 @@ PHPAPI zend_class_entry *zend_ce_insufficient_permissions; PHPAPI zend_class_entry *zend_ce_temporary_failure; PHP_MINIT_FUNCTION(io_exceptions) { - zend_class_entry ce; - /* Register interfaces */ - INIT_CLASS_ENTRY(ce, "FileSystem", class_FileSystem_methods); - zend_ce_filesystem = zend_register_internal_interface(&ce); - - INIT_CLASS_ENTRY(ce, "Network", class_Network_methods); - zend_ce_network = zend_register_internal_interface(&ce); + zend_ce_filesystem = register_class_FileSystem(zend_ce_io); + zend_ce_network = register_class_Network(zend_ce_io); /* Register exceptions */ - INIT_CLASS_ENTRY(ce, "FileSystemError", class_FileSystemError_methods); - zend_ce_filesystem_error = zend_register_internal_class_ex(&ce, zend_ce_exception); - zend_class_implements(zend_ce_filesystem_error, 1, zend_ce_filesystem); - - INIT_CLASS_ENTRY(ce, "FileNotFound", class_FileNotFound_methods); - zend_ce_file_not_found = zend_register_internal_class_ex(&ce, zend_ce_exception); - zend_class_implements(zend_ce_file_not_found, 1, zend_ce_filesystem); - - INIT_CLASS_ENTRY(ce, "NotDirectory", class_FileNotFound_methods); - zend_ce_not_directory = zend_register_internal_class_ex(&ce, zend_ce_exception); - zend_class_implements(zend_ce_not_directory, 1, zend_ce_filesystem); - - INIT_CLASS_ENTRY(ce, "InsufficientPermissions", class_InsufficientPermissions_methods); - zend_ce_insufficient_permissions = zend_register_internal_class_ex(&ce, zend_ce_exception); - zend_class_implements(zend_ce_insufficient_permissions, 1, zend_ce_filesystem); + zend_ce_filesystem_error = register_class_FileSystemError(zend_ce_exception, zend_ce_filesystem); + zend_ce_file_not_found = register_class_FileNotFound(zend_ce_exception, zend_ce_filesystem); + zend_ce_not_directory = register_class_NotDirectory(zend_ce_exception, zend_ce_filesystem); + zend_ce_insufficient_permissions = register_class_InsufficientPermissions(zend_ce_exception, zend_ce_filesystem); - INIT_CLASS_ENTRY(ce, "TemporaryFailure", class_TemporaryFailure_methods); - zend_ce_temporary_failure = zend_register_internal_class_ex(&ce, zend_ce_exception); - zend_class_implements(zend_ce_temporary_failure, 1, zend_ce_network); + zend_ce_temporary_failure = register_class_TemporaryFailure(zend_ce_exception, zend_ce_network); return SUCCESS; } diff --git a/ext/standard/io_exceptions.stub.php b/ext/standard/io_exceptions.stub.php index 06dae6d317e14..88b3ffb17ba6e 100644 --- a/ext/standard/io_exceptions.stub.php +++ b/ext/standard/io_exceptions.stub.php @@ -1,6 +1,6 @@