Skip to content

Commit 3171a6c

Browse files
committed
ext/odbc: fix cond for SQL_NO_TOTAL that led to single byte buffer
The ternary condition here was inverted, which could lead to a single byte buffer being used, which is insufficient for anything. Fix it by making the conditionals clearer. Fixes GH-23443.
1 parent 38ffb63 commit 3171a6c

2 files changed

Lines changed: 31 additions & 3 deletions

File tree

‎ext/pdo_odbc/odbc_stmt.c‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -763,10 +763,14 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
763763
* changed from 256 byte to LONG_COLUMN_BUFFER_SIZE.
764764
*/
765765
ssize_t to_fetch_len;
766-
if (orig_fetched_len == SQL_NO_TOTAL) {
767-
to_fetch_len = C->datalen > (LONG_COLUMN_BUFFER_SIZE - 1) ? (LONG_COLUMN_BUFFER_SIZE - 1) : C->datalen;
768-
} else {
766+
if (orig_fetched_len == SQL_NO_TOTAL && C->datalen > (LONG_COLUMN_BUFFER_SIZE - 1)) {
767+
to_fetch_len = C->datalen;
768+
} else if (orig_fetched_len > 0) {
769+
/* implicitly not SQL_NO_TOTAL, should be OK */
769770
to_fetch_len = orig_fetched_len;
771+
} else {
772+
/* size must be > 0 to actually get data */
773+
to_fetch_len = (LONG_COLUMN_BUFFER_SIZE - 1);
770774
}
771775
ssize_t to_fetch_byte = to_fetch_len + 1;
772776
char *buf2 = emalloc(to_fetch_byte);

‎ext/pdo_odbc/tests/gh23443.phpt‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-23443 (infinite loop / 100% CPU when fetching a large nvarchar(max))
3+
--EXTENSIONS--
4+
pdo_odbc
5+
--SKIPIF--
6+
<?php
7+
require 'ext/pdo/tests/pdo_test.inc';
8+
PDOTest::skip();
9+
?>
10+
--FILE--
11+
<?php
12+
require 'ext/pdo/tests/pdo_test.inc';
13+
$db = PDOTest::test_factory('ext/pdo_odbc/tests/common.phpt');
14+
15+
/*
16+
* Likely depends on ZendMM page size + string overhead that affects long
17+
* column buffer size
18+
*/
19+
$n = 4499;
20+
$row = $db->query("SELECT REPLICATE(CAST(N'A' AS nvarchar(max)), $n) AS v")->fetch(PDO::FETCH_ASSOC);
21+
echo "ok\n";
22+
?>
23+
--EXPECT--
24+
ok

0 commit comments

Comments
 (0)