Commit 0c2fc141fcf for php.net
commit 0c2fc141fcf9edb13b57b34c3843ed75e24ddcf5
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Sun Sep 6 11:01:32 2026 -0400
odbc: check SQLColAttribute return codes in the field info functions
odbc_column_lengths() and odbc_field_type() ignored the SQLColAttribute
return code and returned their output buffer regardless, so a driver that
fails the call left odbc_field_len(), odbc_field_scale() and
odbc_field_type() reporting uninitialized stack. Check the code, warn with
the driver's own diagnostic, and return 0 or false instead.
Closes GH-23601
diff --git a/NEWS b/NEWS
index 6a6d6110970..935583e8733 100644
--- a/NEWS
+++ b/NEWS
@@ -66,6 +66,11 @@ PHP NEWS
replacement when a \k<name> backref has no closing delimiter.
(Ilia Alshanetsky)
+- ODBC:
+ . Fixed odbc_field_len(), odbc_field_scale() and odbc_field_type()
+ returning uninitialized memory when SQLColAttribute fails.
+ (Ilia Alshanetsky)
+
- Opcache:
. Fixed a crash when the huge page SHM remap discarded mappings outside the
reserved address range. (Piotr Hałas)
diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c
index 8b78308f942..798245c4ca9 100644
--- a/ext/odbc/php_odbc.c
+++ b/ext/odbc/php_odbc.c
@@ -683,6 +683,7 @@ void odbc_bindcols(odbc_result *result)
result->values[i].value_max_len = 0;
colfieldid = SQL_COLUMN_DISPLAY_SIZE;
+ result->values[i].name[0] = '\0';
rc = PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)(i+1), PHP_ODBC_SQL_DESC_NAME,
result->values[i].name, sizeof(result->values[i].name), &colnamelen, 0);
result->values[i].coltype = 0;
@@ -809,10 +810,30 @@ void odbc_transact(INTERNAL_FUNCTION_PARAMETERS, int type)
}
/* }}} */
+static void odbc_colattribute_failed(odbc_result *result, zend_long pv_num)
+{
+#if defined(ODBCVER) && (ODBCVER >= 0x0300)
+ SQLINTEGER diag_error;
+ SQLCHAR diag_state[6];
+ SQLCHAR diag_text[128];
+
+ memset(diag_state, '\0', sizeof(diag_state));
+ memset(diag_text, '\0', sizeof(diag_text));
+ if (SQL_SUCCESS == SQLGetDiagRec(SQL_HANDLE_STMT, result->stmt, 1, diag_state, &diag_error, diag_text, sizeof(diag_text), NULL)) {
+ diag_state[sizeof(diag_state) - 1] = '\0';
+ diag_text[sizeof(diag_text) - 1] = '\0';
+ php_error_docref(NULL, E_WARNING, "SQLColAttribute failed for field #%d: [%s] %s", (int)pv_num, diag_state, diag_text);
+ return;
+ }
+#endif
+ php_error_docref(NULL, E_WARNING, "SQLColAttribute failed for field #%d", (int)pv_num);
+}
+
/* {{{ odbc_column_lengths */
void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type)
{
odbc_result *result;
+ RETCODE rc;
#if defined(HAVE_SOLID) || defined(HAVE_SOLID_30)
/* this seems to be necessary for Solid2.3 ( tested by
* tammy@synchronis.com) and Solid 3.0 (tested by eric@terra.telemediair.nl)
@@ -849,7 +870,11 @@ void odbc_column_lengths(INTERNAL_FUNCTION_PARAMETERS, int type)
RETURN_FALSE;
}
- PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)pv_num, (SQLUSMALLINT) (type?SQL_COLUMN_SCALE:SQL_COLUMN_PRECISION), NULL, 0, NULL, &len);
+ rc = PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)pv_num, (SQLUSMALLINT)(type ? SQL_COLUMN_SCALE : SQL_COLUMN_PRECISION), NULL, 0, NULL, &len);
+ if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
+ odbc_colattribute_failed(result, pv_num);
+ len = 0;
+ }
RETURN_LONG(len);
}
@@ -2597,6 +2622,7 @@ PHP_FUNCTION(odbc_field_type)
odbc_result *result;
char tmp[32];
SQLSMALLINT tmplen;
+ RETCODE rc;
zval *pv_res;
zend_long pv_num;
@@ -2622,7 +2648,13 @@ PHP_FUNCTION(odbc_field_type)
RETURN_FALSE;
}
- PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)pv_num, SQL_COLUMN_TYPE_NAME, tmp, 31, &tmplen, NULL);
+ tmp[0] = '\0';
+ rc = PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)pv_num, SQL_COLUMN_TYPE_NAME, tmp, sizeof(tmp) - 1, &tmplen, NULL);
+ if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
+ odbc_colattribute_failed(result, pv_num);
+ RETURN_FALSE;
+ }
+
RETURN_STRING(tmp);
}
/* }}} */