From 45655ca3eeac572c59739bf99807842122359524 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Mon, 19 Oct 2026 08:26:44 -0400 Subject: [PATCH] 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. --- NEWS | 2 + ext/pdo/pdo_dbh.c | 13 ++++-- ext/pdo/tests/pdo_oracle_nulls_invalid.phpt | 49 +++++++++++++++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 ext/pdo/tests/pdo_oracle_nulls_invalid.phpt diff --git a/NEWS b/NEWS index 0c80ffefb1b2..f21972ac6de7 100644 --- a/NEWS +++ b/NEWS @@ -77,6 +77,8 @@ PHP NEWS exits). (Lazizbek Ergashev) - 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 a8be45e15588..804cbb644077 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 000000000000..30b251e1915e --- /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-- + +--FILE-- +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)