Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions Zend/tests/bug70914.phpt

This file was deleted.

2 changes: 1 addition & 1 deletion Zend/tests/get_class_vars/get_class_vars_001.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ array(2) {
["aa"]=>
int(4)
}
get_class_vars(): Argument #1 ($class) must be a valid class name, Unknown given
get_class_vars(): Argument #1 ($class) must be a valid class name, "Unknown" given
6 changes: 3 additions & 3 deletions Zend/tests/get_parent_class_basic.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ bool(false)
string(3) "foo"
bool(false)
bool(false)
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, string given
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, string given
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, string given
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, "" given
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, "[[[[" given
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, " " given
bool(false)
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, array given
get_parent_class(): Argument #1 ($object_or_class) must be an object or a valid class name, int given
Expand Down
15 changes: 15 additions & 0 deletions Zend/tests/zpp/bug70914.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Bug #70914 zend_throw_or_error() format string vulnerability
--EXTENSIONS--
zend_test
--FILE--
<?php

try {
var_dump(zend_class_name('%Z'));
} catch (TypeError $e) {
echo $e::class, ': ', $e->getMessage(), "\n";
}
?>
--EXPECT--
TypeError: zend_class_name(): Argument #1 ($param) must be a valid class name, "%Z" given
192 changes: 92 additions & 100 deletions Zend/tests/zpp/class-string_zpp_specifier_strict_mode.phpt

Large diffs are not rendered by default.

196 changes: 92 additions & 104 deletions Zend/tests/zpp/class-string_zpp_specifier_weak_mode.phpt

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions Zend/tests/zpp/obj_or_class_name_zpp_strict_mode.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ Using 73.5:
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, float given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, float given
Using 'string':
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, string given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, string given
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, "string" given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, "string" given
Using '15':
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, string given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, string given
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, "15" given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, "15" given
Using '56.7':
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, string given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, string given
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, "56.7" given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, "56.7" given
Using 'stdClass':
string(8) "stdClass"
string(8) "stdClass"
Expand Down
12 changes: 6 additions & 6 deletions Zend/tests/zpp/obj_or_class_name_zpp_weak_mode.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ Using 73.5:
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, float given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, float given
Using 'string':
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, string given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, string given
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, "string" given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, "string" given
Using '15':
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, string given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, string given
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, "15" given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, "15" given
Using '56.7':
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, string given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, string given
TypeError: zend_obj_or_class_name(): Argument #1 ($param) must be an object or a valid class name, "56.7" given
TypeError: zend_obj_or_class_name_or_null(): Argument #1 ($param) must be an object, a valid class name, or null, "56.7" given
Using 'stdClass':
string(8) "stdClass"
string(8) "stdClass"
Expand Down
62 changes: 43 additions & 19 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,16 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(uint32_t n
return;
}

if (Z_TYPE_P(arg) == IS_STRING && (
expected_type == Z_EXPECTED_CLASS_NAME ||
expected_type == Z_EXPECTED_CLASS_NAME_OR_NULL ||
expected_type == Z_EXPECTED_OBJECT_OR_CLASS_NAME ||
expected_type == Z_EXPECTED_OBJECT_OR_CLASS_NAME_OR_NULL
)) {
zend_argument_type_error(num, "must be %s, \"%s\" given", expected_error[expected_type], Z_STRVAL_P(arg));
return;
}

