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
1 change: 1 addition & 0 deletions .github/actions/apt-x64/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ runs:
snmp-mibs-downloader \
freetds-dev \
unixodbc-dev \
libsqliteodbc \
llvm \
clang \
dovecot-core \
Expand Down
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ PHP NEWS
- Reflection:
. Fixed bug GH-22683 (Reflection(Class)Constant::__toString() should not warn
on NAN conversions). (Khaled Alam)
. Fixed bug GH-22681 (Reflection*::__toString() truncates on null bytes).
(DanielEScherzer)

- Session:
. Fixed bug GH-21314 (Different session garbage collector behavior between
Expand All @@ -103,6 +105,8 @@ PHP NEWS
do_request() parameters). (David Carlier)
. Fixed xsd:hexBinary decoding to reject odd-length values instead of
silently truncating the last nibble. (Weilin Du)
. Made SOAP encoding errors report the affected type or failing operation
instead of the generic "Violation of encoding rules" message. (Weilin Du)

- Standard:
. Fixed sleep() and usleep() to reject values that overflow the underlying
Expand Down
4 changes: 4 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ PHP 8.6 UPGRADE NOTES
. WSDL/XML Schema parsing now rejects out-of-range integer values for
occurrence constraints and integer restriction facets. Negative minOccurs
and maxOccurs values are rejected as well.
. SOAP encoding errors now report the affected type or failing operation in
the error message instead of the generic "Encoding: Violation of encoding
rules" message. Code that compares the exact message may need to be
updated.

- Sodium:
. The password-hashing functions sodium_crypto_pwhash(),
Expand Down
65 changes: 46 additions & 19 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,9 @@ static zend_object *reflection_objects_new(zend_class_entry *class_type) /* {{{
}
/* }}} */

static void _const_string(smart_str *str, const char *name, zval *value, const char *indent);
static void _const_string(smart_str *str, const zend_string *name, zval *value, const char *indent);
static void _function_string(smart_str *str, const zend_function *fptr, const zend_class_entry *scope, const char* indent);
static void _property_string(smart_str *str, const zend_property_info *prop, const char *prop_name, const char* indent);
static void _property_string(smart_str *str, const zend_property_info *prop, const zend_string *prop_name, const char* indent);
static void _class_const_string(smart_str *str, const zend_string *name, zend_class_constant *c, const char* indent);
static void _enum_case_string(smart_str *str, const zend_string *name, zend_class_constant *c, const char* indent);
static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const char *indent);
Expand All @@ -311,7 +311,8 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const

/* TBD: Repair indenting of doc comment (or is this to be done in the parser?) */
if (ce->doc_comment) {
smart_str_append_printf(str, "%s%s", indent, ZSTR_VAL(ce->doc_comment));
smart_str_appends(str, indent);
smart_str_append(str, ce->doc_comment);
smart_str_appendc(str, '\n');
}

Expand Down Expand Up @@ -517,7 +518,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
if (prop_name && ZSTR_LEN(prop_name) && ZSTR_VAL(prop_name)[0]) { /* skip all private and protected properties */
if (!zend_hash_exists(&ce->properties_info, prop_name)) {
count++;
_property_string(&prop_str, NULL, ZSTR_VAL(prop_name), ZSTR_VAL(sub_indent));
_property_string(&prop_str, NULL, prop_name, ZSTR_VAL(sub_indent));
}
}
} ZEND_HASH_FOREACH_END();
Expand Down Expand Up @@ -572,7 +573,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
/* }}} */

