Skip to content

Commit c6ddd5b

Browse files
Merge branch '4.2'
* 4.2: [Twig] Remove spaces to fix whitespace in tags [Twig] Replace for-loops with blocks for attributes fixed CS [Tests] Change to willThrowException [Console] fix PHPDoc in Command Update FileLoaderLoadException.php Fix wrong calls to clearstatcache Add Vietnamese translation for validators Allow running PHPUnit with "xdebug.scream" ON [VarDumper] Add descriptors tests [Cache] fix bad optim [Yaml] detect circular references [DI] fix reporting bindings on overriden services as unused [Routing] minor fix or previous PR
2 parents 3a51c82 + d32010d commit c6ddd5b

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

Parser.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class Parser
3535
private $refs = array();
3636
private $skippedLineNumbers = array();
3737
private $locallySkippedLineNumbers = array();
38+
private $refsBeingParsed = array();
3839

3940
/**
4041
* Parses a YAML file into a PHP value.
@@ -169,6 +170,7 @@ private function doParse(string $value, int $flags)
169170

170171
if (isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
171172
$isRef = $matches['ref'];
173+
$this->refsBeingParsed[] = $isRef;
172174
$values['value'] = $matches['value'];
173175
}
174176

@@ -201,6 +203,7 @@ private function doParse(string $value, int $flags)
201203
}
202204
if ($isRef) {
203205
$this->refs[$isRef] = end($data);
206+
array_pop($this->refsBeingParsed);
204207
}
205208
} elseif (
206209
self::preg_match('#^(?P<key>(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(\s++(?P<value>.+))?$#u', rtrim($this->currentLine), $values)
@@ -235,6 +238,10 @@ private function doParse(string $value, int $flags)
235238
if (isset($values['value'][0]) && '*' === $values['value'][0]) {
236239
$refName = substr(rtrim($values['value']), 1);
237240
if (!array_key_exists($refName, $this->refs)) {
241+
if (false !== $pos = array_search($refName, $this->refsBeingParsed, true)) {
242+
throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $refName, $refName), $this->currentLineNb + 1, $this->currentLine, $this->filename);
243+
}
244+
238245
throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
239246
}
240247

@@ -288,6 +295,7 @@ private function doParse(string $value, int $flags)
288295
}
289296
} elseif ('<<' !== $key && isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u', $values['value'], $matches)) {
290297
$isRef = $matches['ref'];
298+
$this->refsBeingParsed[] = $isRef;
291299
$values['value'] = $matches['value'];
292300
}
293301

@@ -345,6 +353,7 @@ private function doParse(string $value, int $flags)
345353
}
346354
if ($isRef) {
347355
$this->refs[$isRef] = $data[$key];
356+
array_pop($this->refsBeingParsed);
348357
}
349358
} else {
350359
// multiple documents are not supported
@@ -450,6 +459,7 @@ private function parseBlock(int $offset, string $yaml, int $flags)
450459
$parser->totalNumberOfLines = $this->totalNumberOfLines;
451460
$parser->skippedLineNumbers = $skippedLineNumbers;
452461
$parser->refs = &$this->refs;
462+
$parser->refsBeingParsed = $this->refsBeingParsed;
453463

454464
return $parser->doParse($yaml, $flags);
455465
}
@@ -639,6 +649,10 @@ private function parseValue(string $value, int $flags, string $context)
639649
}
640650

641651
if (!array_key_exists($value, $this->refs)) {
652+
if (false !== $pos = array_search($value, $this->refsBeingParsed, true)) {
653+
throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $value, $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
654+
}
655+
642656
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
643657
}
644658

Tests/ParserTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2023,6 +2023,48 @@ public function testEvalRefException()
20232023
$this->parser->parse($yaml);
20242024
}
20252025

2026+
/**
2027+
* @dataProvider circularReferenceProvider
2028+
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
2029+
* @expectedExceptionMessage Circular reference [foo, bar, foo] detected
2030+
*/
2031+
public function testDetectCircularReferences($yaml)
2032+
{
2033+
$this->parser->parse($yaml, Yaml::PARSE_CUSTOM_TAGS);
2034+
}
2035+
2036+
public function circularReferenceProvider()
2037+
{
2038+
$tests = array();
2039+
2040+
$yaml = <<<YAML
2041+
foo:
2042+
- &foo
2043+
- &bar
2044+
bar: foobar
2045+
baz: *foo
2046+
YAML;
2047+
$tests['sequence'] = array($yaml);
2048+
2049+
$yaml = <<<YAML
2050+
foo: &foo
2051+
bar: &bar
2052+
foobar: baz
2053+
baz: *foo
2054+
YAML;
2055+
$tests['mapping'] = array($yaml);
2056+
2057+
$yaml = <<<YAML
2058+
foo: &foo
2059+
bar: &bar
2060+
foobar: baz
2061+
<<: *foo
2062+
YAML;
2063+
$tests['mapping with merge key'] = array($yaml);
2064+
2065+
return $tests;
2066+
}
2067+
20262068
/**
20272069
* @dataProvider indentedMappingData
20282070
*/

0 commit comments

Comments
 (0)