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
5 changes: 4 additions & 1 deletion NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.5.0beta1

- Reflection:
. Fixed bug GH-17927 (Reflection: have some indication of property hooks in
`_property_string()`). (DanielEScherzer)

31 Jul 2025, PHP 8.5.0alpha4

Expand Down Expand Up @@ -298,7 +301,7 @@ PHP NEWS
(DanielEScherzer)
. Fixed bug GH-12856 (ReflectionClass::getStaticPropertyValue() returns UNDEF
zval for uninitialized typed properties). (nielsdos)
. Fixed bug GH-15766 (ReflectionClass::toString() should have better output
. Fixed bug GH-15766 (ReflectionClass::__toString() should have better output
for enums). (DanielEScherzer)
. Added ReflectionProperty::getMangledName() method. (alexandre-daubois)

Expand Down
7 changes: 6 additions & 1 deletion UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -391,9 +391,14 @@ PHP 8.5 UPGRADE NOTES
argument are lower than -1 or if soft_limit is greater than hard_limit.

- Reflection:
. The output of ReflectionClass::toString() for enums has changed to
. The output of ReflectionClass::__toString() for enums has changed to
better indicate that the class is an enum, and that the enum cases
are enum cases rather than normal class constants.
. The output of ReflectionProperty::__toString() for properties with
hooks has changed to indicate what hooks the property has, whether those
hooks are final, and whether the property is virtual. This also affects
the output of ReflectionClass::__toString() when a class contains hooked
properties.

- Session:
. session_start is stricter in regard to the option argument.
Expand Down
24 changes: 24 additions & 0 deletions Zend/tests/gh18736.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
GH-18736: Circumvented type check with return by ref + finally
--FILE--
<?php

function &test(): int {
$x = 0;
try {
return $x;
} finally {
$x = 'test';
}
}

try {
$x = &test();
var_dump($x);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECT--
test(): Return value must be of type int, string returned
8 changes: 4 additions & 4 deletions Zend/tests/lazy_objects/skipLazyInitialization.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -227,15 +227,15 @@ getValue(): NULL
setRawValueWithoutLazyInitialization():
getValue(): string(5) "value"

## Property [ public $hooked = NULL ]
## Property [ public $hooked = NULL { get; set; } ]

skipInitializerForProperty():
getValue(): NULL

setRawValueWithoutLazyInitialization():
getValue(): string(5) "value"

## Property [ public $virtual ]
## Property [ public virtual $virtual { get; set; } ]

skipInitializerForProperty():
ReflectionException: Can not use skipLazyInitialization on virtual property A::$virtual
Expand Down Expand Up @@ -324,15 +324,15 @@ getValue(): NULL
setRawValueWithoutLazyInitialization():
getValue(): string(5) "value"

## Property [ public $hooked = NULL ]
## Property [ public $hooked = NULL { get; set; } ]

skipInitializerForProperty():
getValue(): NULL

setRawValueWithoutLazyInitialization():
getValue(): string(5) "value"

## Property [ public $virtual ]
## Property [ public virtual $virtual { get; set; } ]

skipInitializerForProperty():
ReflectionException: Can not use skipLazyInitialization on virtual property A::$virtual
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -2326,7 +2326,7 @@ static zend_always_inline bool zend_parse_arg_string(zval *arg, char **dest, siz
static zend_always_inline bool zend_parse_arg_path_str(zval *arg, zend_string **dest, bool check_null, uint32_t arg_num)
{
if (!zend_parse_arg_str(arg, dest, check_null, arg_num) ||
(*dest && UNEXPECTED(CHECK_NULL_PATH(ZSTR_VAL(*dest), ZSTR_LEN(*dest))))) {
(*dest && UNEXPECTED(zend_str_has_nul_byte(*dest)))) {
return 0;
}
return 1;
Expand Down
12 changes: 12 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -5699,8 +5699,20 @@ static void zend_compile_return(zend_ast *ast) /* {{{ */
expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1, 0);
}

uint32_t opnum_before_finally = get_next_op_number();

zend_handle_loops_and_finally((expr_node.op_type & (IS_TMP_VAR | IS_VAR)) ? &expr_node : NULL);

/* Content of reference might have changed in finally, repeat type check. */
if (by_ref
/* Check if any opcodes were emitted since the last return type check. */
&& opnum_before_finally != get_next_op_number()
&& !is_generator
&& (CG(active_op_array)->fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
zend_emit_return_type_check(
expr_ast ? &expr_node : NULL, CG(active_op_array)->arg_info - 1, 0);
}

opline = zend_emit_op(NULL, by_ref ? ZEND_RETURN_BY_REF : ZEND_RETURN,
&expr_node, NULL);

Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -5211,7 +5211,7 @@ static zend_never_inline zend_op_array* ZEND_FASTCALL zend_include_or_eval(zval
}
} else if (UNEXPECTED(EG(exception))) {
break;
} else if (UNEXPECTED(strlen(ZSTR_VAL(inc_filename)) != ZSTR_LEN(inc_filename))) {
} else if (UNEXPECTED(zend_str_has_nul_byte(inc_filename))) {
zend_message_dispatcher(
(type == ZEND_INCLUDE_ONCE) ?
ZMSG_FAILED_INCLUDE_FOPEN : ZMSG_FAILED_REQUIRE_FOPEN,
Expand Down Expand Up @@ -5245,7 +5245,7 @@ static zend_never_inline zend_op_array* ZEND_FASTCALL zend_include_or_eval(zval
break;
case ZEND_INCLUDE:
case ZEND_REQUIRE:
if (UNEXPECTED(strlen(ZSTR_VAL(inc_filename)) != ZSTR_LEN(inc_filename))) {
if (UNEXPECTED(zend_str_has_nul_byte(inc_filename))) {
zend_message_dispatcher(
(type == ZEND_INCLUDE) ?
ZMSG_FAILED_INCLUDE_FOPEN : ZMSG_FAILED_REQUIRE_FOPEN,
Expand Down
2 changes: 1 addition & 1 deletion ext/mbstring/mbstring.c
Original file line number Diff line number Diff line change
Expand Up @@ -4506,7 +4506,7 @@ PHP_FUNCTION(mb_send_mail)
ZEND_PARSE_PARAMETERS_END();

if (str_headers) {
if (strlen(ZSTR_VAL(str_headers)) != ZSTR_LEN(str_headers)) {
if (UNEXPECTED(zend_str_has_nul_byte(str_headers))) {
zend_argument_value_error(4, "must not contain any null bytes");
RETURN_THROWS();
}
Expand Down
36 changes: 17 additions & 19 deletions ext/odbc/php_odbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,21 +346,21 @@ static void _close_odbc_pconn(zend_resource *rsrc)
/* {{{ PHP_INI_DISP(display_link_nums) */
static PHP_INI_DISP(display_link_nums)
{
char *value;
const zend_string *value;

if (type == PHP_INI_DISPLAY_ORIG && ini_entry->modified) {
value = ZSTR_VAL(ini_entry->orig_value);
value = ini_entry->orig_value;
} else if (ini_entry->value) {
value = ZSTR_VAL(ini_entry->value);
value = ini_entry->value;
} else {
value = NULL;
}

if (value) {
if (atoi(value) == -1) {
if (atoi(ZSTR_VAL(value)) == -1) {
PUTS("Unlimited");
} else {
php_printf("%s", value);
php_output_write(ZSTR_VAL(value), ZSTR_LEN(value));
}
}
}
Expand Down Expand Up @@ -670,15 +670,14 @@ void odbc_bindcols(odbc_result *result)
SQLSMALLINT colnamelen; /* Not used */
SQLLEN displaysize;
SQLUSMALLINT colfieldid;
int charextraalloc;

result->values = (odbc_result_value *) safe_emalloc(sizeof(odbc_result_value), result->numcols, 0);

result->longreadlen = ODBCG(defaultlrl);
result->binmode = ODBCG(defaultbinmode);

for(i = 0; i < result->numcols; i++) {
charextraalloc = 0;
bool char_extra_alloc = false;
colfieldid = SQL_COLUMN_DISPLAY_SIZE;

rc = PHP_ODBC_SQLCOLATTRIBUTE(result->stmt, (SQLUSMALLINT)(i+1), PHP_ODBC_SQL_DESC_NAME,
Expand Down Expand Up @@ -716,7 +715,7 @@ void odbc_bindcols(odbc_result *result)
case SQL_WVARCHAR:
colfieldid = SQL_DESC_OCTET_LENGTH;
#else
charextraalloc = 1;
char_extra_alloc = true;
#endif
/* TODO: Check this is the intended behaviour */
ZEND_FALLTHROUGH;
Expand All @@ -742,7 +741,7 @@ void odbc_bindcols(odbc_result *result)
}
/* This is a quirk for ODBC 2.0 compatibility for broken driver implementations.
*/
charextraalloc = 1;
char_extra_alloc = true;
rc = SQLColAttributes(result->stmt, (SQLUSMALLINT)(i+1), SQL_COLUMN_DISPLAY_SIZE,
NULL, 0, NULL, &displaysize);
if (rc != SQL_SUCCESS) {
Expand All @@ -769,7 +768,7 @@ void odbc_bindcols(odbc_result *result)
displaysize += 3;
}

if (charextraalloc) {
if (char_extra_alloc) {
/* Since we don't know the exact # of bytes, allocate extra */
displaysize *= 4;
}
Expand Down Expand Up @@ -1015,10 +1014,9 @@ PHP_FUNCTION(odbc_execute)
zval *pv_res, *tmp;
HashTable *pv_param_ht = (HashTable *) &zend_empty_array;
odbc_params_t *params = NULL;
char *filename;
SQLSMALLINT ctype;
odbc_result *result;
int i, ne;
int i;
RETCODE rc;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|h", &pv_res, odbc_result_ce, &pv_param_ht) == FAILURE) {
Expand All @@ -1029,8 +1027,9 @@ PHP_FUNCTION(odbc_execute)
CHECK_ODBC_RESULT(result);

if (result->numparams > 0) {
if ((ne = zend_hash_num_elements(pv_param_ht)) < result->numparams) {
php_error_docref(NULL, E_WARNING, "Not enough parameters (%d should be %d) given", ne, result->numparams);
uint32_t ne = zend_hash_num_elements(pv_param_ht);
if (ne < result->numparams) {
php_error_docref(NULL, E_WARNING, "Not enough parameters (%" PRIu32 " should be %d) given", ne, result->numparams);
RETURN_FALSE;
}

Expand Down Expand Up @@ -1063,11 +1062,11 @@ PHP_FUNCTION(odbc_execute)
ZSTR_VAL(tmpstr)[0] == '\'' &&
ZSTR_VAL(tmpstr)[ZSTR_LEN(tmpstr) - 1] == '\'') {

if (ZSTR_LEN(tmpstr) != strlen(ZSTR_VAL(tmpstr))) {
if (UNEXPECTED(zend_str_has_nul_byte(tmpstr))) {
odbc_release_params(result, params);
RETURN_FALSE;
}
filename = estrndup(&ZSTR_VAL(tmpstr)[1], ZSTR_LEN(tmpstr) - 2);
char *filename = estrndup(&ZSTR_VAL(tmpstr)[1], ZSTR_LEN(tmpstr) - 2);

/* Check the basedir */
if (php_check_open_basedir(filename)) {
Expand Down Expand Up @@ -2185,8 +2184,7 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool
int direct = 0;
SQLCHAR dsnbuf[1024];
short dsnbuflen;
char *ldb = 0;
int ldb_len = 0;
char *ldb = NULL;

/* a connection string may have = but not ; - i.e. "DSN=PHP" */
if (strstr((char*)db, "=")) {
Expand Down Expand Up @@ -2248,7 +2246,7 @@ bool odbc_sqlconnect(zval *zv, char *db, char *uid, char *pwd, int cur_opt, bool
efree(pwd_quoted);
}
} else {
ldb_len = strlen(db)+1;
size_t ldb_len = strlen(db)+1;
ldb = (char*) emalloc(ldb_len);
memcpy(ldb, db, ldb_len);
}
Expand Down
23 changes: 23 additions & 0 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,9 @@ static void _property_string(smart_str *str, zend_property_info *prop, const cha
if (prop->flags & ZEND_ACC_READONLY) {
smart_str_appends(str, "readonly ");
}
if (prop->flags & ZEND_ACC_VIRTUAL) {
smart_str_appends(str, "virtual ");
}
if (ZEND_TYPE_IS_SET(prop->type)) {
zend_string *type_str = zend_type_to_string(prop->type);
smart_str_append(str, type_str);
Expand All @@ -1054,6 +1057,26 @@ static void _property_string(smart_str *str, zend_property_info *prop, const cha
smart_str_appends(str, " = ");
format_default_value(str, default_value);
}
if (prop->hooks != NULL) {
smart_str_appends(str, " {");
const zend_function *get_hooked = prop->hooks[ZEND_PROPERTY_HOOK_GET];
if (get_hooked != NULL) {
if (get_hooked->common.fn_flags & ZEND_ACC_FINAL) {
smart_str_appends(str, " final get;");
} else {
smart_str_appends(str, " get;");
}
}
const zend_function *set_hooked = prop->hooks[ZEND_PROPERTY_HOOK_SET];
if (set_hooked != NULL) {
if (set_hooked->common.fn_flags & ZEND_ACC_FINAL) {
smart_str_appends(str, " final set;");
} else {
smart_str_appends(str, " set;");
}
}
smart_str_appends(str, " }");
}
}

smart_str_appends(str, " ]\n");
Expand Down
Loading