Skip to content

Commit

Permalink
Fix phpGH-16131: prevent subclass ctor/driver connection string mismatch
Browse files Browse the repository at this point in the history
We now use the create driver-specific codepath without an object to
change, so we go through the exceptions thrown there when there's any
mismatches between the class being used and the connection string.

The class entry fetch in the entry points was also wrong and did not
get a valid class entry, this was also fixed.

A test was added for this, although I'm not pleased by the fact it needs
two real PDO drivers. A better way to test this would be nice, although
it does match the original sample case.
  • Loading branch information
NattyNarwhal committed Sep 30, 2024
1 parent b32a941 commit 4e5fa34
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 5 deletions.
17 changes: 12 additions & 5 deletions ext/pdo/pdo_dbh.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ static bool create_driver_specific_pdo_object(pdo_driver_t *driver, zend_class_e
}

/* A driver-specific implementation was instantiated via the connect() method of the appropriate driver class */
object_init_ex(new_object, ce_based_on_called_object);
if (new_object)
object_init_ex(new_object, ce_based_on_called_object);
return true;
} else {
zend_throw_exception_ex(pdo_exception_ce, 0,
Expand All @@ -266,10 +267,12 @@ static bool create_driver_specific_pdo_object(pdo_driver_t *driver, zend_class_e
}

/* A driver-specific implementation was instantiated via PDO::__construct() */
object_init_ex(new_object, ce_based_on_driver_name);
if (new_object)
object_init_ex(new_object, ce_based_on_driver_name);
} else {
/* No driver-specific implementation found */
object_init_ex(new_object, called_scope);
if (new_object)
object_init_ex(new_object, called_scope);
}

return true;
Expand Down Expand Up @@ -351,6 +354,10 @@ static void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object

dbh = Z_PDO_DBH_P(new_zval_object);
} else {
if (!create_driver_specific_pdo_object(driver, current_scope, NULL)) {
RETURN_THROWS();
}

dbh = php_pdo_dbh_fetch_inner(object);
}

Expand Down Expand Up @@ -497,14 +504,14 @@ static void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object
/* {{{ */
PHP_METHOD(PDO, __construct)
{
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), EX(This).value.ce, NULL);
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), Z_OBJ(EX(This))->ce, NULL);
}
/* }}} */

/* {{{ */
PHP_METHOD(PDO, connect)
{
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), EX(This).value.ce, return_value);
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), Z_OBJ(EX(This))->ce, return_value);
}
/* }}} */

Expand Down
20 changes: 20 additions & 0 deletions ext/pdo/tests/gh-16131.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
--TEST--
GH-16131: Can use wrong driver in connection string with driver subclass
--EXTENSIONS--
pdo
pdo_mysql
pdo_sqlite
--FILE--
<?php

// XXX: The fact we need two specific drivers makes this test annoying,
// since we need two real drivers (or it gives a diff error for missing)
// can it be done better?
$db = new Pdo\Mysql('sqlite::memory:');
var_dump($db->getAttribute(PDO::ATTR_DRIVER_NAME));
--EXPECTF--
Fatal error: Uncaught PDOException: Pdo\%s::connect() cannot be called when connecting to the "%s" driver, either Pdo\%s::connect() or PDO::connect() must be called instead in %s:%d
Stack trace:
#0 %s(%d): PDO->__construct('%s')
#1 {main}
thrown in %s on line %d

0 comments on commit 4e5fa34

Please sign in to comment.