1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-17900 and GH-8084

Calling the constructor twice has no real world benefit.
Block it to fix these two issues.
We also clean up the constructor code a bit:
- `in_ctor` implies `object` exist.
- We surround the instance check with ZEND_DEBUG to avoid a runtime
  penalty.

Closes GH-17900.
Closes GH-8084.
Closes GH-17908.
This commit is contained in:
Niels Dossche
2025-02-23 17:42:04 +01:00
parent 0008a1e84b
commit 2b6c9b68bb
6 changed files with 41 additions and 7 deletions

4
NEWS
View File

@@ -56,6 +56,10 @@ PHP NEWS
. IntlDateFormatter::setTimeZone()/datefmt_set_timezone() throws an exception
with uninitialised classes or clone failure. (David Carlier)
- MySQLi:
. Fixed bugs GH-17900 and GH-8084 (calling mysqli::__construct twice).
(nielsdos)
- MySQLnd:
. Added mysqlnd.collect_memory_statistics to ini quick reference.
(hauk92)

View File

@@ -44,6 +44,10 @@ PHP 8.5 UPGRADE NOTES
. ldap_get_option() and ldap_set_option() now throw a ValueError when
passing an invalid option.
- MySQLi:
. Calling the mysqli constructor on an already-constructed object
is now no longer possible and throws an Error.
- PCNTL:
. pcntl_exec() now throws ValueErrors when entries of the $args parameter
contain null bytes.

View File

@@ -969,10 +969,6 @@ void php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS, bool is_method)
MYSQLI_RESOURCE *mysqli_resource;
MY_MYSQL *mysql;
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
if (is_method && (Z_MYSQLI_P(getThis()))->ptr) {
return;
}
@@ -1004,6 +1000,7 @@ void php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS, bool is_method)
/* {{{ Initialize mysqli and return a resource for use with mysql_real_connect */
PHP_FUNCTION(mysqli_init)
{
ZEND_PARSE_PARAMETERS_NONE();
php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
}
/* }}} */

View File

@@ -72,7 +72,14 @@ void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, bool is_real_connect, b
}
#endif
if (getThis() && !ZEND_NUM_ARGS() && in_ctor) {
if (in_ctor && !ZEND_NUM_ARGS()) {
ZEND_PARSE_PARAMETERS_NONE();
if (UNEXPECTED(Z_MYSQLI_P(object)->ptr)) {
zend_throw_error(NULL, "Cannot call constructor twice");
return;
}
php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, in_ctor);
return;
}
@@ -84,6 +91,11 @@ void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, bool is_real_connect, b
RETURN_THROWS();
}
if (UNEXPECTED(in_ctor && Z_MYSQLI_P(object)->ptr)) {
zend_throw_error(NULL, "Cannot call constructor twice");
return;
}
if (object) {
ZEND_ASSERT(instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry));
mysqli_resource = (Z_MYSQLI_P(object))->ptr;
@@ -325,6 +337,7 @@ PHP_METHOD(mysqli, __construct)
/* {{{ Initialize mysqli and return a resource for use with mysql_real_connect */
PHP_METHOD(mysqli, init)
{
ZEND_PARSE_PARAMETERS_NONE();
php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
}
/* }}} */

View File

@@ -0,0 +1,16 @@
--TEST--
GH-17900 (Assertion failure ext/mysqli/mysqli_prop.c)
--EXTENSIONS--
mysqli
--FILE--
<?php
mysqli_report(MYSQLI_REPORT_OFF);
$mysqli = new mysqli();
try {
$mysqli->__construct('doesnotexist');
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECT--
Cannot call constructor twice

View File

@@ -12,8 +12,8 @@ $mysqli->close();
?>
--EXPECTF--
Fatal error: Uncaught Error: mysqli object is not fully initialized in %s:%d
Fatal error: Uncaught Error: Cannot call constructor twice in %s:%d
Stack trace:
#0 %s(%d): mysqli->close()
#0 %s(%d): mysqli->__construct('doesnotexist')
#1 {main}
thrown in %s on line %d