Commit bba94675f51 for php
commit bba94675f5107e0026c5cd47eea6d0087957d71f
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Mon Oct 19 08:26:44 2026 -0400
ext/pdo: Validate Oracle null handling modes
Reject unsupported ATTR_ORACLE_NULLS values before narrowing them into the
two-bit field, preserving the previous mode when validation fails. The
constructor and setAttribute() share this validation.
Closes GH-24431
diff --git a/NEWS b/NEWS
index 8771d8eae54..5f966a6ea0f 100644
--- a/NEWS
+++ b/NEWS
@@ -83,6 +83,8 @@ PHP NEWS
reference check). (ndossche)
- PDO:
+ . Fixed invalid ATTR_ORACLE_NULLS values being accepted and truncated.
+ (Ilia Alshanetsky)
. Fixed a duplicate warning when ATTR_STATEMENT_CLASS is rejected on a
persistent connection. (Ilia Alshanetsky)
diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c
index a8be45e1558..804cbb64407 100644
--- a/ext/pdo/pdo_dbh.c
+++ b/ext/pdo/pdo_dbh.c
@@ -854,9 +854,16 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /
if (!pdo_get_long_param(&lval, value)) {
return false;
}
- /* TODO Check for valid value (NULL_NATURAL, NULL_EMPTY_STRING, NULL_TO_STRING)? */
- dbh->oracle_nulls = lval;
- return true;
+ switch (lval) {
+ case PDO_NULL_NATURAL:
+ case PDO_NULL_EMPTY_STRING:
+ case PDO_NULL_TO_STRING:
+ dbh->oracle_nulls = lval;
+ return true;
+ default:
+ zend_value_error("PDO::ATTR_ORACLE_NULLS must be one of the PDO::NULL_* constants");
+ return false;
+ }
case PDO_ATTR_DEFAULT_FETCH_MODE:
if (Z_TYPE_P(value) == IS_ARRAY) {
diff --git a/ext/pdo/tests/pdo_oracle_nulls_invalid.phpt b/ext/pdo/tests/pdo_oracle_nulls_invalid.phpt
new file mode 100644
index 00000000000..30b251e1915
--- /dev/null
+++ b/ext/pdo/tests/pdo_oracle_nulls_invalid.phpt
@@ -0,0 +1,49 @@
+--TEST--
+PDO Common: Invalid Oracle null handling modes do not change the attribute
+--EXTENSIONS--
+pdo
+--SKIPIF--
+<?php
+$dir = getenv('REDIR_TEST_DIR');
+if ($dir === false) {
+ die('skip no driver');
+}
+require_once $dir . 'pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
+$pdo = PDOTest::factory();
+
+foreach ([PDO::NULL_NATURAL, PDO::NULL_EMPTY_STRING, PDO::NULL_TO_STRING] as $value) {
+ echo "Valid mode: ";
+ var_dump($pdo->setAttribute(PDO::ATTR_ORACLE_NULLS, $value));
+ var_dump($pdo->getAttribute(PDO::ATTR_ORACLE_NULLS));
+}
+
+foreach ([-1, 3, 4, PHP_INT_MAX] as $value) {
+ try {
+ $pdo->setAttribute(PDO::ATTR_ORACLE_NULLS, $value);
+ } catch (ValueError $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+ echo "Unchanged mode: ";
+ var_dump($pdo->getAttribute(PDO::ATTR_ORACLE_NULLS));
+}
+?>
+--EXPECT--
+Valid mode: bool(true)
+int(0)
+Valid mode: bool(true)
+int(1)
+Valid mode: bool(true)
+int(2)
+ValueError: PDO::ATTR_ORACLE_NULLS must be one of the PDO::NULL_* constants
+Unchanged mode: int(2)
+ValueError: PDO::ATTR_ORACLE_NULLS must be one of the PDO::NULL_* constants
+Unchanged mode: int(2)
+ValueError: PDO::ATTR_ORACLE_NULLS must be one of the PDO::NULL_* constants
+Unchanged mode: int(2)
+ValueError: PDO::ATTR_ORACLE_NULLS must be one of the PDO::NULL_* constants
+Unchanged mode: int(2)