Skip to content

Make PDO connection construction single-shot#22874

Open
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/pdo-guard-reconstruct
Open

Make PDO connection construction single-shot#22874
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:fix/pdo-guard-reconstruct

Conversation

@iliaal

@iliaal iliaal commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Constructing a PDO over an already constructed handle re-runs connection setup and, for a persistent connection, frees the pemalloc'd dbh with efree(), corrupting the heap. The same sink is also reachable by reentering __construct() from a uri: DSN stream wrapper or a failed connect()'s destructor, and by retrying a persistent construct that failed after swapping in the handle. This makes construction single-shot: an is_constructing flag (an ABI-neutral bit taken from _reserved_flags, sizeof(pdo_dbh_t) unchanged) is set as soon as the handle exists for both __construct() and connect(), and construction is rejected once the driver is attached or one is already in progress. Behavior change: a construct that fails now leaves the handle unusable instead of allowing a retry.

$pdo = new PDO('sqlite::memory:', null, null, [PDO::ATTR_PERSISTENT => true]);
$pdo->__construct('sqlite::memory:', null, null, [PDO::ATTR_PERSISTENT => true]); // heap corruption before this change

Constructing a PDO handle over an already constructed one re-ran
connection setup; for a persistent connection the second pass freed the
pemalloc'd dbh with efree() and corrupted the heap. Besides a plain
second __construct(), the same sink was reachable by reentering during a
uri: DSN stream open, by retrying a persistent construct that failed
after swapping in the persistent handle, and by a subclass destructor
reentering while a failed persistent connect() unwinds. Track
construction with an is_constructing flag, set as soon as the handle
exists for both __construct() and connect(), carried onto the persistent
handle and cleared only on success; construction is rejected once the
driver is attached or a construction is in progress. A construct that
fails now leaves the handle unusable instead of allowing a retry.
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.

1 participant