Skip to content

Commit 0fbe257

Browse files
committed
Merge branch 'PHP-8.5'
* PHP-8.5: Fix GH-22667: pdo_odbc heap over-read on oversized column value
2 parents df5e361 + 4eced77 commit 0fbe257

4 files changed

Lines changed: 47 additions & 1 deletion

File tree

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.6.0alpha3
44

5+
- PDO_ODBC:
6+
. Fixed bug GH-22667 (Heap buffer over-read when a column value exceeds the
7+
driver-reported display size). (iliaal)
8+
59
- Reflection:
610
. Fixed bug GH-22681 (Reflection*::__toString() truncates on null bytes).
711
(DanielEScherzer)

ext/pdo_odbc/odbc_stmt.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,14 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
761761
return 1;
762762
} else if (C->fetched_len >= 0) {
763763
/* it was stored perfectly */
764-
ZVAL_STRINGL_FAST(result, C->data, C->fetched_len);
764+
SQLLEN data_len = C->fetched_len;
765+
if (!C->is_long) {
766+
SQLLEN max_len = C->is_unicode ? (SQLLEN)C->datalen + 1 : (SQLLEN)C->datalen;
767+
if (data_len > max_len) {
768+
data_len = max_len;
769+
}
770+
}
771+
ZVAL_STRINGL_FAST(result, C->data, data_len);
765772
if (C->is_unicode) {
766773
goto unicode_conv;
767774
}

ext/pdo_odbc/tests/config.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?php
2+
3+
const PDO_ODBC_SQLITE_DSN = "odbc:Driver=SQLite3;Database=:memory:";

ext/pdo_odbc/tests/gh22667.phpt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
GH-22667 (Heap buffer over-read when a column value exceeds the bound buffer)
3+
--EXTENSIONS--
4+
pdo_odbc
5+
--SKIPIF--
6+
<?php
7+
require __DIR__ . '/config.inc';
8+
try {
9+
$pdo = new PDO(PDO_ODBC_SQLITE_DSN);
10+
} catch (PDOException $e) {
11+
die("skip requires the SQLite3 ODBC driver");
12+
}
13+
?>
14+
--FILE--
15+
<?php
16+
require __DIR__ . '/config.inc';
17+
$pdo = new PDO(PDO_ODBC_SQLITE_DSN);
18+
19+
// The SQLite3 driver reports a 255 byte display size for a computed column, so
20+
// the short-bound buffer holds at most 255 bytes while the value is far longer.
21+
// A conforming driver truncates into the buffer but reports the full length; the
22+
// returned string must stay within the buffer, not over-read past it.
23+
$stmt = $pdo->query("SELECT printf('%.*c', 4096, 'A') AS data");
24+
$row = $stmt->fetch(PDO::FETCH_ASSOC);
25+
$s = $row['data'];
26+
27+
echo "clamped to buffer: "; var_dump(strlen($s) < 4096);
28+
echo "only value bytes: "; var_dump(strlen($s) === substr_count($s, 'A'));
29+
?>
30+
--EXPECT--
31+
clamped to buffer: bool(true)
32+
only value bytes: bool(true)

0 commit comments

Comments
 (0)