From 832ca573b38d0c5ebb0bdb1a785699c29323748b Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 21 Aug 2019 12:11:17 +0200 Subject: [PATCH 1/8] Fix #77812: Interactive mode does not support PHP 7.3-style heredoc As of PHP 7.3.0, the rules regarding the heredoc and nowdoc closing identifier have been relaxed. While formerly, the closing identifier was required to be placed at the beginning of a line and to be immediately followed by a semicolon and a line break, it may now be preceeded by whitespace, and may be followed by any non-word character. We adjust the recognition logic respectively. --- ext/readline/readline_cli.c | 9 +++-- ext/readline/tests/bug77812-libedit.phpt | 30 ++++++++++++++++ ext/readline/tests/bug77812-readline.phpt | 42 +++++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 ext/readline/tests/bug77812-libedit.phpt create mode 100644 ext/readline/tests/bug77812-readline.phpt diff --git a/ext/readline/readline_cli.c b/ext/readline/readline_cli.c index 69ebe117cb161..c7e9c02b51bae 100644 --- a/ext/readline/readline_cli.c +++ b/ext/readline/readline_cli.c @@ -349,9 +349,14 @@ static int cli_is_valid_code(char *code, size_t len, zend_string **prompt) /* {{ case heredoc: if (code[i - (heredoc_len + 1)] == '\n' && !strncmp(code + i - heredoc_len, heredoc_tag, heredoc_len) && code[i] == '\n') { code_type = body; - } else if (code[i - (heredoc_len + 2)] == '\n' && !strncmp(code + i - heredoc_len - 1, heredoc_tag, heredoc_len) && code[i-1] == ';' && code[i] == '\n') { + } else if (!strncmp(code + i - heredoc_len + 1, heredoc_tag, heredoc_len)) { + char c = code[i + 1]; + char *p = code + i - heredoc_len; + + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_') break; + while (*p == ' ' && *p != '\n') p--; + if (*p != '\n') break; code_type = body; - valid_end = 1; } break; case outside: diff --git a/ext/readline/tests/bug77812-libedit.phpt b/ext/readline/tests/bug77812-libedit.phpt new file mode 100644 index 0000000000000..e4d73cdbf849f --- /dev/null +++ b/ext/readline/tests/bug77812-libedit.phpt @@ -0,0 +1,30 @@ +--TEST-- +Bug #77812 (Interactive mode does not support PHP 7.3-style heredoc) +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +resource(%d) of type (process) +Interactive shell + +bar +xx +xxx + +Warning: Use of undefined constant FOO - assumed 'FOO' (this will throw an Error in a future version of PHP) in php shell code on line %d diff --git a/ext/readline/tests/bug77812-readline.phpt b/ext/readline/tests/bug77812-readline.phpt new file mode 100644 index 0000000000000..0e789ad2893cc --- /dev/null +++ b/ext/readline/tests/bug77812-readline.phpt @@ -0,0 +1,42 @@ +--TEST-- +Bug #77812 (Interactive mode does not support PHP 7.3-style heredoc) +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +resource(%d) of type (process) +Interactive shell + +php > echo << bar +<<< > FOO; +bar +php > print(<< xx +<<< > FOO); +xx +php > echo << xxx +<<< > FOO; +xxx +php > FOO +php > ; + +Warning: Use of undefined constant FOO - assumed 'FOO' (this will throw an Error in a future version of PHP) in php shell code on line %d +php > From d0b0070799fec7631cc0de1022a1b0a99f89338c Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 21 Aug 2019 13:39:15 +0200 Subject: [PATCH 2/8] Fix skip clause --- ext/readline/tests/bug77812-libedit.phpt | 4 ++-- ext/readline/tests/bug77812-readline.phpt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/readline/tests/bug77812-libedit.phpt b/ext/readline/tests/bug77812-libedit.phpt index e4d73cdbf849f..dbb01e562f06b 100644 --- a/ext/readline/tests/bug77812-libedit.phpt +++ b/ext/readline/tests/bug77812-libedit.phpt @@ -3,8 +3,8 @@ Bug #77812 (Interactive mode does not support PHP 7.3-style heredoc) --SKIPIF-- --FILE-- --FILE-- Date: Wed, 21 Aug 2019 16:01:53 +0200 Subject: [PATCH 3/8] Remove superfluous if-then This case is already handled by the more general following elseif-then, so we can drop it. --- ext/readline/readline_cli.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ext/readline/readline_cli.c b/ext/readline/readline_cli.c index c7e9c02b51bae..4bced16636a1d 100644 --- a/ext/readline/readline_cli.c +++ b/ext/readline/readline_cli.c @@ -347,9 +347,7 @@ static int cli_is_valid_code(char *code, size_t len, zend_string **prompt) /* {{ } break; case heredoc: - if (code[i - (heredoc_len + 1)] == '\n' && !strncmp(code + i - heredoc_len, heredoc_tag, heredoc_len) && code[i] == '\n') { - code_type = body; - } else if (!strncmp(code + i - heredoc_len + 1, heredoc_tag, heredoc_len)) { + if (!strncmp(code + i - heredoc_len + 1, heredoc_tag, heredoc_len)) { char c = code[i + 1]; char *p = code + i - heredoc_len; From 1dd0e946b358b4534ac704494e444e060a6371c8 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 21 Aug 2019 16:04:04 +0200 Subject: [PATCH 4/8] Extend test case --- ext/readline/tests/bug77812-libedit.phpt | 2 ++ ext/readline/tests/bug77812-readline.phpt | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/ext/readline/tests/bug77812-libedit.phpt b/ext/readline/tests/bug77812-libedit.phpt index dbb01e562f06b..5168c41ad19a3 100644 --- a/ext/readline/tests/bug77812-libedit.phpt +++ b/ext/readline/tests/bug77812-libedit.phpt @@ -16,6 +16,7 @@ var_dump($proc); fwrite($pipes[0], "echo << @@ -28,3 +29,4 @@ xx xxx Warning: Use of undefined constant FOO - assumed 'FOO' (this will throw an Error in a future version of PHP) in php shell code on line %d +FOOL1 diff --git a/ext/readline/tests/bug77812-readline.phpt b/ext/readline/tests/bug77812-readline.phpt index 71f21b80ae5fb..c12454f643d14 100644 --- a/ext/readline/tests/bug77812-readline.phpt +++ b/ext/readline/tests/bug77812-readline.phpt @@ -16,6 +16,7 @@ var_dump($proc); fwrite($pipes[0], "echo << @@ -39,4 +40,9 @@ php > FOO php > ; Warning: Use of undefined constant FOO - assumed 'FOO' (this will throw an Error in a future version of PHP) in php shell code on line %d +php > echo << FOOL +<<< > FOO +php > ,1; +FOOL1 php > From 63512c3437dec5558680aca74e172493cc01b79a Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 22 Aug 2019 09:43:47 +0200 Subject: [PATCH 5/8] Added test with trailing digit --- ext/readline/tests/bug77812-libedit.phpt | 2 ++ ext/readline/tests/bug77812-readline.phpt | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/ext/readline/tests/bug77812-libedit.phpt b/ext/readline/tests/bug77812-libedit.phpt index 5168c41ad19a3..478274a19a46f 100644 --- a/ext/readline/tests/bug77812-libedit.phpt +++ b/ext/readline/tests/bug77812-libedit.phpt @@ -17,6 +17,7 @@ fwrite($pipes[0], "echo << @@ -30,3 +31,4 @@ xxx Warning: Use of undefined constant FOO - assumed 'FOO' (this will throw an Error in a future version of PHP) in php shell code on line %d FOOL1 +FOO42 diff --git a/ext/readline/tests/bug77812-readline.phpt b/ext/readline/tests/bug77812-readline.phpt index c12454f643d14..32d9f4d96045c 100644 --- a/ext/readline/tests/bug77812-readline.phpt +++ b/ext/readline/tests/bug77812-readline.phpt @@ -17,6 +17,7 @@ fwrite($pipes[0], "echo << @@ -45,4 +46,9 @@ php > echo << FOO php > ,1; FOOL1 +php > echo << FOO4 +<<< > FOO +php > ,2; +FOO42 php > From 4067e4039cf4543fa1786ae9cee8bf19fe1818de Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 22 Aug 2019 09:51:15 +0200 Subject: [PATCH 6/8] Extended ASCII chars can be contained in identifiers --- ext/readline/readline_cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/readline/readline_cli.c b/ext/readline/readline_cli.c index 4bced16636a1d..badca384c2354 100644 --- a/ext/readline/readline_cli.c +++ b/ext/readline/readline_cli.c @@ -351,7 +351,7 @@ static int cli_is_valid_code(char *code, size_t len, zend_string **prompt) /* {{ char c = code[i + 1]; char *p = code + i - heredoc_len; - if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_') break; + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c >= 0x80) break; while (*p == ' ' && *p != '\n') p--; if (*p != '\n') break; code_type = body; From f0455e4f2068ae55034992e457055f5f0b5953eb Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 23 Aug 2019 10:45:13 +0200 Subject: [PATCH 7/8] Use `unsigned char` to ensure `>= 0x80` works --- ext/readline/readline_cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/readline/readline_cli.c b/ext/readline/readline_cli.c index badca384c2354..9934afacbb4be 100644 --- a/ext/readline/readline_cli.c +++ b/ext/readline/readline_cli.c @@ -348,7 +348,7 @@ static int cli_is_valid_code(char *code, size_t len, zend_string **prompt) /* {{ break; case heredoc: if (!strncmp(code + i - heredoc_len + 1, heredoc_tag, heredoc_len)) { - char c = code[i + 1]; + unsigned char c = code[i + 1]; char *p = code + i - heredoc_len; if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c >= 0x80) break; From de0779131b331fefa60b665afd04aba6e41a8960 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 23 Aug 2019 13:12:24 +0200 Subject: [PATCH 8/8] Also accept leading tabs; remove superfluous condition --- ext/readline/readline_cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/readline/readline_cli.c b/ext/readline/readline_cli.c index 9934afacbb4be..6e6e9161be452 100644 --- a/ext/readline/readline_cli.c +++ b/ext/readline/readline_cli.c @@ -352,7 +352,7 @@ static int cli_is_valid_code(char *code, size_t len, zend_string **prompt) /* {{ char *p = code + i - heredoc_len; if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c >= 0x80) break; - while (*p == ' ' && *p != '\n') p--; + while (*p == ' ' || *p == '\t') p--; if (*p != '\n') break; code_type = body; }