Skip to content

Commit e23dc68

Browse files
lacatoiredevnexen
authored andcommitted
ext/pcntl: fix an off by one bound and a parameter the parser made required
pcntl_setcpuaffinity() refuses a cpu id equal to the cpu count but named that count as the inclusive upper bound, printing a zend_long with the unsigned format on the way. pcntl_setqos_class() declares $qos_class optional while its parser demanded it, leaving the declared default unreachable. Close GH-23553
1 parent 32f5149 commit e23dc68

4 files changed

Lines changed: 66 additions & 4 deletions

File tree

‎NEWS‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ PHP NEWS
7070
an exception is pending. (nicolas-grekas)
7171
. Fixed pcntl_signal_dispatch() dropping the signals queued behind a handler
7272
that throws. (nicolas-grekas)
73+
. Fixed pcntl_setcpuaffinity() error message advertising the cpu count as
74+
the inclusive upper bound. (lacatoire)
75+
. Fixed pcntl_setqos_class() requiring its optional $qos_class argument.
76+
(lacatoire)
7377

7478
- PDO:
7579
. Fixed PDOStatement::getColumnMeta() reading out of bounds for an invalid

‎ext/pcntl/pcntl.c‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1791,7 +1791,7 @@ PHP_FUNCTION(pcntl_setcpuaffinity)
17911791
}
17921792

17931793
if (cpu < 0 || cpu >= maxcpus) {
1794-
zend_argument_value_error(2, "cpu id must be between 0 and " ZEND_ULONG_FMT " (" ZEND_LONG_FMT ")", maxcpus, cpu);
1794+
zend_argument_value_error(2, "cpu id must be between 0 and " ZEND_LONG_FMT " (" ZEND_LONG_FMT ")", maxcpus - 1, cpu);
17951795
PCNTL_CPU_DESTROY(mask);
17961796
RETURN_THROWS();
17971797
}
@@ -1898,13 +1898,14 @@ PHP_FUNCTION(pcntl_getqos_class)
18981898

18991899
PHP_FUNCTION(pcntl_setqos_class)
19001900
{
1901-
zval *qos_obj;
1901+
zval *qos_obj = NULL;
19021902

1903-
ZEND_PARSE_PARAMETERS_START(1, 1)
1903+
ZEND_PARSE_PARAMETERS_START(0, 1)
1904+
Z_PARAM_OPTIONAL
19041905
Z_PARAM_OBJECT_OF_CLASS(qos_obj, QosClass_ce)
19051906
ZEND_PARSE_PARAMETERS_END();
19061907

1907-
qos_class_t qos_class = qos_zval_to_lval(qos_obj);
1908+
qos_class_t qos_class = qos_obj ? qos_zval_to_lval(qos_obj) : QOS_CLASS_DEFAULT;
19081909

19091910
if (UNEXPECTED(pthread_set_qos_class_self_np((qos_class_t)qos_class, 0) != 0))
19101911
{
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
--TEST--
2+
pcntl_setcpuaffinity(): the upper bound the error advertises is itself a valid cpu id
3+
--EXTENSIONS--
4+
pcntl
5+
--SKIPIF--
6+
<?php
7+
if (PHP_OS_FAMILY === 'Solaris') {
8+
die("skip broken pset_create()");
9+
}
10+
if (!function_exists("pcntl_setcpuaffinity")) die("skip pcntl_setcpuaffinity is not available");
11+
?>
12+
--FILE--
13+
<?php
14+
$pid = getmypid();
15+
$prefix = 'pcntl_setcpuaffinity(): Argument #2 ($cpu_ids) cpu id must be between 0 and ';
16+
17+
/* read the advertised bound out of the message itself */
18+
try {
19+
pcntl_setcpuaffinity($pid, [PHP_INT_MAX]);
20+
exit("PHP_INT_MAX was accepted as a cpu id" . PHP_EOL);
21+
} catch (Throwable $e) {
22+
echo $e::class, "\n";
23+
if (!preg_match('/must be between 0 and (\d+) \(/', $e->getMessage(), $m)) {
24+
exit("unexpected message: " . $e->getMessage() . PHP_EOL);
25+
}
26+
}
27+
$bound = (int) $m[1];
28+
29+
/* Every id is range checked before any syscall runs, so pairing the advertised
30+
bound with an out of range id shows which of the two the check rejects,
31+
without ever changing the process affinity. */
32+
try {
33+
pcntl_setcpuaffinity($pid, [$bound, PHP_INT_MAX]);
34+
} catch (Throwable $e) {
35+
echo $e::class, "\n";
36+
var_dump($e->getMessage() === $prefix . $bound . ' (' . PHP_INT_MAX . ')');
37+
}
38+
39+
/* and the first id past the bound is rejected, naming itself */
40+
try {
41+
pcntl_setcpuaffinity($pid, [$bound + 1]);
42+
} catch (Throwable $e) {
43+
echo $e::class, "\n";
44+
var_dump($e->getMessage() === $prefix . $bound . ' (' . ($bound + 1) . ')');
45+
}
46+
?>
47+
--EXPECT--
48+
ValueError
49+
ValueError
50+
bool(true)
51+
ValueError
52+
bool(true)

‎ext/pcntl/tests/pcntl_qosclass.phpt‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ pcntl_setqos_class(Pcntl\QosClass::Default);
1313
var_dump(Pcntl\QosClass::Default === pcntl_getqos_class());
1414
pcntl_setqos_class(Pcntl\QosClass::Background);
1515
var_dump(Pcntl\QosClass::Background == pcntl_getqos_class());
16+
17+
/* the parameter is optional, and omitting it applies the declared default */
18+
pcntl_setqos_class();
19+
var_dump(Pcntl\QosClass::Default === pcntl_getqos_class());
1620
?>
1721
--EXPECT--
1822
bool(true)
1923
bool(true)
24+
bool(true)

0 commit comments

Comments
 (0)