Skip to content
Open
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
13 changes: 8 additions & 5 deletions Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -1772,7 +1772,6 @@ ZEND_API void zend_free_recorded_errors(void)
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format, ...) /* {{{ */
{
va_list va;
char *message = NULL;

if (!exception_ce) {
exception_ce = zend_ce_error;
Expand All @@ -1784,16 +1783,20 @@ ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const c
}

va_start(va, format);
zend_vspprintf(&message, 0, format, va);
zend_string *message = zend_vstrpprintf(0, format, va);

//TODO: we can't convert compile-time errors to exceptions yet???
if (EG(current_execute_data) && !CG(in_compilation)) {
zend_throw_exception(exception_ce, message, 0);
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
// Use "%S" so that the message can contain null bytes.
const char *format = "%S";
zend_throw_exception_ex(exception_ce, 0, format, message);
} else {
zend_error_noreturn(E_ERROR, "%s", message);
zend_error_noreturn(E_ERROR, "%s", ZSTR_VAL(message));
}

efree(message);
zend_string_release(message);
va_end(va);
}
/* }}} */
Expand Down
7 changes: 3 additions & 4 deletions Zend/zend_exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -888,14 +888,13 @@ ZEND_API ZEND_COLD zend_object *zend_throw_exception(zend_class_entry *exception
ZEND_API ZEND_COLD zend_object *zend_throw_exception_ex(zend_class_entry *exception_ce, zend_long code, const char *format, ...) /* {{{ */
{
va_list arg;
char *message;
zend_object *obj;

va_start(arg, format);
zend_vspprintf(&message, 0, format, arg);
zend_string *msg_str = zend_vstrpprintf(0, format, arg);
va_end(arg);
obj = zend_throw_exception(exception_ce, message, code);
efree(message);
obj = zend_throw_exception_zstr(exception_ce, msg_str, code);
zend_string_release(msg_str);
return obj;
}
/* }}} */
Expand Down
138 changes: 113 additions & 25 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -1298,7 +1298,10 @@ static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attribut
if (name && (flags & REFLECTION_ATTRIBUTE_IS_INSTANCEOF)) {
if (NULL == (base = zend_lookup_class(name))) {
if (!EG(exception)) {
zend_throw_error(NULL, "Class \"%s\" not found", ZSTR_VAL(name));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Class \"%S\" not found";
zend_throw_error(NULL, format, name);
}

RETURN_THROWS();
Expand Down Expand Up @@ -1704,8 +1707,11 @@ ZEND_METHOD(ReflectionFunction, __construct)
}

if (fptr == NULL) {
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Function %S() does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Function %s() does not exist", ZSTR_VAL(fname));
format, fname);
RETURN_THROWS();
}
}
Expand Down Expand Up @@ -2522,8 +2528,11 @@ ZEND_METHOD(ReflectionParameter, __construct)
zend_string_release(lcname);
}
if (!fptr) {
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Function %S() does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Function %s() does not exist", Z_STRVAL_P(reference));
format, Z_STR_P(reference));
RETURN_THROWS();
}
ce = fptr->common.scope;
Expand All @@ -2550,8 +2559,11 @@ ZEND_METHOD(ReflectionParameter, __construct)
return;
}
if ((ce = zend_lookup_class(name)) == NULL) {
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Class \"%S\" does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Class \"%s\" does not exist", ZSTR_VAL(name));
format, name);
zend_string_release(name);
RETURN_THROWS();
}
Expand All @@ -2570,8 +2582,11 @@ ZEND_METHOD(ReflectionParameter, __construct)
/* nothing to do. don't set is_closure since is the invoke handler,
not the closure itself */
} else if ((fptr = zend_hash_find_ptr(&ce->function_table, lcname)) == NULL) {
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Method %S::%S() does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
format, ce->name, name);
zend_string_release(name);
zend_string_release(lcname);
RETURN_THROWS();
Expand Down Expand Up @@ -3388,7 +3403,10 @@ static void instantiate_reflection_method(INTERNAL_FUNCTION_PARAMETERS, bool is_
if (class_name) {
if ((ce = zend_lookup_class(class_name)) == NULL) {
if (!EG(exception)) {
zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(class_name));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Class \"%S\" does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0, format, class_name);
}
zend_string_release(class_name);
RETURN_THROWS();
Expand All @@ -3414,8 +3432,16 @@ static void instantiate_reflection_method(INTERNAL_FUNCTION_PARAMETERS, bool is_
/* do nothing, mptr already set */
} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, method_name_len)) == NULL) {
efree(lcname);
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Method %S::%S() does not exist";
ALLOCA_FLAG(use_heap);
zend_string *method_name_zstr;
ZSTR_ALLOCA_INIT(method_name_zstr, method_name, method_name_len, use_heap);
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Method %s::%s() does not exist", ZSTR_VAL(ce->name), method_name);
format, ce->name, method_name_zstr);
ZSTR_ALLOCA_FREE(method_name_zstr, use_heap);

