Skip to content

Commit 8706cd4

Browse files
GH-22681: avoid truncation on null bytes in Reflection*::__toString()
Given that there is not an unchecked version of `smart_str_append_printf()`, to avoid compiler warnings from using `%S` to format `zend_string` pointers (which the smart string printing machinery supports, but printf does not support) in a few places the format specifier is declared in a variable rather than being specified directly in the `smart_str_append_printf()` call.
1 parent 1db6c84 commit 8706cd4

9 files changed

Lines changed: 59 additions & 32 deletions

ext/reflection/php_reflection.c

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,9 @@ static zval *reflection_instantiate(zend_class_entry *pce, zval *object) /* {{{
308308
}
309309
/* }}} */
310310

311-
static void _const_string(smart_str *str, const char *name, zval *value, const char *indent);
311+
static void _const_string(smart_str *str, const zend_string *name, zval *value, const char *indent);
312312
static void _function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, const char* indent);
313-
static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, const char* indent);
313+
static void _property_string(smart_str *str, zend_property_info *prop, const zend_string *prop_name, const char* indent);
314314
static void _class_const_string(smart_str *str, const zend_string *name, zend_class_constant *c, const char* indent);
315315
static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const char *indent);
316316
static void _extension_string(smart_str *str, const zend_module_entry *module, const char *indent);
@@ -324,7 +324,8 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
324324

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

@@ -494,7 +495,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
494495
if (prop_name && ZSTR_LEN(prop_name) && ZSTR_VAL(prop_name)[0]) { /* skip all private and protected properties */
495496
if (!zend_hash_exists(&ce->properties_info, prop_name)) {
496497
count++;
497-
_property_string(&prop_str, NULL, ZSTR_VAL(prop_name), ZSTR_VAL(sub_indent));
498+
_property_string(&prop_str, NULL, prop_name, ZSTR_VAL(sub_indent));
498499
}
499500
}
500501
} ZEND_HASH_FOREACH_END();
@@ -549,7 +550,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, const
549550
/* }}} */
550551

