Skip to content

Commit b91ea88

Browse files
dev-null-undefineddevnexen
authored andcommitted
Fix GH-24490: pdo_pgsql prepare() hangs on a query containing a NUL byte
No rule in the scanner matches a NUL byte, so what re2c does with one is undefined. Before 5ccc56b it happened to skip one character. Now it returns a zero-length text token and pdo_parse_params() loops forever, or reads an uninitialized YYMARKER if the NUL is the first byte. Add a default rule so a NUL is skipped as one character of text again. Close GH-24496
1 parent c0018be commit b91ea88

3 files changed

Lines changed: 35 additions & 0 deletions

File tree

‎NEWS‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ PHP NEWS
9292
. Improved performance of the SQL parser that handles placeholders.
9393
(brainexe)
9494
. Improved performance of fetching integer columns. (brainexe)
95+
. Fixed bug GH-24490 (pdo_pgsql prepare() hangs on a query containing a NUL
96+
byte). (dev-null-undefined)
9597

9698
- PGSQL:
9799
. Fixed pg_lo_write() rejecting data containing null bytes. (Ilia Alshanetsky)

‎ext/pdo_pgsql/pgsql_sql_parser.re‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,6 @@ int pdo_pgsql_scanner(pdo_scanner_t *s)
4848
COMMENTS { RET(PDO_PARSER_TEXT); }
4949
/* Plain text may contain e/E, as long as it doesn't end with one, which could start an E'...' string */
5050
([eE]* TEXTCHR)+ { RET(PDO_PARSER_TEXT); }
51+
* { SKIP_ONE(PDO_PARSER_TEXT); }
5152
*/
5253
}

‎ext/pdo_pgsql/tests/gh24490.phpt‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
GH-24490 (pdo_pgsql: prepare() hangs on a query containing a NUL byte)
3+
--EXTENSIONS--
4+
pdo_pgsql
5+
--SKIPIF--
6+
<?php
7+
require __DIR__ . '/config.inc';
8+
require dirname(__DIR__, 2) . '/pdo/tests/pdo_test.inc';
9+
PDOTest::skip();
10+
?>
11+
--FILE--
12+
<?php
13+
require __DIR__ . '/../../../ext/pdo/tests/pdo_test.inc';
14+
$db = PDOTest::test_factory(__DIR__ . '/common.phpt');
15+
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
16+
17+
foreach ([true, false] as $emulate) {
18+
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, $emulate);
19+
$db->prepare("SELECT 'abc\0def'");
20+
$db->prepare("\0SELECT 1");
21+
try {
22+
$db->prepare("SELECT '\0', ?, :p");
23+
} catch (\Throwable $e) {
24+
echo $e::class, ": ", $e->getMessage(), "\n";
25+
}
26+
}
27+
echo "Done\n";
28+
?>
29+
--EXPECT--
30+
PDOException: SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters
31+
PDOException: SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters
32+
Done

0 commit comments

Comments
 (0)