RETURN_THROWS();
}
efree(lcname);
Expand Down Expand Up @@ -3919,7 +3945,10 @@ ZEND_METHOD(ReflectionClassConstant, __construct)
ce = classname_obj->ce;
} else {
if ((ce = zend_lookup_class(classname_str)) == NULL) {
zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(classname_str));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Class \"%S\" does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0, format, classname_str);
RETURN_THROWS();
}
}
Expand All @@ -3928,7 +3957,10 @@ ZEND_METHOD(ReflectionClassConstant, __construct)
intern = Z_REFLECTION_P(object);

if ((constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), constname)) == NULL) {
zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(constname));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Constant %S::%S does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, constname);
RETURN_THROWS();
}

Expand Down Expand Up @@ -4208,7 +4240,10 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob
} else {
if ((ce = zend_lookup_class(arg_class)) == NULL) {
if (!EG(exception)) {
zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%s\" does not exist", ZSTR_VAL(arg_class));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Class \"%S\" does not exist";
zend_throw_exception_ex(reflection_exception_ptr, -1, format, arg_class);
}
RETURN_THROWS();
}
Expand Down Expand Up @@ -4348,8 +4383,11 @@ ZEND_METHOD(ReflectionClass, getStaticPropertyValue)
RETURN_COPY(def_value);
}

// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Property %S::$%S does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Property %s::$%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
format, ce->name, name);
}
/* }}} */

Expand Down Expand Up @@ -4377,8 +4415,11 @@ ZEND_METHOD(ReflectionClass, setStaticPropertyValue)
EG(fake_scope) = old_scope;
if (!variable_ptr) {
zend_clear_exception();
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Class %S does not have a property named %S";
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Class %s does not have a property named %s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
format, ce->name, name);
RETURN_THROWS();
}

Expand Down Expand Up @@ -4642,8 +4683,11 @@ ZEND_METHOD(ReflectionClass, getMethod)
} else if ((mptr = zend_hash_find_ptr(&ce->function_table, lc_name)) != NULL) {
reflection_method_factory(ce, mptr, NULL, return_value);
} else {
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Method %S::%S() does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
format, ce->name, name);
}
zend_string_release(lc_name);
}
Expand Down Expand Up @@ -4769,7 +4813,9 @@ ZEND_METHOD(ReflectionClass, getProperty)
}
}
str_name = ZSTR_VAL(name);
bool fully_qualified = false;
if ((tmp = strstr(ZSTR_VAL(name), "::")) != NULL) {
fully_qualified = true;
classname_len = tmp - ZSTR_VAL(name);
classname = zend_string_init(ZSTR_VAL(name), classname_len, 0);
str_name_len = ZSTR_LEN(name) - (classname_len + 2);
Expand All @@ -4786,7 +4832,15 @@ ZEND_METHOD(ReflectionClass, getProperty)
zend_string_release_ex(classname, 0);

if (!instanceof_function(ce, ce2)) {
zend_throw_exception_ex(reflection_exception_ptr, -1, "Fully qualified property name %s::$%s does not specify a base class of %s", ZSTR_VAL(ce2->name), str_name, ZSTR_VAL(ce->name));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Fully qualified property name %S::$%S does not specify a base class of %S";
ALLOCA_FLAG(use_heap);
zend_string *prop_name_zstr;
ZSTR_ALLOCA_INIT(prop_name_zstr, str_name, str_name_len, use_heap);
zend_throw_exception_ex(reflection_exception_ptr, -1, format, ce2->name, prop_name_zstr, ce->name);
ZSTR_ALLOCA_FREE(prop_name_zstr, use_heap);

RETURN_THROWS();
}
ce = ce2;
Expand All @@ -4799,7 +4853,19 @@ ZEND_METHOD(ReflectionClass, getProperty)
return;
}
}
zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %s::$%s does not exist", ZSTR_VAL(ce->name), str_name);
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Property %S::$%S does not exist";
// Can only use the existing `name` string if it wasn't fully qualified
if (fully_qualified) {
ALLOCA_FLAG(use_heap);
zend_string *prop_name_zstr;
ZSTR_ALLOCA_INIT(prop_name_zstr, str_name, str_name_len, use_heap);
zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, prop_name_zstr);
ZSTR_ALLOCA_FREE(prop_name_zstr, use_heap);
} else {
zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, name);
}
}
/* }}} */