551552
/* {{{ _const_string */
552-
static void _const_string(smart_str *str, const char *name, zval *value, const char *indent)
553+
static void _const_string(smart_str *str, const zend_string *name, zval *value, const char *indent)
553554
{
554555
const char *type = zend_zval_type_name(value);
555556
uint32_t flags = Z_CONSTANT_FLAGS_P(value);
@@ -579,7 +580,7 @@ static void _const_string(smart_str *str, const char *name, zval *value, const c
579580

580581
smart_str_appends(str, type);
581582
smart_str_appendc(str, ' ');
582-
smart_str_appends(str, name);
583+
smart_str_append(str, name);
583584
smart_str_appends(str, " ] { ");
584585

585586
if (Z_TYPE_P(value) == IS_ARRAY) {
@@ -610,7 +611,9 @@ static void _class_const_string(smart_str *str, const zend_string *name, zend_cl
610611
const char *type = type_str ? ZSTR_VAL(type_str) : zend_zval_type_name(&c->value);
611612

612613
if (c->doc_comment) {
613-
smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(c->doc_comment));
614+
smart_str_appends(str, indent);
615+
smart_str_append(str, c->doc_comment);
616+
smart_str_appendc(str, '\n');
614617
}
615618
smart_str_append_printf(str, "%sConstant [ %s%s %s %s ] { ",
616619
indent, final, visibility, type, ZSTR_VAL(name));
@@ -827,9 +830,13 @@ static void _function_string(smart_str *str, zend_function *fptr, zend_class_ent
827830
* swallowed, leading to an unaligned comment.
828831
*/
829832
if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
830-
smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(fptr->op_array.doc_comment));
833+
smart_str_appends(str, indent);
834+
smart_str_append(str, fptr->op_array.doc_comment);
835+
smart_str_appendc(str, '\n');
831836
} else if (fptr->type == ZEND_INTERNAL_FUNCTION && fptr->internal_function.doc_comment) {
832-
smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(fptr->internal_function.doc_comment));
837+
smart_str_appends(str, indent);
838+
smart_str_append(str, fptr->internal_function.doc_comment);
839+
smart_str_appendc(str, '\n');
833840
}
834841

835842
smart_str_appendl(str, indent, strlen(indent));
@@ -939,14 +946,18 @@ static zval *property_get_default(zend_property_info *prop_info) {
939946
}
940947

941948
/* {{{ _property_string */
942-
static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, const char* indent)
949+
static void _property_string(smart_str *str, zend_property_info *prop, const zend_string *prop_name, const char* indent)
943950
{
944951
if (prop && prop->doc_comment) {
945-
smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(prop->doc_comment));
952+
smart_str_appends(str, indent);
953+
smart_str_append(str, prop->doc_comment);
954+
smart_str_appendc(str, '\n');
946955
}
947956
smart_str_append_printf(str, "%sProperty [ ", indent);
948957
if (!prop) {
949-
smart_str_append_printf(str, "<dynamic> public $%s", prop_name);
958+
ZEND_ASSERT(prop_name && "Properties without info must have a name provided");
959+
smart_str_appends(str, "<dynamic> public $");
960+
smart_str_append(str, prop_name);
950961
} else {
951962
if (prop->flags & ZEND_ACC_ABSTRACT) {
952963
smart_str_appends(str, "abstract ");
@@ -989,11 +1000,15 @@ static void _property_string(smart_str *str, zend_property_info *prop, const cha
9891000
smart_str_appendc(str, ' ');
9901001
zend_string_release(type_str);
9911002
}
1003+
smart_str_appendc(str, '$');
9921004
if (!prop_name) {
9931005
const char *class_name;
994-
zend_unmangle_property_name(prop->name, &class_name, &prop_name);
1006+
const char *prop_name_cstr;
1007+
zend_unmangle_property_name(prop->name, &class_name, &prop_name_cstr);
1008+
smart_str_appends(str, prop_name_cstr);
1009+
} else {
1010+
smart_str_append(str, prop_name);
9951011
}
996-
smart_str_append_printf(str, "$%s", prop_name);
9971012

9981013
zval *default_value = property_get_default(prop);
9991014
if (default_value && !Z_ISUNDEF_P(default_value)) {
@@ -1031,9 +1046,21 @@ static void _extension_ini_string(const zend_ini_entry *ini_entry, smart_str *st
10311046
}
10321047

10331048
smart_str_appends(str, "> ]\n");
1034-
smart_str_append_printf(str, " %s Current = '%s'\n", indent, ini_entry->value ? ZSTR_VAL(ini_entry->value) : "");
1049+
if (ini_entry->value) {
1050+
smart_str_append_printf(str, " %s Current = '", indent);
1051+
smart_str_append(str, ini_entry->value);
1052+
smart_str_appends(str, "'\n");
1053+
} else {
1054+
smart_str_append_printf(str, " %s Current = ''\n", indent);
1055+
}
10351056
if (ini_entry->modified) {
1036-
smart_str_append_printf(str, " %s Default = '%s'\n", indent, ini_entry->orig_value ? ZSTR_VAL(ini_entry->orig_value) : "");
1057+
if (ini_entry->orig_value) {
1058+
smart_str_append_printf(str, " %s Default = '", indent);
1059+
smart_str_append(str, ini_entry->orig_value);
1060+
smart_str_appends(str, "'\n");
1061+
} else {
1062+
smart_str_append_printf(str, " %s Default = ''\n", indent);
1063+
}
10371064
}
10381065
smart_str_append_printf(str, " %s}\n", indent);
10391066
}
@@ -1122,7 +1149,7 @@ static void _extension_string(smart_str *str, const zend_module_entry *module, c
11221149

11231150
ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) {
11241151
if (ZEND_CONSTANT_MODULE_NUMBER(constant) == module->module_number) {
1125-
_const_string(&str_constants, ZSTR_VAL(constant->name), &constant->value, " ");
1152+
_const_string(&str_constants, constant->name, &constant->value, " ");
11261153
num_constants++;
11271154
}
11281155
} ZEND_HASH_FOREACH_END();
@@ -5894,7 +5921,7 @@ ZEND_METHOD(ReflectionProperty, __toString)
58945921
RETURN_THROWS();
58955922
}
58965923
GET_REFLECTION_OBJECT_PTR(ref);
5897-
_property_string(&str, ref->prop, ZSTR_VAL(ref->unmangled_name), "");
5924+
_property_string(&str, ref->prop, ref->unmangled_name, "");
58985925
RETURN_STR(smart_str_extract(&str));
58995926
}
59005927
/* }}} */
@@ -7955,7 +7982,7 @@ ZEND_METHOD(ReflectionConstant, __toString)
79557982
}
79567983

