Skip to content

Commit 2bcc533

Browse files
authored
Merge pull request microsoft#311 from TysonAndre/fix-fuzz-static
Properly handle failure to parse right side of binary operations
2 parents 29c7430 + 46204f1 commit 2bcc533

File tree

4 files changed

+117
-5
lines changed

4 files changed

+117
-5
lines changed

src/Parser.php

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,10 +1068,9 @@ private function parsePrimaryExpression($parentNode) {
10681068
// anonymous-function-creation-expression
10691069
case TokenKind::StaticKeyword:
10701070
// handle `static::`, `static(`, `new static;`, `instanceof static`
1071-
if (($this->lookahead([TokenKind::ColonColonToken, TokenKind::OpenParenToken])) ||
1072-
(!$this->lookahead([TokenKind::FunctionKeyword, TokenKind::FnKeyword]))
1073-
) {
1074-
return $this->parseQualifiedName($parentNode);
1071+
if ((!$this->lookahead([TokenKind::FunctionKeyword, TokenKind::FnKeyword]))) {
1072+
// TODO: Should this check the parent type to reject `$x = static;`, `$x = static();`, etc.
1073+
return $this->parseStaticQualifiedName($parentNode);
10751074
}
10761075
// Could be `static function` anonymous function creation expression, so flow through
10771076
case TokenKind::FunctionKeyword:
@@ -1370,6 +1369,21 @@ private function isQualifiedNameStartForCatchFn() {
13701369
};
13711370
}
13721371

1372+
/**
1373+
* @return QualifiedName
1374+
*/
1375+
private function parseStaticQualifiedName($parentNode) {
1376+
$node = new QualifiedName();
1377+
$token = $this->eat(TokenKind::StaticKeyword);
1378+
$token->kind = TokenKind::Name;
1379+
$node->parent = $parentNode;
1380+
$node->nameParts = [$token];
1381+
return $node;
1382+
}
1383+
1384+
/**
1385+
* @return QualifiedName|null - returns null for invalid qualified names such as `static\` (use parseStaticQualifiedName for that)
1386+
*/
13731387
private function parseQualifiedName($parentNode) {
13741388
return ($this->parseQualifiedNameFn())($parentNode);
13751389
}
@@ -1388,7 +1402,9 @@ private function parseQualifiedNameFn() {
13881402
DelimitedList\QualifiedNameParts::class,
13891403
TokenKind::BackslashToken,
13901404
function ($token) {
1391-
// a\static() <- VALID
1405+
// a\static() <- INVALID (but not checked for right now)
1406+
// new a\static() <- INVALID
1407+
// new static() <- VALID
13921408
// a\static\b <- INVALID
13931409
// a\function <- INVALID
13941410
// a\true\b <-VALID
@@ -1485,6 +1501,9 @@ private function parseNamedLabelStatement($parentNode) {
14851501
return $namedLabelStatement;
14861502
}
14871503

1504+
/**
1505+
* @param int|int[] ...$expectedKinds an array of one or more kinds/sets of allowed kinds in each position
1506+
*/
14881507
private function lookahead(...$expectedKinds) : bool {
14891508
$startPos = $this->lexer->getCurrentPosition();
14901509
$startToken = $this->token;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?php \&static\
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[
2+
{
3+
"kind": 0,
4+
"message": "';' expected.",
5+
"start": 14,
6+
"length": 0
7+
},
8+
{
9+
"kind": 0,
10+
"message": "';' expected.",
11+
"start": 15,
12+
"length": 0
13+
}
14+
]
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{
2+
"SourceFileNode": {
3+
"statementList": [
4+
{
5+
"InlineHtml": {
6+
"scriptSectionEndTag": null,
7+
"text": null,
8+
"scriptSectionStartTag": {
9+
"kind": "ScriptSectionStartTag",
10+
"textLength": 6
11+
}
12+
}
13+
},
14+
{
15+
"ExpressionStatement": {
16+
"expression": {
17+
"BinaryExpression": {
18+
"leftOperand": {
19+
"QualifiedName": {
20+
"globalSpecifier": {
21+
"kind": "BackslashToken",
22+
"textLength": 1
23+
},
24+
"relativeSpecifier": null,
25+
"nameParts": []
26+
}
27+
},
28+
"operator": {
29+
"kind": "AmpersandToken",
30+
"textLength": 1
31+
},
32+
"rightOperand": {
33+
"QualifiedName": {
34+
"globalSpecifier": null,
35+
"relativeSpecifier": null,
36+
"nameParts": [
37+
{
38+
"kind": "Name",
39+
"textLength": 6
40+
}
41+
]
42+
}
43+
}
44+
}
45+
},
46+
"semicolon": {
47+
"error": "MissingToken",
48+
"kind": "SemicolonToken",
49+
"textLength": 0
50+
}
51+
}
52+
},
53+
{
54+
"ExpressionStatement": {
55+
"expression": {
56+
"QualifiedName": {
57+
"globalSpecifier": {
58+
"kind": "BackslashToken",
59+
"textLength": 1
60+
},
61+
"relativeSpecifier": null,
62+
"nameParts": []
63+
}
64+
},
65+
"semicolon": {
66+
"error": "MissingToken",
67+
"kind": "SemicolonToken",
68+
"textLength": 0
69+
}
70+
}
71+
}
72+
],
73+
"endOfFileToken": {
74+
"kind": "EndOfFileToken",
75+
"textLength": 0
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)