[PDO] Bound-check column index in getColumnMeta() - #23654
Conversation
| } catch (ValueError $e) { | ||
| echo get_class($e), ': ', $e->getMessage(), "\n"; | ||
| } | ||
|
|
||
| $stmt->execute(); | ||
| var_dump($stmt->getColumnMeta(0)); | ||
|
|
||
| try { | ||
| var_dump($stmt->getColumnMeta(5)); | ||
| } catch (ValueError $e) { | ||
| echo get_class($e), ': ', $e->getMessage(), "\n"; | ||
| } |
There was a problem hiding this comment.
| } catch (ValueError $e) { | |
| echo get_class($e), ': ', $e->getMessage(), "\n"; | |
| } | |
| $stmt->execute(); | |
| var_dump($stmt->getColumnMeta(0)); | |
| try { | |
| var_dump($stmt->getColumnMeta(5)); | |
| } catch (ValueError $e) { | |
| echo get_class($e), ': ', $e->getMessage(), "\n"; | |
| } | |
| } catch (Throwable $e) { | |
| echo $e::class, ': ', $e->getMessage(), "\n"; | |
| } | |
| $stmt->execute(); | |
| var_dump($stmt->getColumnMeta(0)); | |
| try { | |
| var_dump($stmt->getColumnMeta(5)); | |
| } catch (Throwable $e) { | |
| echo $e::class, ': ', $e->getMessage(), "\n"; | |
| } |
There was a problem hiding this comment.
Took the $e::class part. The thrown type changed to PDOException in the meantime, and ext/pdo tests catch that rather than Throwable.
| if (stmt->columns == NULL || colno >= stmt->column_count) { | ||
| zend_value_error("Invalid column index"); | ||
| RETURN_THROWS(); | ||
| } |
There was a problem hiding this comment.
Would this make sense?
| if (stmt->columns == NULL || colno >= stmt->column_count) { | |
| zend_value_error("Invalid column index"); | |
| RETURN_THROWS(); | |
| } | |
| if (stmt->columns == NULL || colno >= stmt->column_count) { | |
| pdo_raise_impl_error(stmt->dbh, stmt, "07009", "invalid column index"); | |
| RETURN_FALSE; | |
| } |
07009 (Invalid descriptor index) seems like a good fit for this case.
There was a problem hiding this comment.
Adopted. Added a zval_ptr_dtor(return_value) with it, since the hook has already built the array and RETURN_FALSE would otherwise drop it.
The guard sits after the hook though, so it does not cover pdo_firebird, which indexes out_sqlda.sqlvar[colno] unchecked and then returns 1. I would fix that driver-side like GH-17837 rather than move the guard ahead of the hook, since that would change what the bound-checking drivers return. Sound right?
PDOStatement::getColumnMeta() indexed stmt->columns as soon as the driver hook reported success, without checking that the columns had been described or that the index was in range, so pdo_odbc, whose hook always reports success, read out of bounds and crashed. Raise SQLSTATE 07009 and return false instead, matching what the drivers that bound-check the index in their own hook already return.
731ecbc to
cb00636
Compare
PDOStatement::getColumnMeta() indexed columns as soon as the driver hook succeeded, without checking that columns had been described or that the index was in range, so a driver that reports success unconditionally (pdo_odbc) segfaulted on an unexecuted statement. Both cases now raise ValueError, matching the fetch paths. Drivers that report failure themselves still return false.