From e1c4d6dc9e0b0a93e6b7bbc6cf509d4b90564901 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Fri, 16 Aug 2019 19:16:27 +0200 Subject: [PATCH] PoC for throw_legacy_failure delcare statement --- .../declare_statement_isolated.phpt | 19 +++++++++++++++++ .../fixture/declare_off.inc | 4 ++++ .../fixture/declare_on.inc | 4 ++++ .../fixture/no_declare.inc | 3 +++ Zend/zend_compile.c | 20 ++++++++++++++++++ Zend/zend_globals.h | 1 + ext/standard/array.c | 2 +- ...ay_combine_throw_legacy_failure_error.phpt | 17 +++++++++++++++ main/main.c | 21 +++++++++++++++++++ main/php.h | 3 +++ 10 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/throw_legacy_failure/declare_statement_isolated.phpt create mode 100644 Zend/tests/throw_legacy_failure/fixture/declare_off.inc create mode 100644 Zend/tests/throw_legacy_failure/fixture/declare_on.inc create mode 100644 Zend/tests/throw_legacy_failure/fixture/no_declare.inc create mode 100644 ext/standard/tests/array/array_combine_throw_legacy_failure_error.phpt diff --git a/Zend/tests/throw_legacy_failure/declare_statement_isolated.phpt b/Zend/tests/throw_legacy_failure/declare_statement_isolated.phpt new file mode 100644 index 0000000000000..d2fbff3bce1b3 --- /dev/null +++ b/Zend/tests/throw_legacy_failure/declare_statement_isolated.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test throw_legacy_failure declare statement is isolated to file +--FILE-- + +DONE +--EXPECTF-- +Warning: array_combine(): Both parameters should have an equal number of elements in %sfixture/no_declare.inc on line %d +Error caught + +Warning: array_combine(): Both parameters should have an equal number of elements in %sfixture/declare_off.inc on line %d +DONE diff --git a/Zend/tests/throw_legacy_failure/fixture/declare_off.inc b/Zend/tests/throw_legacy_failure/fixture/declare_off.inc new file mode 100644 index 0000000000000..b5c2d820b4f82 --- /dev/null +++ b/Zend/tests/throw_legacy_failure/fixture/declare_off.inc @@ -0,0 +1,4 @@ +fn_flags |= ZEND_ACC_STRICT_TYPES; } + } else if (zend_string_equals_literal_ci(name, "throw_legacy_failure")) { + zval value_zv; + + if (FAILURE == zend_declare_is_first_statement(ast)) { + zend_error_noreturn(E_COMPILE_ERROR, "throw_legacy_failure declaration must be " + "the very first statement in the script"); + } + + if (ast->child[1] != NULL) { + zend_error_noreturn(E_COMPILE_ERROR, "throw_legacy_failure declaration must not use block mode"); + } + + zend_const_expr_to_zval(&value_zv, value_ast); + + if (Z_TYPE(value_zv) != IS_LONG || (Z_LVAL(value_zv) != 0 && Z_LVAL(value_zv) != 1)) { + zend_error_noreturn(E_COMPILE_ERROR, "throw_legacy_failure declaration must have 0 or 1 as its value"); + } + + CG(throw_legacy_failure) = zval_get_long(&value_zv); + } else { zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", ZSTR_VAL(name)); } diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 9a55924f42817..f590049debee1 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -113,6 +113,7 @@ struct _zend_compiler_globals { zend_bool multibyte; zend_bool detect_unicode; zend_bool encoding_declared; + zend_bool throw_legacy_failure; zend_ast *ast; zend_arena *ast_arena; diff --git a/ext/standard/array.c b/ext/standard/array.c index 70523d479ef4f..78f704b4f0fb4 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -6419,7 +6419,7 @@ PHP_FUNCTION(array_combine) num_values = zend_hash_num_elements(values); if (num_keys != num_values) { - php_error_docref(NULL, E_WARNING, "Both parameters should have an equal number of elements"); + php_exception_or_error_docref(NULL, E_WARNING, "Both parameters should have an equal number of elements"); RETURN_FALSE; } diff --git a/ext/standard/tests/array/array_combine_throw_legacy_failure_error.phpt b/ext/standard/tests/array/array_combine_throw_legacy_failure_error.phpt new file mode 100644 index 0000000000000..5cd91fd6fa1e5 --- /dev/null +++ b/ext/standard/tests/array/array_combine_throw_legacy_failure_error.phpt @@ -0,0 +1,17 @@ +--TEST-- +Test array_combine() function : error conditions - with throw_legacy_failure declare statement +--FILE-- + +DONE +--EXPECTF-- +Error caught +DONE diff --git a/main/main.c b/main/main.c index df73f00bebb39..fbefcd8297ee3 100644 --- a/main/main.c +++ b/main/main.c @@ -1170,6 +1170,27 @@ PHPAPI ZEND_COLD void php_error_docref2(const char *docref, const char *param1, } /* }}} */ +/* {{{ php_exception_or_error_docref */ +/* Throw an Exception if throw_legacy_failure declare statement is present otherwise fallback to a traditional + * docref error. */ +PHPAPI ZEND_COLD void php_exception_or_error_docref(const char *docref, int type, const char *format, ...) +{ + va_list args; + + va_start(args, format); + if (CG(throw_legacy_failure) == 1) { + char *message = NULL; + + zend_vspprintf(&message, 0, format, args); + zend_throw_exception(zend_ce_error_exception, message, E_ERROR); + efree(message); + } else { + php_verror(docref, "", type, format, args); + } + va_end(args); +} +/* }}} */ + #ifdef PHP_WIN32 PHPAPI ZEND_COLD void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2) { char *buf = php_win32_error_to_msg(error); diff --git a/main/php.h b/main/php.h index c74f76f2ab943..798c4f6ceca05 100644 --- a/main/php.h +++ b/main/php.h @@ -345,6 +345,9 @@ PHPAPI ZEND_COLD void php_error_docref1(const char *docref, const char *param1, PHP_ATTRIBUTE_FORMAT(printf, 4, 5); PHPAPI ZEND_COLD void php_error_docref2(const char *docref, const char *param1, const char *param2, int type, const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 5, 6); +PHPAPI ZEND_COLD void php_exception_or_error_docref(const char *docref, int type, const char *format, ...) + PHP_ATTRIBUTE_FORMAT(printf, 3, 4); + #ifdef PHP_WIN32 PHPAPI ZEND_COLD void php_win32_docref2_from_error(DWORD error, const char *param1, const char *param2); #endif