zend_argument_type_error(num, "must be %s, %s given", expected_error[expected_type], zend_zval_value_name(arg));
}
/* }}} */
Expand Down Expand Up @@ -492,23 +502,28 @@ ZEND_API bool ZEND_FASTCALL zend_parse_arg_class(zval *arg, zend_class_entry **p
*pce = NULL;
return 1;
}
zend_string *class_name;
if (!zend_parse_arg_str(arg, &class_name, check_null, num)) {
*pce = NULL;
zend_wrong_parameter_error(ZPP_ERROR_WRONG_ARG, num, NULL, check_null ? Z_EXPECTED_STRING_OR_NULL : Z_EXPECTED_STRING, arg);
return 0;
/* Only accept string and Stringable(?) as int/foat/bool are not valid class names */
if (UNEXPECTED(Z_TYPE_P(arg) != IS_STRING)) {
if (Z_TYPE_P(arg) != IS_OBJECT || !zend_parse_arg_str_slow(arg, num)) {
*pce = NULL;
zend_wrong_parameter_type_error(num, check_null ? Z_EXPECTED_CLASS_NAME_OR_NULL : Z_EXPECTED_CLASS_NAME, arg);
return 0;
}
/* Object was converted to string */
ZEND_ASSERT(Z_TYPE_P(arg) == IS_STRING);
}
zend_string *class_name = Z_STR_P(arg);

*pce = zend_lookup_class(class_name);
if (ce_base) {
if ((!*pce || !instanceof_function(*pce, ce_base))) {
zend_argument_type_error(num, "must be a class name derived from %s, %s given", ZSTR_VAL(ce_base->name), ZSTR_VAL(class_name));
zend_argument_type_error(num, "must be a class name derived from %s, \"%s\" given", ZSTR_VAL(ce_base->name), ZSTR_VAL(class_name));
*pce = NULL;
return 0;
}
}
if (!*pce) {
zend_argument_type_error(num, "must be a valid class name, %s given", ZSTR_VAL(class_name));
zend_wrong_parameter_type_error(num, check_null ? Z_EXPECTED_CLASS_NAME_OR_NULL : Z_EXPECTED_CLASS_NAME, arg);
return 0;
}
return 1;
Expand Down Expand Up @@ -1020,33 +1035,42 @@ static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec

case 'C':
{
zend_class_entry *lookup, **pce = va_arg(*va, zend_class_entry **);
zend_class_entry *ce_base = *pce;
zend_class_entry **pce = va_arg(*va, zend_class_entry **);
const zend_class_entry *ce_base = *pce;

if (check_null && Z_TYPE_P(arg) == IS_NULL) {
*pce = NULL;
break;
}
if (!try_convert_to_string(arg)) {
*pce = NULL;
return ""; /* try_convert_to_string() throws an exception */
}

if ((lookup = zend_lookup_class(Z_STR_P(arg))) == NULL) {
*pce = NULL;
} else {
*pce = lookup;
/* Only accept string and Stringable(?) as int/foat/bool are not valid class names */
if (UNEXPECTED(Z_TYPE_P(arg) != IS_STRING)) {
if (Z_TYPE_P(arg) != IS_OBJECT || !zend_parse_arg_str_slow(arg, arg_num)) {
*pce = NULL;
/* __toString may throw */
if (!EG(exception)) {
zend_spprintf(error, 0, "must be a valid class name%s, %s given",
check_null ? " or null" : "", zend_zval_value_name(arg));
}
*pce = NULL;
return "";
}
/* Object was converted to string */
ZEND_ASSERT(Z_TYPE_P(arg) == IS_STRING);
}
zend_string *class_name = Z_STR_P(arg);

*pce = zend_lookup_class(class_name);
if (ce_base) {
if ((!*pce || !instanceof_function(*pce, ce_base))) {
zend_spprintf(error, 0, "must be a class name derived from %s%s, %s given",
zend_spprintf(error, 0, "must be a class name derived from %s%s, \"%s\" given",
ZSTR_VAL(ce_base->name), check_null ? " or null" : "", Z_STRVAL_P(arg));
*pce = NULL;
return "";
}
}
if (!*pce) {
zend_spprintf(error, 0, "must be a valid class name%s, %s given",
zend_spprintf(error, 0, "must be a valid class name%s, \"%s\" given",
check_null ? " or null" : "", Z_STRVAL_P(arg));
return "";
}
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -1569,6 +1569,8 @@ static zend_always_inline zval *zend_try_array_init(zval *zv)
_(Z_EXPECTED_ARRAY_OR_STRING_OR_NULL, "of type array|string|null") \
_(Z_EXPECTED_STRING_OR_LONG, "of type string|int") \
_(Z_EXPECTED_STRING_OR_LONG_OR_NULL, "of type string|int|null") \
_(Z_EXPECTED_CLASS_NAME, "a valid class name") \
_(Z_EXPECTED_CLASS_NAME_OR_NULL, "a valid class name or null") \
_(Z_EXPECTED_OBJECT_OR_CLASS_NAME, "an object or a valid class name") \
_(Z_EXPECTED_OBJECT_OR_CLASS_NAME_OR_NULL, "an object, a valid class name, or null") \
_(Z_EXPECTED_OBJECT_OR_STRING, "of type object|string") \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ $dom->registerNodeClass("Dom\\HTMLDocument", "DOMDocument");

?>
--EXPECTF--
Fatal error: Uncaught TypeError: DOMDocument::registerNodeClass(): Argument #1 ($baseClass) must be a class name derived from DOMNode, Dom\HTMLDocument given in %s:%d
Fatal error: Uncaught TypeError: DOMDocument::registerNodeClass(): Argument #1 ($baseClass) must be a class name derived from DOMNode, "Dom\HTMLDocument" given in %s:%d
Stack trace:
#0 %s(%d): DOMDocument->registerNodeClass('Dom\\HTMLDocumen...', 'DOMDocument')
#1 {main}
Expand Down
2 changes: 1 addition & 1 deletion ext/mysqli/tests/mysqli_fetch_object.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,5 @@ NULL
NULL
mysqli_result object is already closed
TypeError: mysqli_fetch_object(): Argument #3 ($constructor_args) must be of type array, string given
TypeError: mysqli_fetch_object(): Argument #2 ($class) must be a valid class name, this_class_does_not_exist given
TypeError: mysqli_fetch_object(): Argument #2 ($class) must be a valid class name, "this_class_does_not_exist" given
done!
4 changes: 2 additions & 2 deletions ext/mysqli/tests/mysqli_fetch_object_oo.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,12 @@ require_once 'skipifconnectfailure.inc';
require_once 'clean_table.inc';
?>
--EXPECT--
Error: Object of class mysqli could not be converted to string
TypeError: mysqli_result::fetch_object(): Argument #1 ($class) must be a valid class name, mysqli given
ArgumentCountError: mysqli_result::fetch_object() expects at most 2 arguments, 3 given
TypeError: mysqli_result::fetch_object(): Argument #2 ($constructor_args) must be of type array, null given
ArgumentCountError: Too few arguments to function mysqli_fetch_object_construct::__construct(), 1 passed and exactly 2 expected
NULL
NULL
Error: mysqli_result object is already closed
TypeError: mysqli_result::fetch_object(): Argument #1 ($class) must be a valid class name, this_class_does_not_exist given
TypeError: mysqli_result::fetch_object(): Argument #1 ($class) must be a valid class name, "this_class_does_not_exist" given
done!
2 changes: 1 addition & 1 deletion ext/pdo_mysql/tests/pdo_mysql_stmt_fetchobject.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,5 @@ object(myclass)#%d (4) {
["null"]=>
NULL
}
PDOStatement::fetchObject(): Argument #1 ($class) must be a valid class name, class_does_not_exist given
PDOStatement::fetchObject(): Argument #1 ($class) must be a valid class name or null, "class_does_not_exist" given
done!
2 changes: 1 addition & 1 deletion ext/pgsql/tests/22pg_fetch_object.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,5 @@ object(test_class)#%d (3) {
["bin"]=>
NULL
}
pg_fetch_object(): Argument #3 ($class) must be a valid class name, does_not_exist given
pg_fetch_object(): Argument #3 ($class) must be a valid class name, "does_not_exist" given
Ok
2 changes: 1 addition & 1 deletion ext/phar/tests/phar_oo_006.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ unlink(__DIR__ . '/files/phar_oo_006.phar.php');
__halt_compiler();
?>
--EXPECTF--
TypeError: SplFileInfo::setFileClass(): Argument #1 ($class) must be a class name derived from SplFileObject, SplFileInfo given
TypeError: SplFileInfo::setFileClass(): Argument #1 ($class) must be a class name derived from SplFileObject, "SplFileInfo" given
MyFile::__construct(phar://%s/a.php)
a.php
MyFile::__construct(phar://%s/b/c.php)
Expand Down
39 changes: 38 additions & 1 deletion ext/snmp/snmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ typedef struct snmp_session php_snmp_session;
} \
}

static bool mib_needs_reset;

ZEND_DECLARE_MODULE_GLOBALS(snmp)
static PHP_GINIT_FUNCTION(snmp);

Expand Down Expand Up @@ -1658,6 +1660,7 @@ PHP_FUNCTION(snmp_read_mib)
RETURN_THROWS();
}

mib_needs_reset = 1;
if (!read_mib(filename)) {
char *error = strerror(errno);
php_error_docref(NULL, E_WARNING, "Error while reading MIB file '%s': %s", filename, error);
Expand All @@ -1667,6 +1670,27 @@ PHP_FUNCTION(snmp_read_mib)
}
/* }}} */

/* {{{ Resets the MIB tree and set the mib directories to the provided mibdirs. */
PHP_FUNCTION(snmp_init_mib)
{
zend_string *mibdirs = NULL;

ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_PATH_STR_OR_NULL(mibdirs)
ZEND_PARSE_PARAMETERS_END();

// If the mibdirs has been changed, we need to reset the MIB tree at the end of the request
if (mibdirs != NULL) {
mib_needs_reset = 1;
}

shutdown_mib();
netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIBDIRS, ZSTR_VAL(mibdirs));
init_mib();
}
/* }}} */

/* {{{ Creates a new SNMP session to specified host. */
PHP_METHOD(SNMP, __construct)
{
Expand Down Expand Up @@ -2201,6 +2225,19 @@ PHP_MSHUTDOWN_FUNCTION(snmp)
}
/* }}} */

/* {{{ PHP_RSHUTDOWN_FUNCTION */
static PHP_RSHUTDOWN_FUNCTION(snmp)
{
if (mib_needs_reset) {
shutdown_mib();
netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIBDIRS, NULL);
init_mib();
}

return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(snmp)
{
Expand Down Expand Up @@ -2228,7 +2265,7 @@ zend_module_entry snmp_module_entry = {
PHP_MINIT(snmp),
PHP_MSHUTDOWN(snmp),
NULL,
NULL,
PHP_RSHUTDOWN(snmp),
PHP_MINFO(snmp),
PHP_SNMP_VERSION,
PHP_MODULE_GLOBALS(snmp),
Expand Down
2 changes: 2 additions & 0 deletions ext/snmp/snmp.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ function snmp_get_valueretrieval(): int {}

function snmp_read_mib(string $filename): bool {}

function snmp_init_mib(?string $mibdirs): void {}

/** @not-serializable */
class SNMP
{
Expand Down
8 changes: 7 additions & 1 deletion ext/snmp/snmp_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions ext/spl/tests/ArrayObject/arrayObject___construct_error1.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ try {
?>
--EXPECT--
Bad iterator type:
TypeError: ArrayObject::__construct(): Argument #3 ($iteratorClass) must be a class name derived from ArrayIterator, Exception given
TypeError: ArrayObject::__construct(): Argument #3 ($iteratorClass) must be a class name derived from ArrayIterator, "Exception" given
Non-existent class:
TypeError: ArrayObject::__construct(): Argument #3 ($iteratorClass) must be a class name derived from ArrayIterator, nonExistentClassName given
TypeError: ArrayObject::__construct(): Argument #3 ($iteratorClass) must be a class name derived from ArrayIterator, "nonExistentClassName" given
Loading