/* {{{ _const_string */
static void _const_string(smart_str *str, const char *name, zval *value, const char *indent)
static void _const_string(smart_str *str, const zend_string *name, zval *value, const char *indent)
{
const char *type = zend_zval_type_name(value);
uint32_t flags = Z_CONSTANT_FLAGS_P(value);
Expand Down Expand Up @@ -602,7 +603,7 @@ static void _const_string(smart_str *str, const char *name, zval *value, const c

smart_str_appends(str, type);
smart_str_appendc(str, ' ');
smart_str_appends(str, name);
smart_str_append(str, name);
smart_str_appends(str, " ] { ");

if (Z_TYPE_P(value) == IS_ARRAY) {
Expand Down Expand Up @@ -635,7 +636,9 @@ static void _class_const_string(smart_str *str, const zend_string *name, zend_cl
const char *type = type_str ? ZSTR_VAL(type_str) : zend_zval_type_name(&c->value);

if (c->doc_comment) {
smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(c->doc_comment));
smart_str_appends(str, indent);
smart_str_append(str, c->doc_comment);
smart_str_appendc(str, '\n');
}
smart_str_append_printf(str, "%sConstant [ %s%s %s %s ] { ",
indent, final, visibility, type, ZSTR_VAL(name));
Expand Down Expand Up @@ -869,9 +872,13 @@ static void _function_string(smart_str *str, const zend_function *fptr, const ze
* swallowed, leading to an unaligned comment.
*/
if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(fptr->op_array.doc_comment));
smart_str_appends(str, indent);
smart_str_append(str, fptr->op_array.doc_comment);
smart_str_appendc(str, '\n');
} else if (fptr->type == ZEND_INTERNAL_FUNCTION && fptr->internal_function.doc_comment) {
smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(fptr->internal_function.doc_comment));
smart_str_appends(str, indent);
smart_str_append(str, fptr->internal_function.doc_comment);
smart_str_appendc(str, '\n');
}

smart_str_appends(str, indent);
Expand Down Expand Up @@ -979,14 +986,18 @@ static zval *property_get_default(const zend_property_info *prop_info) {
}

/* {{{ _property_string */
static void _property_string(smart_str *str, const zend_property_info *prop, const char *prop_name, const char* indent)
static void _property_string(smart_str *str, const zend_property_info *prop, const zend_string *prop_name, const char* indent)
{
if (prop && prop->doc_comment) {
smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(prop->doc_comment));
smart_str_appends(str, indent);
smart_str_append(str, prop->doc_comment);
smart_str_appendc(str, '\n');
}
smart_str_append_printf(str, "%sProperty [ ", indent);
if (!prop) {
smart_str_append_printf(str, "<dynamic> public $%s", prop_name);
ZEND_ASSERT(prop_name && "Properties without info must have a name provided");
smart_str_appends(str, "<dynamic> public $");
smart_str_append(str, prop_name);
} else {
if (prop->flags & ZEND_ACC_ABSTRACT) {
smart_str_appends(str, "abstract ");
Expand Down Expand Up @@ -1032,11 +1043,15 @@ static void _property_string(smart_str *str, const zend_property_info *prop, con
smart_str_appendc(str, ' ');
zend_string_release(type_str);
}
smart_str_appendc(str, '$');
if (!prop_name) {
const char *class_name;
zend_unmangle_property_name(prop->name, &class_name, &prop_name);
const char *prop_name_cstr;
zend_unmangle_property_name(prop->name, &class_name, &prop_name_cstr);
smart_str_appends(str, prop_name_cstr);
} else {
smart_str_append(str, prop_name);
}
smart_str_append_printf(str, "$%s", prop_name);

const zval *default_value = property_get_default(prop);
if (default_value && !Z_ISUNDEF_P(default_value)) {
Expand Down Expand Up @@ -1092,9 +1107,21 @@ static void _extension_ini_string(const zend_ini_entry *ini_entry, smart_str *st
}

smart_str_appends(str, "> ]\n");
smart_str_append_printf(str, " Current = '%s'\n", ini_entry->value ? ZSTR_VAL(ini_entry->value) : "");
if (ini_entry->value) {
smart_str_appends(str, " Current = '");
smart_str_append(str, ini_entry->value);
smart_str_appends(str, "'\n");
} else {
smart_str_appends(str, " Current = ''\n");
}
if (ini_entry->modified) {
smart_str_append_printf(str, " Default = '%s'\n", ini_entry->orig_value ? ZSTR_VAL(ini_entry->orig_value) : "");
if (ini_entry->orig_value) {
smart_str_appends(str, " Default = '");
smart_str_append(str, ini_entry->orig_value);
smart_str_appends(str, "'\n");
} else {
smart_str_appends(str, " Default = ''\n");
}
}
smart_str_appends(str, " }\n");
}
Expand Down Expand Up @@ -1183,7 +1210,7 @@ static void _extension_string(smart_str *str, const zend_module_entry *module) /

ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) {
if (ZEND_CONSTANT_MODULE_NUMBER(constant) == module->module_number) {
_const_string(&str_constants, ZSTR_VAL(constant->name), &constant->value, " ");
_const_string(&str_constants, constant->name, &constant->value, " ");
num_constants++;
}
} ZEND_HASH_FOREACH_END();
Expand Down Expand Up @@ -5744,7 +5771,7 @@ ZEND_METHOD(ReflectionProperty, __toString)

ZEND_PARSE_PARAMETERS_NONE();
GET_REFLECTION_OBJECT_PTR(ref);
_property_string(&str, ref->prop, ZSTR_VAL(ref->unmangled_name), "");
_property_string(&str, ref->prop, ref->unmangled_name, "");
RETURN_STR(smart_str_extract(&str));
}
/* }}} */
Expand Down Expand Up @@ -8167,7 +8194,7 @@ ZEND_METHOD(ReflectionConstant, __toString)
ZEND_PARSE_PARAMETERS_NONE();

GET_REFLECTION_OBJECT_PTR(const_);
_const_string(&str, ZSTR_VAL(const_->name), &const_->value, "");
_const_string(&str, const_->name, &const_->value, "");
RETURN_STR(smart_str_extract(&str));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
--TEST--
GH-22681: null bytes in doc comment truncate ReflectionClassConstant::__toString()
--FILE--
<?php

eval(<<<END
class Demo {
/** F\0oo */
public const DEMO = true;
}
END
);

$r = new ReflectionClassConstant(Demo::class, 'DEMO');
echo $r;
var_dump( $r->getDocComment() );

echo new ReflectionClass(Demo::class);

?>
--EXPECTF--
/** F%0oo */
Constant [ public bool DEMO ] { 1 }
string(11) "/** F%0oo */"
Class [ <user> class Demo ] {
@@ %s(%d) : eval()'d code %d-%d

- Constants [1] {
/** F%0oo */
Constant [ public bool DEMO ] { 1 }
}

- Static properties [0] {
}

- Static methods [0] {
}

- Properties [0] {
}

- Methods [0] {
}
}
37 changes: 37 additions & 0 deletions ext/reflection/tests/gh22681/ReflectionClass_doc_comment.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--TEST--
GH-22681: null bytes in doc comment truncate ReflectionClass::__toString()
--FILE--
<?php

eval(<<<END
/** F\0oo */
class Demo {}
END
);

$r = new ReflectionClass(Demo::class);
echo $r;
var_dump( $r->getDocComment() );

?>
--EXPECTF--
/** F%0oo */
Class [ <user> class Demo ] {
@@ %s(%d) : eval()'d code %d-%d

- Constants [0] {
}

- Static properties [0] {
}

- Static methods [0] {
}

- Properties [0] {
}

- Methods [0] {
}
}
string(11) "/** F%0oo */"
15 changes: 15 additions & 0 deletions ext/reflection/tests/gh22681/ReflectionConstant_name.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
GH-22681: null bytes in name truncate ReflectionConstant::__toString()
--FILE--
<?php

define("F\0oo", true);

$r = new ReflectionConstant("F\0oo");
echo $r;
var_dump( $r->getName() );

?>
--EXPECTF--
Constant [ bool F%0oo ] { 1 }
string(4) "F%0oo"
49 changes: 49 additions & 0 deletions ext/reflection/tests/gh22681/ReflectionEnum_case_doc_comment.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
--TEST--
GH-22681: null bytes in doc comment truncate ReflectionEnum::__toString()
--FILE--
<?php

eval(<<<END
enum Demo {
/** F\0oo */
case C;
}
END
);

$r = new ReflectionEnum(Demo::class);
echo $r;
var_dump( new ReflectionEnumUnitCase(Demo::class, 'C')->getDocComment() );
?>
--EXPECTF--
Enum [ <user> enum Demo implements UnitEnum ] {
@@ %s(%d) : eval()'d code %d-%d

- Enum cases [1] {
/** F
Case C
}

- Constants [0] {
}

- Static properties [0] {
}

- Static methods [1] {
Method [ <internal, prototype UnitEnum> static public method cases ] {

- Parameters [0] {
}
- Return [ array ]
}
}

- Properties [1] {
Property [ public protected(set) readonly string $name ]
}

- Methods [0] {
}
}
string(11) "/** F%0oo */"
23 changes: 23 additions & 0 deletions ext/reflection/tests/gh22681/ReflectionExtension_ini_value.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
GH-22681: null bytes in INI values truncate ReflectionExtension::__toString()
--FILE--
<?php

ini_set('arg_separator.output', "f\0oo");
$r = new ReflectionExtension('core');
$str = (string)$r;
$index = strpos($str, 'Entry [ arg_separator.output');
$str = substr($str, $index);
$index = strpos($str, 'Entry', 1);
$str = substr($str, 0, $index);
echo $str . "\n";
var_dump( $r->getINIEntries()['arg_separator.output'] );

?>
--EXPECTF--
Entry [ arg_separator.output <ALL> ]
Current = 'f%0oo'
Default = '&'
}

string(4) "f%0oo"
Loading