Skip to content

Commit 2b6c9b6

Browse files
committed
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.
1 parent 0008a1e commit 2b6c9b6

File tree

6 files changed

+41
-7
lines changed

6 files changed

+41
-7
lines changed

NEWS

+4
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

+4
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

+1-4
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

+14-1
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

+16
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

+2-2
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)