Skip to content

Commit 2b6c9b6

Browse files
committed
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 phpGH-17900. Closes phpGH-8084. Closes phpGH-17908.
1 parent 0008a1e commit 2b6c9b6

File tree

6 files changed

+41
-7
lines changed

6 files changed

+41
-7
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ PHP NEWS
5656
. IntlDateFormatter::setTimeZone()/datefmt_set_timezone() throws an exception
5757
with uninitialised classes or clone failure. (David Carlier)
5858

59+
- MySQLi:
60+
. Fixed bugs GH-17900 and GH-8084 (calling mysqli::__construct twice).
61+
(nielsdos)
62+
5963
- MySQLnd:
6064
. Added mysqlnd.collect_memory_statistics to ini quick reference.
6165
(hauk92)

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ PHP 8.5 UPGRADE NOTES
4444
. ldap_get_option() and ldap_set_option() now throw a ValueError when
4545
passing an invalid option.
4646

47+
- MySQLi:
48+
. Calling the mysqli constructor on an already-constructed object
49+
is now no longer possible and throws an Error.
50+
4751
- PCNTL:
4852
. pcntl_exec() now throws ValueErrors when entries of the $args parameter
4953
contain null bytes.

ext/mysqli/mysqli_api.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -969,10 +969,6 @@ void php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS, bool is_method)
969969
MYSQLI_RESOURCE *mysqli_resource;
970970
MY_MYSQL *mysql;
971971

972-
if (zend_parse_parameters_none() == FAILURE) {
973-
RETURN_THROWS();
974-
}
975-
976972
if (is_method && (Z_MYSQLI_P(getThis()))->ptr) {
977973
return;
978974
}
@@ -1004,6 +1000,7 @@ void php_mysqli_init(INTERNAL_FUNCTION_PARAMETERS, bool is_method)
10041000
/* {{{ Initialize mysqli and return a resource for use with mysql_real_connect */
10051001
PHP_FUNCTION(mysqli_init)
10061002
{
1003+
ZEND_PARSE_PARAMETERS_NONE();
10071004
php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
10081005
}
10091006
/* }}} */

ext/mysqli/mysqli_nonapi.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,14 @@ void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, bool is_real_connect, b
7272
}
7373
#endif
7474

75-
if (getThis() && !ZEND_NUM_ARGS() && in_ctor) {
75+
if (in_ctor && !ZEND_NUM_ARGS()) {
76+
ZEND_PARSE_PARAMETERS_NONE();
77+
78+
if (UNEXPECTED(Z_MYSQLI_P(object)->ptr)) {
79+
zend_throw_error(NULL, "Cannot call constructor twice");
80+
return;
81+
}
82+
7683
php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, in_ctor);
7784
return;
7885
}
@@ -84,6 +91,11 @@ void mysqli_common_connect(INTERNAL_FUNCTION_PARAMETERS, bool is_real_connect, b
8491
RETURN_THROWS();
8592
}
8693

94+
if (UNEXPECTED(in_ctor && Z_MYSQLI_P(object)->ptr)) {
95+
zend_throw_error(NULL, "Cannot call constructor twice");
96+
return;
97+
}
98+
8799
if (object) {
88100
ZEND_ASSERT(instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry));
89101
mysqli_resource = (Z_MYSQLI_P(object))->ptr;
@@ -325,6 +337,7 @@ PHP_METHOD(mysqli, __construct)
325337
/* {{{ Initialize mysqli and return a resource for use with mysql_real_connect */
326338
PHP_METHOD(mysqli, init)
327339
{
340+
ZEND_PARSE_PARAMETERS_NONE();
328341
php_mysqli_init(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
329342
}
330343
/* }}} */

ext/mysqli/tests/gh17900.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
GH-17900 (Assertion failure ext/mysqli/mysqli_prop.c)
3+
--EXTENSIONS--
4+
mysqli
5+
--FILE--
6+
<?php
7+
mysqli_report(MYSQLI_REPORT_OFF);
8+
$mysqli = new mysqli();
9+
try {
10+
$mysqli->__construct('doesnotexist');
11+
} catch (Error $e) {
12+
echo $e->getMessage(), "\n";
13+
}
14+
?>
15+
--EXPECT--
16+
Cannot call constructor twice

ext/mysqli/tests/mysqli_incomplete_initialization.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ $mysqli->close();
1212

1313
?>
1414
--EXPECTF--
15-
Fatal error: Uncaught Error: mysqli object is not fully initialized in %s:%d
15+
Fatal error: Uncaught Error: Cannot call constructor twice in %s:%d
1616
Stack trace:
17-
#0 %s(%d): mysqli->close()
17+
#0 %s(%d): mysqli->__construct('doesnotexist')
1818
#1 {main}
1919
thrown in %s on line %d

0 commit comments

Comments
 (0)