8000 Prevent "interval" overflow in ExtUvLoop · reactphp/event-loop@4e32262 · GitHub
[go: up one dir, main page]

Skip to content
Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 4e32262

Browse files
Prevent "interval" overflow in ExtUvLoop
1 parent babf91e commit 4e32262

File tree

3 files changed

+65
-4
lines changed

3 files changed

+65
-4
lines changed

src/ExtUvLoop.php

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public function addTimer($interval, $callback)
127127
$this->timers->attach($timer, $event);
128128
\uv_timer_start(
129129
$event,
130-
(int) ($interval * 1000) + 1,
130+
$this->convertFloatSecondsToMilliseconds($interval),
131131
0,
132132
$callback
133133
);
@@ -150,8 +150,8 @@ public function addPeriodicTimer($interval, $callback)
150150
$this->timers->attach($timer, $event);
151151
\uv_timer_start(
152152
$event,
153-
(int) ($interval * 1000) + 1,
154-
(int) ($interval * 1000) + 1,
153+
$this->convertFloatSecondsToMilliseconds($interval),
154+
$this->convertFloatSecondsToMilliseconds($interval),
155155
$callback
156156
);
157157

@@ -313,4 +313,31 @@ private function createStreamListener()
313313

314314
return $callback;
315315
}
316+
317+
/**
318+
* @param float $interval
319+
* @return int
320+
*/
321+
private function convertFloatSecondsToMilliseconds($interval)
322+
{
323+
if ($interval < 0) {
324+
throw new \InvalidArgumentException('Interval cannot be lower than 0.');
325+
}
326+
327+
// Subtract 2 because 1 doesn't seems to work and may give wrong results
328+
$maxValue = ((int) (\PHP_INT_MAX / 1000)) - 2;
329+
330+
if ($interval > $maxValue) {
331+
throw new \InvalidArgumentException(
332+
"Interval overflow, maximum value is '{$maxValue}', but '{$interval}' passed."
333+
);
334+
}
335+
336+
$result = (int) \floor($interval * 1000);
337+
338+
return $result === 0
339+
? 1
340+
: $result
341+
;
342+
}
316343
}

tests/AbstractLoopTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -591,9 +591,11 @@ public function testSignalsKeepTheLoopRunningAndRemovingItStopsTheLoop()
591591

592592
public function testTimerIntervalCanBeFarInFuture()
593593
{
594+
// Maximum interval for ExtUvLoop implementation
595+
$interval = (PHP_INT_MAX / 1000) - 2;
594596
$loop = $this->loop;
595597
// start a timer very far in the future
596-
$timer = $this->loop->addTimer(PHP_INT_MAX, function () { });
598+
$timer = $this->loop->addTimer($interval, function () { });
597599

598600
$this->loop->futureTick(function () use ($timer, $loop) {
599601
$loop->cancelTimer($timer);

tests/ExtUvLoopTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,36 @@ public function createLoop()
1414

1515
return new ExtUvLoop();
1616
}
17+
18+
/** @dataProvider intervalProvider */
19+
public function testTimerInterval($interval, $expectedExceptionMessage)
20+
{
21+
$this->expectException('InvalidArgumentException');
22+
$this->expectExceptionMessage($expectedExceptionMessage);
23+
24+
$this->loop
25+
->addTimer(
26+
$interval,
27+
function () {
28+
return 0;
29+
}
30+
);
31+
}
32+
33+
public function intervalProvider()
34+
{
35+
$oversizeInterval = PHP_INT_MAX / 1000;
36+
$maxValue = ((int) (PHP_INT_MAX / 1000)) - 2;
37+
38+
return array(
39+
array(
40+
-1,
41+
'Interval cannot be lower than 0.'
42+
),
43+
array(
44+
$oversizeInterval,
45+
"Interval overflow, maximum value is '{$maxValue}', but '{$oversizeInterval}' passed."
46+
)
47+
);
48+
}
1749
}

0 commit comments

Comments
 (0)
0