Expand Down Expand Up @@ -5665,7 +5731,10 @@ ZEND_METHOD(ReflectionClass, isSubclassOf)
class_ce = argument->ptr;
} else {
if ((class_ce = zend_lookup_class(class_str)) == NULL) {
zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(class_str));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Class \"%S\" does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0, format, class_str);
RETURN_THROWS();
}
}
Expand Down Expand Up @@ -5698,7 +5767,10 @@ ZEND_METHOD(ReflectionClass, implementsInterface)
interface_ce = argument->ptr;
} else {
if ((interface_ce = zend_lookup_class(interface_str)) == NULL) {
zend_throw_exception_ex(reflection_exception_ptr, 0, "Interface \"%s\" does not exist", ZSTR_VAL(interface_str));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Interface \"%S\" does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0, format, interface_str);
RETURN_THROWS();
}
}
Expand Down Expand Up @@ -5866,7 +5938,10 @@ ZEND_METHOD(ReflectionProperty, __construct)
ce = classname_obj->ce;
} else {
if ((ce = zend_lookup_class(classname_str)) == NULL) {
zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(classname_str));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Class \"%S\" does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0, format, classname_str);
RETURN_THROWS();
}
}
Expand All @@ -5882,7 +5957,10 @@ ZEND_METHOD(ReflectionProperty, __construct)
}
}
if (dynam_prop == 0) {
zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %s::$%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Property %S::$%S does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, name);
RETURN_THROWS();
}
}
Expand Down Expand Up @@ -6244,13 +6322,17 @@ static zend_result reflection_property_check_lazy_compatible(
zend_property_info *prop, zend_string *unmangled_name,
reflection_object *intern, zend_object *object, const char *method)
{
if (!prop) {
if (!prop) {
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Can not use %s on dynamic property %S::$%S";
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Can not use %s on dynamic property %s::$%s",
method, ZSTR_VAL(intern->ce->name),
ZSTR_VAL(unmangled_name));
format,
method, intern->ce->name,
unmangled_name);
return FAILURE;
}
// Non-dynamic properties cannot have null bytes so %s is fine

if (prop->flags & ZEND_ACC_STATIC) {
zend_throw_exception_ex(reflection_exception_ptr, 0,
Expand Down Expand Up @@ -7569,7 +7651,10 @@ ZEND_METHOD(ReflectionEnum, getCase)

zend_class_constant *constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name);
if (constant == NULL) {
zend_throw_exception_ex(reflection_exception_ptr, 0, "Case %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Case %S::%S does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0, format, ce->name, name);
RETURN_THROWS();
}
if (!(ZEND_CLASS_CONST_FLAGS(constant) & ZEND_CLASS_CONST_IS_CASE)) {
Expand Down Expand Up @@ -7879,7 +7964,10 @@ ZEND_METHOD(ReflectionConstant, __construct)
zend_constant *const_ = zend_get_constant_ptr(lc_name);
zend_string_release_ex(lc_name, /* persistent */ false);
if (!const_) {
zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant \"%s\" does not exist", ZSTR_VAL(name));
// %S is used for zend_string pointers by smart str printing, but normally
// is for wide character strings and so compilers complain if this is inline
const char *format = "Constant \"%S\" does not exist";
zend_throw_exception_ex(reflection_exception_ptr, 0, format, name);
RETURN_THROWS();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
GH-22905: null bytes in ReflectionClassConstant::__construct() error messages (class name)
--FILE--
<?php

new ReflectionClassConstant("foo\0bar", "");

?>
--EXPECTF--
Fatal error: Uncaught ReflectionException: Class "foo%0bar" does not exist in %s:%d
Stack trace:
#0 %s(%d): ReflectionClassConstant->__construct('foo\x00bar', '')
#1 {main}
thrown in %s on line %d
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
GH-22905: null bytes in ReflectionClassConstant::__construct() error messages (constant name)
--FILE--
<?php

class Demo {}
new ReflectionClassConstant(Demo::class, "foo\0bar");

?>
--EXPECTF--
Fatal error: Uncaught ReflectionException: Constant Demo::foo%0bar does not exist in %s:%d
Stack trace:
#0 %s(%d): ReflectionClassConstant->__construct('Demo', 'foo\x00bar')
#1 {main}
thrown in %s on line %d
Loading
Loading