From 19f3c454b374abdb25d1fd01512ee20626a950e5 Mon Sep 17 00:00:00 2001 From: Evert Pot Date: Mon, 24 Oct 2016 01:06:21 -0400 Subject: [PATCH 1/3] Catching another infinite loop condition. Fixes #329. Thanks for the research @PHPGangsta --- CHANGELOG.md | 2 + lib/Recur/RRuleIterator.php | 20 ++++++++-- .../EventIterator/InfiniteLoopProblemTest.php | 39 +++++++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0071f367..40a71bc44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ChangeLog ------------------ * +* #329: Infinite loop when using `BYMONTHDAY`, `BYDAY` and/or `BYSETPOS` to + expand a `BYMONTH` rule. 4.1.6 (2018-04-20) ------------------ diff --git a/lib/Recur/RRuleIterator.php b/lib/Recur/RRuleIterator.php index dbea1155d..473413ca5 100644 --- a/lib/Recur/RRuleIterator.php +++ b/lib/Recur/RRuleIterator.php @@ -620,12 +620,14 @@ protected function nextYearly() { } - $currentMonth = $this->currentDate->format('n'); - $currentYear = $this->currentDate->format('Y'); - $currentDayOfMonth = $this->currentDate->format('j'); + //$currentMonth = $this->currentDate->format('n'); + //$currentYear = $this->currentDate->format('Y'); + //$currentDayOfMonth = $this->currentDate->format('j'); $advancedToNewMonth = false; + $noOccurrenceCounter = 0; + // If we got a byDay or getMonthDay filter, we must first expand // further. if ($this->byDay || $this->byMonthDay) { @@ -633,6 +635,18 @@ protected function nextYearly() { while (true) { $occurrences = $this->getMonthlyOccurrences(); + if(!$occurrences) { + // We are counting subsequent months where there weren't + // occurrences. If we exceed the treshold we might be + // dealing with a recurrence rule that doesn't generate + // valid instances. + $noOccurrenceCounter++; + if (++$noOccurrenceCounter > 10) { + throw new InvalidDataException('BYDAY, BYMONTHDAY and/or BYSETPOS rules don\'t generate valid recurrence instances'); + } + } else { + $noOccurrenceCounter = 0; + } foreach ($occurrences as $occurrence) { diff --git a/tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php b/tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php index 0ba7296a5..dc00267cd 100644 --- a/tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php +++ b/tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php @@ -7,6 +7,7 @@ use PHPUnit\Framework\TestCase; use Sabre\VObject\Component\VCalendar; use Sabre\VObject\Recur; +use Sabre\VObject\Reader; class InfiniteLoopProblemTest extends TestCase { @@ -96,4 +97,42 @@ function testZeroInterval() { } + /** + * Another infinite loop, from Issue #329. + * + * This was triggered due to a BYMONTHDAY rule that was using a value that + * never occurred in the BYMONTH rule. + * + * This bug surfaced similar issues with BYDAY and BYSETPOS. + * + * @expectedException \Sabre\VObject\InvalidDataException + */ + function testBadByMonthday() { + + $input = Reader::read(<<expand( + new DateTimeImmutable('2015-01-01'), + new DateTimeImmutable('2016-01-01') + ); + + } + } From d2e3790aa1ae890623622212e868c154b35d3303 Mon Sep 17 00:00:00 2001 From: Evert Pot Date: Mon, 24 Oct 2016 01:10:46 -0400 Subject: [PATCH 2/3] CS --- lib/Recur/RRuleIterator.php | 2 +- tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Recur/RRuleIterator.php b/lib/Recur/RRuleIterator.php index 473413ca5..3b476ef2f 100644 --- a/lib/Recur/RRuleIterator.php +++ b/lib/Recur/RRuleIterator.php @@ -635,7 +635,7 @@ protected function nextYearly() { while (true) { $occurrences = $this->getMonthlyOccurrences(); - if(!$occurrences) { + if (!$occurrences) { // We are counting subsequent months where there weren't // occurrences. If we exceed the treshold we might be // dealing with a recurrence rule that doesn't generate diff --git a/tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php b/tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php index dc00267cd..c3acd94b4 100644 --- a/tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php +++ b/tests/VObject/Recur/EventIterator/InfiniteLoopProblemTest.php @@ -6,8 +6,8 @@ use DateTimeZone; use PHPUnit\Framework\TestCase; use Sabre\VObject\Component\VCalendar; -use Sabre\VObject\Recur; use Sabre\VObject\Reader; +use Sabre\VObject\Recur; class InfiniteLoopProblemTest extends TestCase { From 64831ee4ac47476f5298901015d5ef925797e711 Mon Sep 17 00:00:00 2001 From: EoleDev Date: Wed, 25 Jul 2018 15:23:00 +0200 Subject: [PATCH 3/3] Remove comments of old code --- lib/Recur/RRuleIterator.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/Recur/RRuleIterator.php b/lib/Recur/RRuleIterator.php index 3b476ef2f..f99b96080 100644 --- a/lib/Recur/RRuleIterator.php +++ b/lib/Recur/RRuleIterator.php @@ -620,10 +620,6 @@ protected function nextYearly() { } - //$currentMonth = $this->currentDate->format('n'); - //$currentYear = $this->currentDate->format('Y'); - //$currentDayOfMonth = $this->currentDate->format('j'); - $advancedToNewMonth = false; $noOccurrenceCounter = 0;