From 8b3ab22de35421d52563740513d3cfb38b8244a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 15 Sep 2023 18:34:52 -0300 Subject: [PATCH 1/5] Fix implicit conversion from float to int in AlterOperation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- phpstan-baseline.neon | 5 -- psalm-baseline.xml | 6 +- src/Components/AlterOperation.php | 6 +- tests/Misc/BugsTest.php | 1 + tests/data/bugs/fuzz1.in | 1 + tests/data/bugs/fuzz1.out | 114 ++++++++++++++++++++++++++++++ 6 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 tests/data/bugs/fuzz1.in create mode 100644 tests/data/bugs/fuzz1.out diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 7de4c647c..0d1a703fe 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -15,11 +15,6 @@ parameters: count: 1 path: src/Components/AlterOperation.php - - - message: "#^Parameter \\#1 \\$key of function array_key_exists expects int\\|string, float\\|int\\|string given\\.$#" - count: 2 - path: src/Components/AlterOperation.php - - message: "#^Property PhpMyAdmin\\\\SqlParser\\\\Components\\\\AlterOperation\\:\\:\\$options \\(PhpMyAdmin\\\\SqlParser\\\\Components\\\\OptionsArray\\) does not accept PhpMyAdmin\\\\SqlParser\\\\Components\\\\OptionsArray\\|null\\.$#" count: 1 diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 597b0a774..36235b1e2 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -12,9 +12,6 @@ $arrayKey - - Parser::$STATEMENT_PARSERS[$token->value] - $component @@ -631,8 +628,7 @@ $this->last $this->last - - $this->str[$this->last + 1] + $this->str[$this->last + 1] $this->str[$this->last++] $this->str[$this->last] diff --git a/src/Components/AlterOperation.php b/src/Components/AlterOperation.php index b28e451b4..271cdaf70 100644 --- a/src/Components/AlterOperation.php +++ b/src/Components/AlterOperation.php @@ -11,7 +11,7 @@ use function array_key_exists; use function in_array; -use function is_numeric; +use function is_int; use function is_string; use function trim; @@ -412,7 +412,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = $state = 2; } elseif ($state === 2) { - if (is_string($token->value) || is_numeric($token->value)) { + if (is_string($token->value) || is_int($token->value)) { $arrayKey = $token->value; } else { $arrayKey = $token->token; @@ -445,7 +445,7 @@ public static function parse(Parser $parser, TokensList $list, array $options = ); break; } - } elseif (! empty(Parser::$STATEMENT_PARSERS[$token->value])) { + } elseif (! empty(Parser::$STATEMENT_PARSERS[$arrayKey])) { // We have reached the end of ALTER operation and suddenly found // a start to new statement, but have not found a delimiter between them $parser->error( diff --git a/tests/Misc/BugsTest.php b/tests/Misc/BugsTest.php index f012caccb..3fa44a524 100644 --- a/tests/Misc/BugsTest.php +++ b/tests/Misc/BugsTest.php @@ -22,6 +22,7 @@ public function testBug(string $test): void public function bugProvider(): array { return [ + ['bugs/fuzz1'], ['bugs/gh9'], ['bugs/gh14'], ['bugs/gh16'], diff --git a/tests/data/bugs/fuzz1.in b/tests/data/bugs/fuzz1.in new file mode 100644 index 000000000..406cde8e3 --- /dev/null +++ b/tests/data/bugs/fuzz1.in @@ -0,0 +1 @@ +ALTER..2 \ No newline at end of file diff --git a/tests/data/bugs/fuzz1.out b/tests/data/bugs/fuzz1.out new file mode 100644 index 000000000..4ebecfc0a --- /dev/null +++ b/tests/data/bugs/fuzz1.out @@ -0,0 +1,114 @@ +{ + "query": "ALTER..2", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "ALTER..2", + "len": 8, + "last": 8, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "ALTER", + "value": "ALTER", + "keyword": "ALTER", + "type": 1, + "flags": 3, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ".", + "value": ".", + "keyword": null, + "type": 2, + "flags": 16, + "position": 5 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ".2", + "value": 0.2, + "keyword": null, + "type": 6, + "flags": 2, + "position": 6 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 4, + "idx": 4 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\AlterStatement", + "table": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", + "database": null, + "table": null, + "column": null, + "expr": ".", + "alias": null, + "function": null, + "subquery": null + }, + "altered": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Components\\AlterOperation", + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": [] + }, + "field": null, + "partitions": null, + "unknown": [ + { + "@type": "@4" + } + ] + } + ], + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": [] + }, + "first": 0, + "last": 3 + } + ], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [ + [ + "Unrecognized alter operation.", + { + "@type": "@5" + }, + 0 + ] + ] + } +} \ No newline at end of file From fb8fe989e578b231c729ab6e3f64de3ab4cf6f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 15 Sep 2023 20:52:34 -0300 Subject: [PATCH 2/5] Fix undefined array key in WithStatement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CTE name must be a valid identifier. Signed-off-by: Maurício Meneghini Fauth --- src/Statements/WithStatement.php | 3 +- tests/Misc/BugsTest.php | 1 + tests/data/bugs/fuzz2.in | 1 + tests/data/bugs/fuzz2.out | 111 +++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 tests/data/bugs/fuzz2.in create mode 100644 tests/data/bugs/fuzz2.out diff --git a/src/Statements/WithStatement.php b/src/Statements/WithStatement.php index eb207496f..cd22ff55c 100644 --- a/src/Statements/WithStatement.php +++ b/src/Statements/WithStatement.php @@ -16,6 +16,7 @@ use function array_slice; use function count; +use function preg_match; /** * `WITH` statement. @@ -114,7 +115,7 @@ public function parse(Parser $parser, TokensList $list) } if ($state === 0) { - if ($token->type !== Token::TYPE_NONE) { + if ($token->type !== Token::TYPE_NONE || ! preg_match('/^[a-zA-Z0-9_$]+$/', $token->token)) { $parser->error('The name of the CTE was expected.', $token); break; } diff --git a/tests/Misc/BugsTest.php b/tests/Misc/BugsTest.php index 3fa44a524..cf9571d87 100644 --- a/tests/Misc/BugsTest.php +++ b/tests/Misc/BugsTest.php @@ -23,6 +23,7 @@ public function bugProvider(): array { return [ ['bugs/fuzz1'], + ['bugs/fuzz2'], ['bugs/gh9'], ['bugs/gh14'], ['bugs/gh16'], diff --git a/tests/data/bugs/fuzz2.in b/tests/data/bugs/fuzz2.in new file mode 100644 index 000000000..bda1ec626 --- /dev/null +++ b/tests/data/bugs/fuzz2.in @@ -0,0 +1 @@ +WITH]( \ No newline at end of file diff --git a/tests/data/bugs/fuzz2.out b/tests/data/bugs/fuzz2.out new file mode 100644 index 000000000..335ea320f --- /dev/null +++ b/tests/data/bugs/fuzz2.out @@ -0,0 +1,111 @@ +{ + "query": "WITH](", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "WITH](", + "len": 6, + "last": 6, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "WITH", + "value": "WITH", + "keyword": "WITH", + "type": 1, + "flags": 3, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "]", + "value": "]", + "keyword": null, + "type": 0, + "flags": 0, + "position": 4 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "(", + "value": "(", + "keyword": null, + "type": 2, + "flags": 16, + "position": 5 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 4, + "idx": 4 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\WithStatement", + "withers": [], + "cteStatementParser": null, + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": [] + }, + "first": 0, + "last": 0 + } + ], + "brackets": 1, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [ + [ + "Unexpected character.", + "]", + 4, + 0 + ] + ], + "parser": [ + [ + "The name of the CTE was expected.", + { + "@type": "@3" + }, + 0 + ], + [ + "Unexpected end of the WITH CTE.", + { + "@type": "@3" + }, + 0 + ], + [ + "Unexpected beginning of statement.", + { + "@type": "@3" + }, + 0 + ] + ] + } +} \ No newline at end of file From b91a3a92b5f24f7ca3e0541e7ca3509321804077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 15 Sep 2023 21:31:47 -0300 Subject: [PATCH 3/5] Fix undefined array key in WithStatement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check if CTE column brackets was closed. Signed-off-by: Maurício Meneghini Fauth --- src/Components/ArrayObj.php | 4 + src/Statements/WithStatement.php | 7 +- tests/Misc/BugsTest.php | 1 + tests/data/bugs/fuzz3.in | 1 + tests/data/bugs/fuzz3.out | 113 +++++++++++++++++++++++++++ tests/data/parser/parseArrayErr3.out | 10 ++- 6 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 tests/data/bugs/fuzz3.in create mode 100644 tests/data/bugs/fuzz3.out diff --git a/src/Components/ArrayObj.php b/src/Components/ArrayObj.php index eab1b0659..1397eb243 100644 --- a/src/Components/ArrayObj.php +++ b/src/Components/ArrayObj.php @@ -92,6 +92,10 @@ public static function parse(Parser $parser, TokensList $list, array $options = // End of statement. if ($token->type === Token::TYPE_DELIMITER) { + if ($brackets > 0) { + $parser->error('A closing bracket was expected.', $token); + } + break; } diff --git a/src/Statements/WithStatement.php b/src/Statements/WithStatement.php index cd22ff55c..58c1d1dbc 100644 --- a/src/Statements/WithStatement.php +++ b/src/Statements/WithStatement.php @@ -125,7 +125,12 @@ public function parse(Parser $parser, TokensList $list) $state = 1; } elseif ($state === 1) { if ($token->type === Token::TYPE_OPERATOR && $token->value === '(') { - $this->withers[$wither]->columns = Array2d::parse($parser, $list); + $columns = Array2d::parse($parser, $list); + if ($parser->errors !== []) { + break; + } + + $this->withers[$wither]->columns = $columns; $state = 2; } elseif ($token->type === Token::TYPE_KEYWORD && $token->keyword === 'AS') { $state = 3; diff --git a/tests/Misc/BugsTest.php b/tests/Misc/BugsTest.php index cf9571d87..b9ec4282a 100644 --- a/tests/Misc/BugsTest.php +++ b/tests/Misc/BugsTest.php @@ -24,6 +24,7 @@ public function bugProvider(): array return [ ['bugs/fuzz1'], ['bugs/fuzz2'], + ['bugs/fuzz3'], ['bugs/gh9'], ['bugs/gh14'], ['bugs/gh16'], diff --git a/tests/data/bugs/fuzz3.in b/tests/data/bugs/fuzz3.in new file mode 100644 index 000000000..48d31fa9b --- /dev/null +++ b/tests/data/bugs/fuzz3.in @@ -0,0 +1 @@ +WITH*/A( \ No newline at end of file diff --git a/tests/data/bugs/fuzz3.out b/tests/data/bugs/fuzz3.out new file mode 100644 index 000000000..6b9ee9903 --- /dev/null +++ b/tests/data/bugs/fuzz3.out @@ -0,0 +1,113 @@ +{ + "query": "WITH*/A(", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "WITH*/A(", + "len": 8, + "last": 8, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "WITH", + "value": "WITH", + "keyword": "WITH", + "type": 1, + "flags": 3, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "*/", + "value": "*/", + "keyword": null, + "type": 4, + "flags": 2, + "position": 4 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "A", + "value": "A", + "keyword": null, + "type": 0, + "flags": 0, + "position": 6 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "(", + "value": "(", + "keyword": null, + "type": 2, + "flags": 16, + "position": 7 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 5, + "idx": 5 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\WithStatement", + "withers": { + "A": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\WithKeyword", + "name": "A", + "columns": [], + "statement": null + } + }, + "cteStatementParser": null, + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": [] + }, + "first": 0, + "last": 3 + } + ], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [ + [ + "A closing bracket was expected.", + { + "@type": "@6" + }, + 0 + ], + [ + "Unexpected end of the WITH CTE.", + { + "@type": "@6" + }, + 0 + ] + ] + } +} \ No newline at end of file diff --git a/tests/data/parser/parseArrayErr3.out b/tests/data/parser/parseArrayErr3.out index 4b86033d0..81a1c2928 100644 --- a/tests/data/parser/parseArrayErr3.out +++ b/tests/data/parser/parseArrayErr3.out @@ -239,6 +239,14 @@ }, "errors": { "lexer": [], - "parser": [] + "parser": [ + [ + "A closing bracket was expected.", + { + "@type": "@17" + }, + 0 + ] + ] } } \ No newline at end of file From 3a02adeb0de60c0e7d60b5605eccb255dcc072dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Fri, 15 Sep 2023 22:38:10 -0300 Subject: [PATCH 4/5] Fix undefined array key AlterOperation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- src/Statements/AlterStatement.php | 9 ++- tests/Misc/BugsTest.php | 1 + tests/data/bugs/fuzz1.out | 44 ++++---------- tests/data/bugs/fuzz4.in | 1 + tests/data/bugs/fuzz4.out | 98 +++++++++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 33 deletions(-) create mode 100644 tests/data/bugs/fuzz4.in create mode 100644 tests/data/bugs/fuzz4.out diff --git a/src/Statements/AlterStatement.php b/src/Statements/AlterStatement.php index de3123c43..3cd902d78 100644 --- a/src/Statements/AlterStatement.php +++ b/src/Statements/AlterStatement.php @@ -67,7 +67,14 @@ class AlterStatement extends Statement public function parse(Parser $parser, TokensList $list) { ++$list->idx; // Skipping `ALTER`. - $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS); + $parsedOptions = OptionsArray::parse($parser, $list, static::$OPTIONS); + if ($parsedOptions->isEmpty()) { + $parser->error('Unrecognized alter operation.', $list->tokens[$list->idx]); + + return; + } + + $this->options = $parsedOptions; ++$list->idx; // Parsing affected table. diff --git a/tests/Misc/BugsTest.php b/tests/Misc/BugsTest.php index b9ec4282a..2faa7e13d 100644 --- a/tests/Misc/BugsTest.php +++ b/tests/Misc/BugsTest.php @@ -25,6 +25,7 @@ public function bugProvider(): array ['bugs/fuzz1'], ['bugs/fuzz2'], ['bugs/fuzz3'], + ['bugs/fuzz4'], ['bugs/gh9'], ['bugs/gh14'], ['bugs/gh16'], diff --git a/tests/data/bugs/fuzz1.out b/tests/data/bugs/fuzz1.out index 4ebecfc0a..c7a03aba8 100644 --- a/tests/data/bugs/fuzz1.out +++ b/tests/data/bugs/fuzz1.out @@ -61,38 +61,11 @@ "statements": [ { "@type": "PhpMyAdmin\\SqlParser\\Statements\\AlterStatement", - "table": { - "@type": "PhpMyAdmin\\SqlParser\\Components\\Expression", - "database": null, - "table": null, - "column": null, - "expr": ".", - "alias": null, - "function": null, - "subquery": null - }, - "altered": [ - { - "@type": "PhpMyAdmin\\SqlParser\\Components\\AlterOperation", - "options": { - "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", - "options": [] - }, - "field": null, - "partitions": null, - "unknown": [ - { - "@type": "@4" - } - ] - } - ], - "options": { - "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", - "options": [] - }, + "table": null, + "altered": [], + "options": null, "first": 0, - "last": 3 + "last": 0 } ], "brackets": 0, @@ -105,7 +78,14 @@ [ "Unrecognized alter operation.", { - "@type": "@5" + "@type": "@2" + }, + 0 + ], + [ + "Unexpected beginning of statement.", + { + "@type": "@4" }, 0 ] diff --git a/tests/data/bugs/fuzz4.in b/tests/data/bugs/fuzz4.in new file mode 100644 index 000000000..c688c143f --- /dev/null +++ b/tests/data/bugs/fuzz4.in @@ -0,0 +1 @@ +ALTeR=SET \ No newline at end of file diff --git a/tests/data/bugs/fuzz4.out b/tests/data/bugs/fuzz4.out new file mode 100644 index 000000000..2801189a1 --- /dev/null +++ b/tests/data/bugs/fuzz4.out @@ -0,0 +1,98 @@ +{ + "query": "ALTeR=SET", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "ALTeR=SET", + "len": 9, + "last": 9, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "ALTeR", + "value": "ALTER", + "keyword": "ALTER", + "type": 1, + "flags": 3, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "=", + "value": "=", + "keyword": null, + "type": 2, + "flags": 2, + "position": 5 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "SET", + "value": "SET", + "keyword": "SET", + "type": 1, + "flags": 11, + "position": 6 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 4, + "idx": 4 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\AlterStatement", + "table": null, + "altered": [], + "options": null, + "first": 0, + "last": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Statements\\SetStatement", + "options": { + "@type": "PhpMyAdmin\\SqlParser\\Components\\OptionsArray", + "options": [] + }, + "end_options": null, + "set": [], + "first": 1, + "last": 2 + } + ], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [ + [ + "Unrecognized alter operation.", + { + "@type": "@2" + }, + 0 + ] + ] + } +} \ No newline at end of file From dd1e7752966bf16a0e31b110ac2643701f54ba4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Sat, 16 Sep 2023 00:54:06 -0300 Subject: [PATCH 5/5] Fix invalid characters passed to hexdec function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- src/Token.php | 2 +- tests/data/bugs/fuzz5.in | 1 + tests/data/bugs/fuzz5.out | 76 ++++++++++++++++++ tests/data/bugs/fuzz6.in | 1 + tests/data/bugs/fuzz6.out | 69 ++++++++++++++++ tests/data/lexer/lexNumber.in | 4 +- tests/data/lexer/lexNumber.out | 139 ++++++++++++++++++++++++--------- 7 files changed, 251 insertions(+), 41 deletions(-) create mode 100644 tests/data/bugs/fuzz5.in create mode 100644 tests/data/bugs/fuzz5.out create mode 100644 tests/data/bugs/fuzz6.in create mode 100644 tests/data/bugs/fuzz6.out diff --git a/src/Token.php b/src/Token.php index c7b028b3d..0e2698bb5 100644 --- a/src/Token.php +++ b/src/Token.php @@ -254,8 +254,8 @@ public function extract() case self::TYPE_NUMBER: $ret = str_replace('--', '', $this->token); // e.g. ---42 === -42 if ($this->flags & self::FLAG_NUMBER_HEX) { + $ret = str_replace(['-', '+'], '', $this->token); if ($this->flags & self::FLAG_NUMBER_NEGATIVE) { - $ret = str_replace('-', '', $this->token); $ret = -hexdec($ret); } else { $ret = hexdec($ret); diff --git a/tests/data/bugs/fuzz5.in b/tests/data/bugs/fuzz5.in new file mode 100644 index 000000000..61dd39880 --- /dev/null +++ b/tests/data/bugs/fuzz5.in @@ -0,0 +1 @@ ++0xO \ No newline at end of file diff --git a/tests/data/bugs/fuzz5.out b/tests/data/bugs/fuzz5.out new file mode 100644 index 000000000..ee8ec15e4 --- /dev/null +++ b/tests/data/bugs/fuzz5.out @@ -0,0 +1,76 @@ +{ + "query": "+0xO", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "+0xO", + "len": 4, + "last": 4, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "+0x", + "value": 0, + "keyword": null, + "type": 6, + "flags": 1, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "O", + "value": "O", + "keyword": null, + "type": 0, + "flags": 0, + "position": 3 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 3, + "idx": 3 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [ + [ + "Unexpected beginning of statement.", + { + "@type": "@2" + }, + 0 + ], + [ + "Unexpected beginning of statement.", + { + "@type": "@3" + }, + 0 + ] + ] + } +} \ No newline at end of file diff --git a/tests/data/bugs/fuzz6.in b/tests/data/bugs/fuzz6.in new file mode 100644 index 000000000..f3afa7709 --- /dev/null +++ b/tests/data/bugs/fuzz6.in @@ -0,0 +1 @@ +-+0x! \ No newline at end of file diff --git a/tests/data/bugs/fuzz6.out b/tests/data/bugs/fuzz6.out new file mode 100644 index 000000000..fce6bf5b7 --- /dev/null +++ b/tests/data/bugs/fuzz6.out @@ -0,0 +1,69 @@ +{ + "query": "-+0x!", + "lexer": { + "@type": "PhpMyAdmin\\SqlParser\\Lexer", + "str": "-+0x!", + "len": 5, + "last": 5, + "list": { + "@type": "PhpMyAdmin\\SqlParser\\TokensList", + "tokens": [ + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "-+0x", + "value": 0, + "keyword": null, + "type": 6, + "flags": 9, + "position": 0 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "!", + "value": "!", + "keyword": null, + "type": 2, + "flags": 2, + "position": 4 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": null, + "value": null, + "keyword": null, + "type": 9, + "flags": 0, + "position": null + } + ], + "count": 3, + "idx": 3 + }, + "delimiter": ";", + "delimiterLen": 1, + "strict": false, + "errors": [] + }, + "parser": { + "@type": "PhpMyAdmin\\SqlParser\\Parser", + "list": { + "@type": "@1" + }, + "statements": [], + "brackets": 0, + "strict": false, + "errors": [] + }, + "errors": { + "lexer": [], + "parser": [ + [ + "Unexpected beginning of statement.", + { + "@type": "@2" + }, + 0 + ] + ] + } +} \ No newline at end of file diff --git a/tests/data/lexer/lexNumber.in b/tests/data/lexer/lexNumber.in index 5751b0987..a0fff528e 100644 --- a/tests/data/lexer/lexNumber.in +++ b/tests/data/lexer/lexNumber.in @@ -1,3 +1,3 @@ -SELECT 12, 34, 5.67, 0x89, -10, --11, +12, .15, 0xFFa, 0xfFA, -0xFFa, -0xfFA, 1e-10, 1e10, .5e10, b'10'; +SELECT 12, 34, 5.67, 0x89, -10, --11, +12, .15, 0xFFa, 0xfFA, +0xfFA, -0xFFa, -0xfFA, 1e-10, 1e10, .5e10, b'10'; -- invalid numbers -SELECT 12ex10, b'15', 0XFfA, -0XFfA; \ No newline at end of file +SELECT 12ex10, b'15', 0XFfA, -0XFfA, +0XFfA; \ No newline at end of file diff --git a/tests/data/lexer/lexNumber.out b/tests/data/lexer/lexNumber.out index 2609bb428..5c6988dd1 100644 --- a/tests/data/lexer/lexNumber.out +++ b/tests/data/lexer/lexNumber.out @@ -1,10 +1,10 @@ { - "query": "SELECT 12, 34, 5.67, 0x89, -10, --11, +12, .15, 0xFFa, 0xfFA, -0xFFa, -0xfFA, 1e-10, 1e10, .5e10, b'10';\n-- invalid numbers\nSELECT 12ex10, b'15', 0XFfA, -0XFfA;", + "query": "SELECT 12, 34, 5.67, 0x89, -10, --11, +12, .15, 0xFFa, 0xfFA, +0xfFA, -0xFFa, -0xfFA, 1e-10, 1e10, .5e10, b'10';\n-- invalid numbers\nSELECT 12ex10, b'15', 0XFfA, -0XFfA, +0XFfA;", "lexer": { "@type": "PhpMyAdmin\\SqlParser\\Lexer", - "str": "SELECT 12, 34, 5.67, 0x89, -10, --11, +12, .15, 0xFFa, 0xfFA, -0xFFa, -0xfFA, 1e-10, 1e10, .5e10, b'10';\n-- invalid numbers\nSELECT 12ex10, b'15', 0XFfA, -0XFfA;", - "len": 160, - "last": 160, + "str": "SELECT 12, 34, 5.67, 0x89, -10, --11, +12, .15, 0xFFa, 0xfFA, +0xfFA, -0xFFa, -0xfFA, 1e-10, 1e10, .5e10, b'10';\n-- invalid numbers\nSELECT 12ex10, b'15', 0XFfA, -0XFfA, +0XFfA;", + "len": 176, + "last": 176, "list": { "@type": "PhpMyAdmin\\SqlParser\\TokensList", "tokens": [ @@ -298,11 +298,11 @@ }, { "@type": "PhpMyAdmin\\SqlParser\\Token", - "token": "-0xFFa", - "value": -4090, + "token": "+0xfFA", + "value": 4090, "keyword": null, "type": 6, - "flags": 9, + "flags": 1, "position": 62 }, { @@ -325,7 +325,7 @@ }, { "@type": "PhpMyAdmin\\SqlParser\\Token", - "token": "-0xfFA", + "token": "-0xFFa", "value": -4090, "keyword": null, "type": 6, @@ -350,6 +350,33 @@ "flags": 0, "position": 77 }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "-0xfFA", + "value": -4090, + "keyword": null, + "type": 6, + "flags": 9, + "position": 78 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ",", + "value": ",", + "keyword": null, + "type": 2, + "flags": 16, + "position": 84 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 85 + }, { "@type": "PhpMyAdmin\\SqlParser\\Token", "token": "1e-10", @@ -357,7 +384,7 @@ "keyword": null, "type": 6, "flags": 4, - "position": 78 + "position": 86 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -366,7 +393,7 @@ "keyword": null, "type": 2, "flags": 16, - "position": 83 + "position": 91 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -375,7 +402,7 @@ "keyword": null, "type": 3, "flags": 0, - "position": 84 + "position": 92 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -384,7 +411,7 @@ "keyword": null, "type": 6, "flags": 4, - "position": 85 + "position": 93 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -393,7 +420,7 @@ "keyword": null, "type": 2, "flags": 16, - "position": 89 + "position": 97 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -402,7 +429,7 @@ "keyword": null, "type": 3, "flags": 0, - "position": 90 + "position": 98 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -411,7 +438,7 @@ "keyword": null, "type": 6, "flags": 6, - "position": 91 + "position": 99 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -420,7 +447,7 @@ "keyword": null, "type": 2, "flags": 16, - "position": 96 + "position": 104 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -429,7 +456,7 @@ "keyword": null, "type": 3, "flags": 0, - "position": 97 + "position": 105 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -438,7 +465,7 @@ "keyword": null, "type": 6, "flags": 16, - "position": 98 + "position": 106 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -447,7 +474,7 @@ "keyword": null, "type": 9, "flags": 0, - "position": 103 + "position": 111 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -456,7 +483,7 @@ "keyword": null, "type": 3, "flags": 0, - "position": 104 + "position": 112 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -465,7 +492,7 @@ "keyword": null, "type": 4, "flags": 4, - "position": 105 + "position": 113 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -474,7 +501,7 @@ "keyword": null, "type": 3, "flags": 0, - "position": 123 + "position": 131 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -483,7 +510,7 @@ "keyword": "SELECT", "type": 1, "flags": 3, - "position": 124 + "position": 132 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -492,7 +519,7 @@ "keyword": null, "type": 3, "flags": 0, - "position": 130 + "position": 138 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -501,7 +528,7 @@ "keyword": null, "type": 0, "flags": 0, - "position": 131 + "position": 139 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -510,7 +537,7 @@ "keyword": null, "type": 2, "flags": 16, - "position": 137 + "position": 145 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -519,7 +546,7 @@ "keyword": null, "type": 3, "flags": 0, - "position": 138 + "position": 146 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -528,7 +555,7 @@ "keyword": null, "type": 0, "flags": 0, - "position": 139 + "position": 147 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -537,7 +564,7 @@ "keyword": null, "type": 7, "flags": 1, - "position": 140 + "position": 148 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -546,7 +573,7 @@ "keyword": null, "type": 2, "flags": 16, - "position": 144 + "position": 152 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -555,7 +582,7 @@ "keyword": null, "type": 3, "flags": 0, - "position": 145 + "position": 153 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -564,7 +591,7 @@ "keyword": null, "type": 0, "flags": 0, - "position": 146 + "position": 154 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -573,7 +600,7 @@ "keyword": null, "type": 2, "flags": 16, - "position": 151 + "position": 159 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -582,7 +609,7 @@ "keyword": null, "type": 3, "flags": 0, - "position": 152 + "position": 160 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -591,7 +618,7 @@ "keyword": null, "type": 2, "flags": 1, - "position": 153 + "position": 161 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -600,7 +627,43 @@ "keyword": null, "type": 0, "flags": 0, - "position": 154 + "position": 162 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": ",", + "value": ",", + "keyword": null, + "type": 2, + "flags": 16, + "position": 167 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": " ", + "value": " ", + "keyword": null, + "type": 3, + "flags": 0, + "position": 168 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "+", + "value": "+", + "keyword": null, + "type": 2, + "flags": 1, + "position": 169 + }, + { + "@type": "PhpMyAdmin\\SqlParser\\Token", + "token": "0XFfA", + "value": "0XFfA", + "keyword": null, + "type": 0, + "flags": 0, + "position": 170 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -609,7 +672,7 @@ "keyword": null, "type": 9, "flags": 0, - "position": 159 + "position": 175 }, { "@type": "PhpMyAdmin\\SqlParser\\Token", @@ -621,7 +684,7 @@ "position": null } ], - "count": 68, + "count": 75, "idx": 0 }, "delimiter": ";",