79577984
GET_REFLECTION_OBJECT_PTR(const_);
7958-
_const_string(&str, ZSTR_VAL(const_->name), &const_->value, "");
7985+
_const_string(&str, const_->name, &const_->value, "");
79597986
RETURN_STR(smart_str_extract(&str));
79607987
}
79617988

ext/reflection/tests/gh22681/ReflectionClassConstant_doc_comment.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ echo new ReflectionClass(Demo::class);
1919

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

2828
- Constants [1] {
29-
/** F
29+
/** F%0oo */
3030
Constant [ public bool DEMO ] { 1 }
3131
}
3232

ext/reflection/tests/gh22681/ReflectionClass_doc_comment.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ var_dump( $r->getDocComment() );
1515

1616
?>
1717
--EXPECTF--
18-
/** F
18+
/** F%0oo */
1919
Class [ <user> class Demo ] {
2020
@@ %s(%d) : eval()'d code %d-%d
2121

ext/reflection/tests/gh22681/ReflectionConstant_name.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ var_dump( $r->getName() );
1111

1212
?>
1313
--EXPECTF--
14-
Constant [ bool F ] { 1 }
14+
Constant [ bool F%0oo ] { 1 }
1515
string(4) "F%0oo"

ext/reflection/tests/gh22681/ReflectionEnum_case_doc_comment.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Class [ <user> final class Demo implements UnitEnum ] {
2020
@@ %s(%d) : eval()'d code %d-%d
2121

2222
- Constants [1] {
23-
/** F
23+
/** F%0oo */
2424
Constant [ public Demo C ] { Object }
2525
}
2626

ext/reflection/tests/gh22681/ReflectionExtension_ini_value.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ var_dump( $r->getINIEntries()['arg_separator.output'] );
1616
?>
1717
--EXPECTF--
1818
Entry [ arg_separator.output <ALL> ]
19-
Current = 'f'
19+
Current = 'f%0oo'
2020
Default = '&'
2121
}
2222

ext/reflection/tests/gh22681/ReflectionFunctionAbstract_doc_comment.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ var_dump( $r->getDocComment() );
2424

2525
?>
2626
--EXPECTF--
27-
/** F
27+
/** F%0oo */
2828
Function [ <user> function demo ] {
2929
@@ %s(%d) : eval()'d code %d - %d
3030
}
3131
string(11) "/** F%0oo */"
32-
/** B
32+
/** B%0ar */
3333
Method [ <user> public method demo ] {
3434
@@ %s(%d) : eval()'d code %d - %d
3535
}

ext/reflection/tests/gh22681/ReflectionProperty_doc_comment.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ echo new ReflectionClass(Demo::class);
1919

2020
?>
2121
--EXPECTF--
22-
/** F
22+
/** F%0oo */
2323
Property [ public $prop = NULL ]
2424
string(11) "/** F%0oo */"
2525
Class [ <user> class Demo ] {
@@ -35,7 +35,7 @@ Class [ <user> class Demo ] {
3535
}
3636

3737
- Properties [1] {
38-
/** F
38+
/** F%0oo */
3939
Property [ public $prop = NULL ]
4040
}
4141

ext/reflection/tests/gh22681/ReflectionProperty_dynamic_name.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ var_dump( $r->getDocComment() );
1111
echo new ReflectionObject($obj);
1212

1313
?>
14-
--EXPECT--
15-
Property [ <dynamic> public $F ]
14+
--EXPECTF--
15+
Property [ <dynamic> public $F%0oo ]
1616
bool(false)
1717
Object of class [ <internal:Core> class stdClass ] {
1818

@@ -29,7 +29,7 @@ Object of class [ <internal:Core> class stdClass ] {
2929
}
3030

3131
- Dynamic properties [1] {
32-
Property [ <dynamic> public $F ]
32+
Property [ <dynamic> public $F%0oo ]
3333
}
3434

3535
- Methods [0] {

0 commit comments

Comments
 (0)