Commit a4c4173d9a1 for php
commit a4c4173d9a125837b7e03a2c8c3c0ea0d178077d
Author: Calvin Buckley <calvinb@php.net>
Date: Sat Sep 26 18:49:55 2026 -0300
ext/odbc: fix cond for SQL_NO_TOTAL that led to single byte buffer (#23462)
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.
diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c
index d71d24fd8b9..d30979651d3 100644
--- a/ext/pdo_odbc/odbc_stmt.c
+++ b/ext/pdo_odbc/odbc_stmt.c
@@ -775,10 +775,14 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo
* changed from 256 byte to LONG_COLUMN_BUFFER_SIZE.
*/
ssize_t to_fetch_len;
- if (orig_fetched_len == SQL_NO_TOTAL) {
- to_fetch_len = C->datalen > (LONG_COLUMN_BUFFER_SIZE - 1) ? (LONG_COLUMN_BUFFER_SIZE - 1) : C->datalen;
- } else {
+ if (orig_fetched_len == SQL_NO_TOTAL && C->datalen > (LONG_COLUMN_BUFFER_SIZE - 1)) {
+ to_fetch_len = C->datalen;
+ } else if (orig_fetched_len > 0) {
+ /* implicitly not SQL_NO_TOTAL, should be OK */
to_fetch_len = orig_fetched_len;
+ } else {
+ /* size must be > 0 to actually get data */
+ to_fetch_len = (LONG_COLUMN_BUFFER_SIZE - 1);
}
ssize_t to_fetch_byte = to_fetch_len + 1;
char *buf2 = emalloc(to_fetch_byte);
diff --git a/ext/pdo_odbc/tests/gh23443.phpt b/ext/pdo_odbc/tests/gh23443.phpt
new file mode 100644
index 00000000000..00505868760
--- /dev/null
+++ b/ext/pdo_odbc/tests/gh23443.phpt
@@ -0,0 +1,24 @@
+--TEST--
+GH-23443 (infinite loop / 100% CPU when fetching a large nvarchar(max))
+--EXTENSIONS--
+pdo_odbc
+--SKIPIF--
+<?php
+require 'ext/pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require 'ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory('ext/pdo_odbc/tests/common.phpt');
+
+/*
+ * Likely depends on ZendMM page size + string overhead that affects long
+ * column buffer size
+ */
+$n = 4499;
+$row = $db->query("SELECT REPLICATE(CAST(N'A' AS nvarchar(max)), $n) AS v")->fetch(PDO::FETCH_ASSOC);
+echo "ok\n";
+?>
+--EXPECT--
+ok