diff --git a/NEWS b/NEWS index 4ed36d63b4f8..07336444bfc1 100644 --- a/NEWS +++ b/NEWS @@ -176,6 +176,10 @@ PHP NEWS . Fixed a duplicate warning when ATTR_STATEMENT_CLASS is rejected on a persistent connection. (Ilia Alshanetsky) +- PDO_Firebird: + . Fixed bug GH-25006 (getColumnMeta() reads out of bounds for an + out-of-range column index). (Ilia Alshanetsky) + - Phar: . Fixed bug GH-24740 (Oversized tar metadata exhausts the memory limit). (Lazizbek Ergashev) diff --git a/ext/pdo_firebird/firebird_statement.c b/ext/pdo_firebird/firebird_statement.c index b8802751bf9b..c166833c0006 100644 --- a/ext/pdo_firebird/firebird_statement.c +++ b/ext/pdo_firebird/firebird_statement.c @@ -342,9 +342,15 @@ static int pdo_firebird_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */ static int pdo_firebird_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zval *return_value) { pdo_firebird_stmt *S = (pdo_firebird_stmt *) stmt->driver_data; - XSQLVAR *var = &S->out_sqlda.sqlvar[colno]; - + XSQLVAR *var; enum pdo_param_type param_type; + + if (colno >= stmt->column_count) { + ZVAL_EMPTY_ARRAY(return_value); + return 1; + } + + var = &S->out_sqlda.sqlvar[colno]; if (var->sqlscale < 0) { param_type = PDO_PARAM_STR; } else { diff --git a/ext/pdo_firebird/tests/gh25006.phpt b/ext/pdo_firebird/tests/gh25006.phpt new file mode 100644 index 000000000000..d0e9918322a2 --- /dev/null +++ b/ext/pdo_firebird/tests/gh25006.phpt @@ -0,0 +1,73 @@ +--TEST-- +GH-25006 (PDO_Firebird::getColumnMeta() reads out of bounds for an out-of-range column index) +--EXTENSIONS-- +pdo_firebird +--SKIPIF-- + +--XLEAK-- +A bug in firebird causes a memory leak when calling `isc_attach_database()`. +See https://github.com/FirebirdSQL/firebird/issues/7849 +--FILE-- +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + +$stmt = $dbh->prepare('SELECT 1 AS one, 2 AS two FROM RDB$DATABASE'); + +echo "before execute: "; +try { + var_dump($stmt->getColumnMeta(2)); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +$stmt->execute(); + +echo "column 0: "; +$meta = $stmt->getColumnMeta(0); +echo $meta['name'], ' ', $meta['pdo_type'], "\n"; + +echo "column 1: "; +$meta = $stmt->getColumnMeta(1); +echo $meta['name'], ' ', $meta['pdo_type'], "\n"; + +foreach ([2, 1000000] as $col) { + echo "column $col: "; + try { + var_dump($stmt->getColumnMeta($col)); + } catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } +} + +echo "no output columns: "; +$empty = $dbh->prepare('EXECUTE BLOCK AS BEGIN END'); +echo $empty->columnCount(), ' '; +try { + var_dump($empty->getColumnMeta(0)); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +echo "negative: "; +try { + var_dump($stmt->getColumnMeta(-1)); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; +} + +echo "done\n"; +?> +--EXPECT-- +before execute: PDOException: SQLSTATE[07009]: Invalid descriptor index: invalid column index +column 0: ONE 1 +column 1: TWO 1 +column 2: PDOException: SQLSTATE[07009]: Invalid descriptor index: invalid column index +column 1000000: PDOException: SQLSTATE[07009]: Invalid descriptor index: invalid column index +no output columns: 0 PDOException: SQLSTATE[07009]: Invalid descriptor index: invalid column index +negative: ValueError: PDOStatement::getColumnMeta(): Argument #1 ($column) must be greater than or equal to 0 +done