Skip to content

Fix leak of driver_params argument of PDOStatement::bindParam() and bindColumn() - #23463

Open
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/pdo-bindparam-driverparams-leak-84
Open

Fix leak of driver_params argument of PDOStatement::bindParam() and bindColumn()#23463
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/pdo-bindparam-driverparams-leak-84

Conversation

@iliaal

@iliaal iliaal commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

PDOStatement::bindParam() and bindColumn() leak references on the driver_params argument: register_bound_param() never releases its transient copy, and really_register_bound_param() drops its hash-bound reference on neither of its two early failure returns, so 200k failing bindParam() calls grow memory by about 128MB and even successful calls leak one reference each. Both paths now release what they take; the EVT_ALLOC hook failure needed no change because deleting the hash entry frees it through param_dtor().

$obj = new C();
try {
$stmt->bindParam(1, $obj, PDO::PARAM_STR, 0, $dp);
} catch (Error $e) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry to use this to ask a question, but trying to understand the rational. Do you mind to make me understand why you sometimes decide not printing anything? Wouldn't the same argument as in #23041 (comment) apply here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loop would print it 20k times. Pinned class and message once.

register_bound_param() took a reference on the driver_params argument
but never released it: really_register_bound_param() ADDREFs another
reference for the bound-params hash, yet its early failure paths after
that point (rewrite_name_to_position(), PDO_PARAM_EVT_NORMALIZE hook)
and every return path of register_bound_param() itself dropped only
param.parameter, leaking one or two references per call. 200k failing
bindParam() calls grow memory by ~128MB. The transient copy is now
released on both failure and success, and really_register_bound_param()
releases its hash-bound reference on early failures; the
PDO_PARAM_EVT_ALLOC hook failure path already released it via the hash
dtor. Sibling audit: bindValue() and execute()'s input_params loop leave
driver_params undefined so the new releases are no-ops there.

Closes phpGH-23463
@iliaal
iliaal force-pushed the fix/pdo-bindparam-driverparams-leak-84 branch from 8199d65 to 6b819bd Compare August 26, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants