Skip to content

Call error handler for E_COMPILE_WARNING #4758

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
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
31 changes: 31 additions & 0 deletions Zend/tests/compile_warning_error_handler.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
Error handler is invoked for E_COMPILE_WARNING
--FILE--
<?php

set_error_handler(function($errno, $errstr) {
echo $errstr, "\n";
});

eval("\1 echo 'Foo\n'; \1;");

set_error_handler(function($errno, $errstr) {
throw new Exception($errstr);
});

try {
eval("\1 echo 'Foo'; \1;");
} catch (Exception $e) {
echo $e, "\n";
}

?>
--EXPECTF--
Unexpected character in input: '%s' (ASCII=1) state=0
Unexpected character in input: '%s' (ASCII=1) state=0
Foo
Exception: Unexpected character in input: '%s' (ASCII=1) state=0 in %s:%d
Stack trace:
#0 %s(%d): {closure}(%s)
#1 %s(%d): eval()
#2 {main}
1 change: 0 additions & 1 deletion Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -1312,7 +1312,6 @@ static ZEND_COLD void zend_error_va_list(
case E_CORE_ERROR:
case E_CORE_WARNING:
case E_COMPILE_ERROR:
case E_COMPILE_WARNING:
/* The error may not be safe to handle in user-space */
zend_error_cb(type, error_filename, error_lineno, format, args);
break;
Expand Down
33 changes: 19 additions & 14 deletions Zend/zend_language_scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ ZEND_API void zend_multibyte_yyinput_again(zend_encoding_filter old_input_filter
ZVAL_STRINGL(zendlval, yytext, yyleng); \
}

static int zend_scan_escape_string(zval *zendlval, char *str, int len, char quote_type)
static int zend_scan_escape_string(zval *zendlval, char *str, int len, char quote_type, zend_bool throw)
{
register char *s, *t;
char *end;
Expand Down Expand Up @@ -1018,8 +1018,10 @@ static int zend_scan_escape_string(zval *zendlval, char *str, int len, char quot
}

if (!valid) {
zend_throw_exception(zend_ce_parse_error,
"Invalid UTF-8 codepoint escape sequence", 0);
if (throw) {
zend_throw_exception(zend_ce_parse_error,
"Invalid UTF-8 codepoint escape sequence", 0);
}
zval_ptr_dtor(zendlval);
ZVAL_UNDEF(zendlval);
return FAILURE;
Expand All @@ -1030,8 +1032,10 @@ static int zend_scan_escape_string(zval *zendlval, char *str, int len, char quot

/* per RFC 3629, UTF-8 can only represent 21 bits */
if (codepoint > 0x10FFFF || errno) {
zend_throw_exception(zend_ce_parse_error,
"Invalid UTF-8 codepoint escape sequence: Codepoint too large", 0);
if (throw) {
zend_throw_exception(zend_ce_parse_error,
"Invalid UTF-8 codepoint escape sequence: Codepoint too large", 0);
}
zval_ptr_dtor(zendlval);
ZVAL_UNDEF(zendlval);
return FAILURE;
Expand Down Expand Up @@ -1822,9 +1826,9 @@ NEWLINE ("\r"|"\n"|"\r\n")
size_t i;
for (i = 0; i < len; i++) {
if (lnum[i] == '8' || lnum[i] == '9') {
zend_throw_exception(zend_ce_parse_error, "Invalid numeric literal", 0);
ZVAL_UNDEF(zendlval);
if (PARSER_MODE()) {
zend_throw_exception(zend_ce_parse_error, "Invalid numeric literal", 0);
RETURN_TOKEN(T_ERROR);
}
RETURN_TOKEN_WITH_VAL(T_LNUMBER);
Expand Down Expand Up @@ -2310,7 +2314,7 @@ skip_escape_conversion:
switch (*YYCURSOR++) {
case '"':
yyleng = YYCURSOR - SCNG(yy_text);
if (EXPECTED(zend_scan_escape_string(zendlval, yytext+bprefix+1, yyleng-bprefix-2, '"') == SUCCESS)
if (EXPECTED(zend_scan_escape_string(zendlval, yytext+bprefix+1, yyleng-bprefix-2, '"', PARSER_MODE()) == SUCCESS)
|| !PARSER_MODE()) {
RETURN_TOKEN_WITH_VAL(T_CONSTANT_ENCAPSED_STRING);
} else {
Expand Down Expand Up @@ -2403,7 +2407,7 @@ skip_escape_conversion:
/* Check for ending label on the next line */
if (heredoc_label->length < YYLIMIT - YYCURSOR && !memcmp(YYCURSOR, s, heredoc_label->length)) {
if (!IS_LABEL_SUCCESSOR(YYCURSOR[heredoc_label->length])) {
if (spacing == (HEREDOC_USING_SPACES | HEREDOC_USING_TABS)) {
if (spacing == (HEREDOC_USING_SPACES | HEREDOC_USING_TABS) && PARSER_MODE()) {
zend_throw_exception(zend_ce_parse_error, "Invalid indentation - tabs and spaces cannot be mixed", 0);
}

Expand Down Expand Up @@ -2431,6 +2435,7 @@ skip_escape_conversion:

zend_ptr_stack_reverse_apply(&current_state.heredoc_label_stack, copy_heredoc_label_stack);

// TODO: Exception logic should no longer be needed!
zend_exception_save();
while (heredoc_nesting_level) {
zval zv;
Expand Down Expand Up @@ -2466,7 +2471,7 @@ skip_escape_conversion:
(first_token == T_VARIABLE
|| first_token == T_DOLLAR_OPEN_CURLY_BRACES
|| first_token == T_CURLY_OPEN
) && SCNG(heredoc_indentation)) {
) && SCNG(heredoc_indentation) && PARSER_MODE()) {
zend_throw_exception_ex(zend_ce_parse_error, 0, "Invalid body indentation level (expecting an indentation level of at least %d)", SCNG(heredoc_indentation));
}

Expand Down Expand Up @@ -2565,7 +2570,7 @@ skip_escape_conversion:
double_quotes_scan_done:
yyleng = YYCURSOR - SCNG(yy_text);

if (EXPECTED(zend_scan_escape_string(zendlval, yytext, yyleng, '"') == SUCCESS)
if (EXPECTED(zend_scan_escape_string(zendlval, yytext, yyleng, '"', PARSER_MODE()) == SUCCESS)
|| !PARSER_MODE()) {
RETURN_TOKEN_WITH_VAL(T_ENCAPSED_AND_WHITESPACE);
} else {
Expand Down Expand Up @@ -2611,7 +2616,7 @@ double_quotes_scan_done:

yyleng = YYCURSOR - SCNG(yy_text);

if (EXPECTED(zend_scan_escape_string(zendlval, yytext, yyleng, '`') == SUCCESS)
if (EXPECTED(zend_scan_escape_string(zendlval, yytext, yyleng, '`', PARSER_MODE()) == SUCCESS)
|| !PARSER_MODE()) {
RETURN_TOKEN_WITH_VAL(T_ENCAPSED_AND_WHITESPACE);
} else {
Expand Down Expand Up @@ -2663,7 +2668,7 @@ double_quotes_scan_done:
continue;
}

if (spacing == (HEREDOC_USING_SPACES | HEREDOC_USING_TABS)) {
if (spacing == (HEREDOC_USING_SPACES | HEREDOC_USING_TABS) && PARSER_MODE()) {
zend_throw_exception(zend_ce_parse_error, "Invalid indentation - tabs and spaces cannot be mixed", 0);
}

Expand Down Expand Up @@ -2727,7 +2732,7 @@ heredoc_scan_done:
RETURN_TOKEN(T_ERROR);
}

if (UNEXPECTED(zend_scan_escape_string(zendlval, ZSTR_VAL(copy), ZSTR_LEN(copy), 0) != SUCCESS)) {
if (UNEXPECTED(zend_scan_escape_string(zendlval, ZSTR_VAL(copy), ZSTR_LEN(copy), 0, PARSER_MODE()) != SUCCESS)) {
zend_string_efree(copy);
RETURN_TOKEN(T_ERROR);
}
Expand Down Expand Up @@ -2784,7 +2789,7 @@ heredoc_scan_done:
continue;
}

if (spacing == (HEREDOC_USING_SPACES | HEREDOC_USING_TABS)) {
if (spacing == (HEREDOC_USING_SPACES | HEREDOC_USING_TABS) && PARSER_MODE()) {
zend_throw_exception(zend_ce_parse_error, "Invalid indentation - tabs and spaces cannot be mixed", 0);
}

Expand Down
32 changes: 32 additions & 0 deletions ext/tokenizer/tests/compile_warning_error_handler.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
Error handler is invoked for E_COMPILE_WARNING
--FILE--
<?php

set_error_handler(function($errno, $errstr) {
echo $errstr, "\n";
});

var_dump(count(token_get_all("<?php \1 echo 'Foo\n'; \1;")));

set_error_handler(function($errno, $errstr) {
throw new Exception($errstr);
});

// The exceptions get eaten
try {
var_dump(count(token_get_all("<?php \1 echo 'Foo'; \1;")));
} catch (Exception $e) {
echo $e, "\n";
}

?>
--EXPECTF--
Unexpected character in input: '%s' (ASCII=1) state=0
Unexpected character in input: '%s' (ASCII=1) state=0
int(10)
Exception: Unexpected character in input: '%s' (ASCII=1) state=0 in %s:%d
Stack trace:
#0 [internal function]: {closure}(%s)
#1 %s(%d): token_get_all(%s)
#2 {main}
2 changes: 0 additions & 2 deletions ext/tokenizer/tokenizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,6 @@ PHP_FUNCTION(token_get_all)
success = tokenize_parse(return_value, source);
} else {
success = tokenize(return_value, source);
/* Normal token_get_all() should not throw. */
zend_clear_exception();
}

if (!success) RETURN_FALSE;
Expand Down