diff --git a/NEWS b/NEWS index 6472816e407d3..8350e4dfa2e69 100644 --- a/NEWS +++ b/NEWS @@ -66,6 +66,8 @@ PHP NEWS the Uri\WhatWg\Url parser. (timwolla) . Reject out-of-range ports when using the Uri\Rfc3986\Uri parser. (timwolla) + . Return null instead of 0 for Uri\Rfc3986\Uri::getPort() when the + URI contains an empty port. (timwolla) . Clean up naming of internal API. (timwolla) 28 Aug 2025, PHP 8.5.0beta2 diff --git a/Zend/tests/attributes/constants/constant_listed_as_target-internal.phpt b/Zend/tests/attributes/constants/constant_listed_as_target-internal.phpt index b0b88c2f6edab..8a979095e7b95 100644 --- a/Zend/tests/attributes/constants/constant_listed_as_target-internal.phpt +++ b/Zend/tests/attributes/constants/constant_listed_as_target-internal.phpt @@ -3,9 +3,10 @@ Constants listed in valid targets when used wrong (internal attribute) --FILE-- --EXPECTF-- -Fatal error: Attribute "Deprecated" cannot target class (allowed targets: function, method, class constant, constant) in %s on line %d +Fatal error: Attribute "Deprecated" cannot target parameter (allowed targets: class, function, method, class constant, constant) in %s on line %d diff --git a/Zend/tests/attributes/delayed_target_validation/validator_Deprecated.phpt b/Zend/tests/attributes/delayed_target_validation/validator_Deprecated.phpt new file mode 100644 index 0000000000000..f5fedb4ee68e1 --- /dev/null +++ b/Zend/tests/attributes/delayed_target_validation/validator_Deprecated.phpt @@ -0,0 +1,142 @@ +--TEST-- +#[\DelayedTargetValidation] with #[\Deprecated]: validator errors delayed +--FILE-- +getAttributes(); + var_dump($attributes); + try { + $attributes[1]->newInstance(); + } catch (Error $e) { + echo get_class($e) . ": " . $e->getMessage() . "\n"; + } +} + +?> +--EXPECTF-- +******************** +Interface [ interface DemoInterface ] { + @@ %s %d-%d + + - Constants [0] { + } + + - Static properties [0] { + } + + - Static methods [0] { + } + + - Properties [0] { + } + + - Methods [0] { + } +} + +array(2) { + [0]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(23) "DelayedTargetValidation" + } + [1]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(10) "Deprecated" + } +} +Error: Cannot apply #[\Deprecated] to interface DemoInterface +******************** +Class [ class DemoClass ] { + @@ %s %d-%d + + - Constants [0] { + } + + - Static properties [0] { + } + + - Static methods [0] { + } + + - Properties [0] { + } + + - Methods [0] { + } +} + +array(2) { + [0]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(23) "DelayedTargetValidation" + } + [1]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(10) "Deprecated" + } +} +Error: Cannot apply #[\Deprecated] to class DemoClass +******************** +Enum [ enum DemoEnum implements UnitEnum ] { + @@ %s %d-%d + + - Constants [0] { + } + + - Static properties [0] { + } + + - Static methods [1] { + Method [ static public method cases ] { + + - Parameters [0] { + } + - Return [ array ] + } + } + + - Properties [1] { + Property [ public protected(set) readonly string $name ] + } + + - Methods [0] { + } +} + +array(2) { + [0]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(23) "DelayedTargetValidation" + } + [1]=> + object(ReflectionAttribute)#%d (1) { + ["name"]=> + string(10) "Deprecated" + } +} +Error: Cannot apply #[\Deprecated] to enum DemoEnum diff --git a/Zend/tests/attributes/delayed_target_validation/with_Deprecated.phpt b/Zend/tests/attributes/delayed_target_validation/with_Deprecated.phpt index 093b0abb08e0c..e103f9d97389a 100644 --- a/Zend/tests/attributes/delayed_target_validation/with_Deprecated.phpt +++ b/Zend/tests/attributes/delayed_target_validation/with_Deprecated.phpt @@ -40,6 +40,14 @@ class DemoClass { } } +#[DelayedTargetValidation] +#[Deprecated] // Does something here +trait DeprecatedTrait {} + +class WithDeprecatedTrait { + use DeprecatedTrait; +} + #[DelayedTargetValidation] #[Deprecated] // Does something here function demoFn() { @@ -61,6 +69,7 @@ demoFn(); var_dump(GLOBAL_CONST); ?> --EXPECTF-- +Deprecated: Trait DeprecatedTrait used by WithDeprecatedTrait is deprecated in %s on line %d Got: example Deprecated: Method DemoClass::printVal() is deprecated in %s on line %d diff --git a/Zend/tests/attributes/deprecated/error_on_class.phpt b/Zend/tests/attributes/deprecated/error_on_class.phpt new file mode 100644 index 0000000000000..97c48af1491f9 --- /dev/null +++ b/Zend/tests/attributes/deprecated/error_on_class.phpt @@ -0,0 +1,11 @@ +--TEST-- +#[\Deprecated]: Using on a class +--FILE-- + +--EXPECTF-- +Fatal error: Cannot apply #[\Deprecated] to class Demo in %s on line %d diff --git a/Zend/tests/attributes/deprecated/error_on_enum.phpt b/Zend/tests/attributes/deprecated/error_on_enum.phpt new file mode 100644 index 0000000000000..0d998a2389923 --- /dev/null +++ b/Zend/tests/attributes/deprecated/error_on_enum.phpt @@ -0,0 +1,11 @@ +--TEST-- +#[\Deprecated]: Using on an enum +--FILE-- + +--EXPECTF-- +Fatal error: Cannot apply #[\Deprecated] to enum Demo in %s on line %d diff --git a/Zend/tests/attributes/deprecated/error_on_interface.phpt b/Zend/tests/attributes/deprecated/error_on_interface.phpt new file mode 100644 index 0000000000000..595181a7cecd5 --- /dev/null +++ b/Zend/tests/attributes/deprecated/error_on_interface.phpt @@ -0,0 +1,11 @@ +--TEST-- +#[\Deprecated]: Using on an interface +--FILE-- + +--EXPECTF-- +Fatal error: Cannot apply #[\Deprecated] to interface Demo in %s on line %d diff --git a/Zend/tests/attributes/deprecated/traits/basic.phpt b/Zend/tests/attributes/deprecated/traits/basic.phpt new file mode 100644 index 0000000000000..77738058e2a56 --- /dev/null +++ b/Zend/tests/attributes/deprecated/traits/basic.phpt @@ -0,0 +1,33 @@ +--TEST-- +#[\Deprecated]: Basic trait deprecation +--FILE-- + +--EXPECTF-- +Deprecated: Trait DemoTrait1 used by DemoClass is deprecated, please do not use in %s on line %d + +Deprecated: Trait DemoTrait2 used by DemoClass is deprecated since 2.7, will be removed in 3.0 in %s on line %d + +Deprecated: Trait DemoTrait3 used by DemoClass is deprecated, going away in %s on line %d + +Deprecated: Trait DemoTrait4 used by DemoClass is deprecated since 3.5 in %s on line %d diff --git a/Zend/tests/attributes/deprecated/traits/inheritance.phpt b/Zend/tests/attributes/deprecated/traits/inheritance.phpt new file mode 100644 index 0000000000000..6a54a83e2e440 --- /dev/null +++ b/Zend/tests/attributes/deprecated/traits/inheritance.phpt @@ -0,0 +1,18 @@ +--TEST-- +#[\Deprecated]: Deprecated traits only apply to direct use, not inheritance +--FILE-- + +--EXPECTF-- +Deprecated: Trait DemoTrait used by DemoClass is deprecated in %s on line %d diff --git a/Zend/tests/attributes/deprecated/traits/insteadof_unused_warnings.phpt b/Zend/tests/attributes/deprecated/traits/insteadof_unused_warnings.phpt new file mode 100644 index 0000000000000..390455f73ba73 --- /dev/null +++ b/Zend/tests/attributes/deprecated/traits/insteadof_unused_warnings.phpt @@ -0,0 +1,43 @@ +--TEST-- +#[\Deprecated]: `insteadof` rendering a trait unused still triggers deprecation messages +--FILE-- +lowerCase()); +var_dump($d->upperCase()); + +?> +--EXPECTF-- +Deprecated: Trait DemoTraitA used by DemoClass is deprecated in %s on line %d + +Deprecated: Trait DemoTraitB used by DemoClass is deprecated in %s on line %d +string(1) "a" +string(1) "A" diff --git a/Zend/tests/attributes/deprecated/traits/multiple_traits.phpt b/Zend/tests/attributes/deprecated/traits/multiple_traits.phpt new file mode 100644 index 0000000000000..2d838493f4511 --- /dev/null +++ b/Zend/tests/attributes/deprecated/traits/multiple_traits.phpt @@ -0,0 +1,22 @@ +--TEST-- +#[\Deprecated]: Using multiple traits +--FILE-- + +--EXPECTF-- +Deprecated: Trait DemoTraitA used by DemoClass is deprecated in %s on line %d + +Deprecated: Trait DemoTraitB used by DemoClass is deprecated in %s on line %d diff --git a/Zend/tests/attributes/deprecated/traits/throwing_error_handler.phpt b/Zend/tests/attributes/deprecated/traits/throwing_error_handler.phpt new file mode 100644 index 0000000000000..2704ea68e5b3a --- /dev/null +++ b/Zend/tests/attributes/deprecated/traits/throwing_error_handler.phpt @@ -0,0 +1,25 @@ +--TEST-- +#[\Deprecated]: Deprecation converted to ErrorException does not break +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught ErrorException: Trait DemoTrait used by DemoClass is deprecated in %s:%d +Stack trace: +#0 %s: my_error_handler(16384, 'Trait DemoTrait...', '%s', %d) +#1 {main} + thrown in %s on line %d diff --git a/Zend/tests/attributes/deprecated/traits/trait_using_trait.phpt b/Zend/tests/attributes/deprecated/traits/trait_using_trait.phpt new file mode 100644 index 0000000000000..851adeb232d30 --- /dev/null +++ b/Zend/tests/attributes/deprecated/traits/trait_using_trait.phpt @@ -0,0 +1,19 @@ +--TEST-- +#[\Deprecated]: Trait using a deprecated trait +--FILE-- + +--EXPECTF-- +Deprecated: Trait DemoTraitA used by DemoTraitB is deprecated in %s on line %d diff --git a/Zend/tests/attributes/deprecated/traits/with_conflicts.phpt b/Zend/tests/attributes/deprecated/traits/with_conflicts.phpt new file mode 100644 index 0000000000000..5adbb3c57d494 --- /dev/null +++ b/Zend/tests/attributes/deprecated/traits/with_conflicts.phpt @@ -0,0 +1,43 @@ +--TEST-- +#[\Deprecated]: Using multiple traits with conflict resolution +--FILE-- +lowerCase()); +var_dump($d->upperCase()); + +?> +--EXPECTF-- +Deprecated: Trait DemoTraitA used by DemoClass is deprecated in %s on line %d + +Deprecated: Trait DemoTraitB used by DemoClass is deprecated in %s on line %d +string(1) "a" +string(1) "B" diff --git a/Zend/zend_API.c b/Zend/zend_API.c index fa5365b776d2c..4e3cdc597bfe2 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1520,6 +1520,9 @@ ZEND_API zend_result zend_update_class_constant(zend_class_constant *c, const ze zval_ptr_dtor(&c->value); ZVAL_COPY_VALUE(&c->value, &tmp); + /* may not return SUCCESS in case of an exception, + * should've returned FAILURE in zval_update_constant_ex! */ + ZEND_ASSERT(!EG(exception)); return SUCCESS; } diff --git a/Zend/zend_attributes.c b/Zend/zend_attributes.c index 4777e5ca08ad1..b69e192701e48 100644 --- a/Zend/zend_attributes.c +++ b/Zend/zend_attributes.c @@ -110,6 +110,25 @@ static zend_string *validate_attribute( return NULL; } +static zend_string *validate_deprecated( + zend_attribute *attr, + uint32_t target, + zend_class_entry *scope +) { + if (target != ZEND_ATTRIBUTE_TARGET_CLASS) { + /* Being used for a method or something, validation does not apply */ + return NULL; + } + if (!(scope->ce_flags & ZEND_ACC_TRAIT)) { + const char *type = zend_get_object_type_case(scope, false); + return zend_strpprintf(0, "Cannot apply #[\\Deprecated] to %s %s", type, ZSTR_VAL(scope->name)); + } + + scope->ce_flags |= ZEND_ACC_DEPRECATED; + return NULL; + +} + ZEND_METHOD(Attribute, __construct) { zend_long flags = ZEND_ATTRIBUTE_TARGET_ALL; @@ -579,6 +598,7 @@ void zend_register_attribute_ce(void) zend_ce_deprecated = register_class_Deprecated(); attr = zend_mark_internal_attribute(zend_ce_deprecated); + attr->validator = validate_deprecated; zend_ce_nodiscard = register_class_NoDiscard(); attr = zend_mark_internal_attribute(zend_ce_nodiscard); diff --git a/Zend/zend_attributes.stub.php b/Zend/zend_attributes.stub.php index 6db68d4d418e2..ded9c89593a36 100644 --- a/Zend/zend_attributes.stub.php +++ b/Zend/zend_attributes.stub.php @@ -77,7 +77,7 @@ public function __construct() {} /** * @strict-properties */ -#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_FUNCTION|Attribute::TARGET_CLASS_CONSTANT|Attribute::TARGET_CONSTANT)] +#[Attribute(Attribute::TARGET_METHOD|Attribute::TARGET_FUNCTION|Attribute::TARGET_CLASS_CONSTANT|Attribute::TARGET_CONSTANT|Attribute::TARGET_CLASS)] final class Deprecated { public readonly ?string $message; diff --git a/Zend/zend_attributes_arginfo.h b/Zend/zend_attributes_arginfo.h index a271df8e91de9..05f7eeb3e5d45 100644 --- a/Zend/zend_attributes_arginfo.h +++ b/Zend/zend_attributes_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: fa08288df8338c1a16fbf83c179c4084a56007e1 */ + * Stub hash: b868cb33f41d9442f42d0cec84e33fcc09f5d88c */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL") @@ -253,7 +253,7 @@ static zend_class_entry *register_class_Deprecated(void) zend_string *attribute_name_Attribute_class_Deprecated_0 = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, 1); zend_attribute *attribute_Attribute_class_Deprecated_0 = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_Deprecated_0, 1); zend_string_release(attribute_name_Attribute_class_Deprecated_0); - ZVAL_LONG(&attribute_Attribute_class_Deprecated_0->args[0].value, ZEND_ATTRIBUTE_TARGET_METHOD | ZEND_ATTRIBUTE_TARGET_FUNCTION | ZEND_ATTRIBUTE_TARGET_CLASS_CONST | ZEND_ATTRIBUTE_TARGET_CONST); + ZVAL_LONG(&attribute_Attribute_class_Deprecated_0->args[0].value, ZEND_ATTRIBUTE_TARGET_METHOD | ZEND_ATTRIBUTE_TARGET_FUNCTION | ZEND_ATTRIBUTE_TARGET_CLASS_CONST | ZEND_ATTRIBUTE_TARGET_CONST | ZEND_ATTRIBUTE_TARGET_CLASS); return class_entry; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 6c444340a9e76..c07fa9bfa7d7e 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -255,6 +255,9 @@ typedef struct _zend_oparray_context { /* or IS_CONSTANT_VISITED_MARK | | | */ #define ZEND_CLASS_CONST_IS_CASE (1 << 6) /* | | | X */ /* | | | */ +/* deprecation flag | | | */ +#define ZEND_ACC_DEPRECATED (1 << 11) /* X | X | | X */ +/* | | | */ /* has #[\Override] attribute | | | */ #define ZEND_ACC_OVERRIDE (1 << 28) /* | X | X | */ /* | | | */ @@ -272,7 +275,7 @@ typedef struct _zend_oparray_context { #define ZEND_ACC_PROTECTED_SET (1 << 11) /* | | X | */ #define ZEND_ACC_PRIVATE_SET (1 << 12) /* | | X | */ /* | | | */ -/* Class Flags (unused: 30,31) | | | */ +/* Class Flags (unused: 31) | | | */ /* =========== | | | */ /* | | | */ /* Special class types | | | */ @@ -290,7 +293,7 @@ typedef struct _zend_oparray_context { /* | | | */ /* Class has magic methods __get/__set/__unset/ | | | */ /* __isset that use guards | | | */ -#define ZEND_ACC_USE_GUARDS (1 << 11) /* X | | | */ +#define ZEND_ACC_USE_GUARDS (1 << 30) /* X | | | */ /* | | | */ /* Class constants updated | | | */ #define ZEND_ACC_CONSTANTS_UPDATED (1 << 12) /* X | | | */ @@ -341,9 +344,6 @@ typedef struct _zend_oparray_context { /* Function Flags (unused: 30) | | | */ /* ============== | | | */ /* | | | */ -/* deprecation flag | | | */ -#define ZEND_ACC_DEPRECATED (1 << 11) /* | X | | X */ -/* | | | */ /* Function returning by reference | | | */ #define ZEND_ACC_RETURN_REFERENCE (1 << 12) /* | X | | */ /* | | | */ diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index efdcb905fd773..a18c393be7f98 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -487,6 +487,9 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, CONST_PROTECT_RECURSION(c); zend_deprecated_constant(c, c->name); CONST_UNPROTECT_RECURSION(c); + if (UNEXPECTED(EG(exception))) { + return NULL; + } } } return &c->value; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 1bd79e5283046..ba9a7fa7e528f 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2006,6 +2006,27 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_constant(const zend_consta zend_string_release(message_suffix); } +ZEND_API ZEND_COLD void zend_use_of_deprecated_trait( + zend_class_entry *trait, + const zend_string *used_by +) { + zend_string *message_suffix = ZSTR_EMPTY_ALLOC(); + + if (get_deprecation_suffix_from_attribute(trait->attributes, trait, &message_suffix) == FAILURE) { + return; + } + + int code = trait->type == ZEND_INTERNAL_CLASS ? E_DEPRECATED : E_USER_DEPRECATED; + + zend_error_unchecked(code, "Trait %s used by %s is deprecated%S", + ZSTR_VAL(trait->name), + ZSTR_VAL(used_by), + message_suffix + ); + + zend_string_release(message_suffix); +} + ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void) { zend_error(E_DEPRECATED, "Automatic conversion of false to array is deprecated"); diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index cf15c9e3b2db5..13fb1ab7667a3 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -66,6 +66,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_functi ZEND_API ZEND_COLD void ZEND_FASTCALL zend_nodiscard_function(const zend_function *fbc); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_constant(const zend_class_constant *c, const zend_string *constant_name); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_constant(const zend_constant *c, const zend_string *constant_name); +ZEND_API ZEND_COLD void zend_use_of_deprecated_trait(zend_class_entry *trait, const zend_string *used_by); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_false_to_array_deprecated(void); ZEND_COLD void ZEND_FASTCALL zend_param_must_be_ref(const zend_function *func, uint32_t arg_num); ZEND_API ZEND_COLD void ZEND_FASTCALL zend_use_resource_as_offset(const zval *dim); diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 8679a53e8ff59..89e51cb7f0754 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -3524,6 +3524,13 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string free_alloca(traits_and_interfaces, use_heap); return NULL; } + if (UNEXPECTED(trait->ce_flags & ZEND_ACC_DEPRECATED)) { + zend_use_of_deprecated_trait(trait, ce->name); + if (UNEXPECTED(EG(exception))) { + free_alloca(traits_and_interfaces, use_heap); + return NULL; + } + } for (j = 0; j < i; j++) { if (traits_and_interfaces[j] == trait) { /* skip duplications */ diff --git a/ext/dba/dba.c b/ext/dba/dba.c index 086998973e20a..37f05ebb94fe7 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -256,14 +256,14 @@ static void dba_close_info(dba_info *info) if (info->flags & DBA_PERSISTENT) { php_stream_pclose(info->fp); } else { - php_stream_close(info->fp); + php_stream_free(info->fp, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR); } } if (info->lock.fp) { if (info->flags & DBA_PERSISTENT) { php_stream_pclose(info->lock.fp); } else { - php_stream_close(info->lock.fp); + php_stream_free(info->lock.fp, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR); } } @@ -516,6 +516,17 @@ static zend_always_inline zend_string *php_dba_zend_string_dup_safe(zend_string } } +/* See mysqlnd_fixup_regular_list */ +static void php_dba_fixup_regular_list(php_stream *stream) +{ + dtor_func_t origin_dtor = EG(regular_list).pDestructor; + EG(regular_list).pDestructor = NULL; + zend_hash_index_del(&EG(regular_list), stream->res->handle); + EG(regular_list).pDestructor = origin_dtor; + efree(stream->res); + stream->res = NULL; +} + /* {{{ php_dba_open */ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) { @@ -827,6 +838,9 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) /* do not log errors for .lck file while in read only mode on .lck file */ lock_file_mode = "rb"; connection->info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|IGNORE_PATH|persistent_flag, NULL); + if (connection->info->lock.fp && !persistent_flag) { + php_dba_fixup_regular_list(connection->info->lock.fp); + } } if (!connection->info->lock.fp) { /* when not in read mode or failed to open .lck file read only. now try again in create(write) mode and log errors */ @@ -837,6 +851,9 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) zend_string *opened_path = NULL; connection->info->lock.fp = php_stream_open_wrapper(lock_name, lock_file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, &opened_path); if (connection->info->lock.fp) { + if (!persistent_flag) { + php_dba_fixup_regular_list(connection->info->lock.fp); + } if (is_db_lock) { if (opened_path) { /* replace the path info with the real path of the opened file */ @@ -873,6 +890,9 @@ static void php_dba_open(INTERNAL_FUNCTION_PARAMETERS, bool persistent) connection->info->fp = connection->info->lock.fp; /* use the same stream for locking and database access */ } else { connection->info->fp = php_stream_open_wrapper(ZSTR_VAL(connection->info->path), file_mode, STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH|persistent_flag, NULL); + if (connection->info->fp && !persistent_flag) { + php_dba_fixup_regular_list(connection->info->fp); + } } if (!connection->info->fp) { /* stream operation already wrote an error message */ diff --git a/ext/dba/tests/gh19706.phpt b/ext/dba/tests/gh19706.phpt new file mode 100644 index 0000000000000..4cf3ef5f54d3c --- /dev/null +++ b/ext/dba/tests/gh19706.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-19706 (dba stream resource mismanagement) +--EXTENSIONS-- +dba +--FILE-- + +--CLEAN-- + +--EXPECT-- +object(Dba\Connection)#1 (0) { +} +object(Dba\Connection)#1 (0) { +} diff --git a/ext/uri/tests/059.phpt b/ext/uri/tests/059.phpt new file mode 100644 index 0000000000000..3d7cef10dff12 --- /dev/null +++ b/ext/uri/tests/059.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test empty ports become null +--EXTENSIONS-- +uri +--FILE-- +getPort()); + +?> +--EXPECTF-- +object(Uri\Rfc3986\Uri)#%d (8) { + ["scheme"]=> + string(5) "https" + ["username"]=> + NULL + ["password"]=> + NULL + ["host"]=> + string(11) "example.com" + ["port"]=> + NULL + ["path"]=> + string(0) "" + ["query"]=> + NULL + ["fragment"]=> + NULL +} +NULL diff --git a/ext/uri/uri_parser_rfc3986.c b/ext/uri/uri_parser_rfc3986.c index f9581e6d93ed2..7a004a41b0a8f 100644 --- a/ext/uri/uri_parser_rfc3986.c +++ b/ext/uri/uri_parser_rfc3986.c @@ -212,7 +212,7 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_port_read(const { const UriUriA *uriparser_uri = get_uri_for_reading(internal_uri->uri, read_mode); - if (has_text_range(&uriparser_uri->portText)) { + if (has_text_range(&uriparser_uri->portText) && get_text_range_length(&uriparser_uri->portText) > 0) { ZVAL_LONG(retval, port_str_to_zend_long_checked(uriparser_uri->portText.first, get_text_range_length(&uriparser_uri->portText))); } else { ZVAL_NULL(retval); @@ -326,15 +326,14 @@ php_uri_parser_rfc3986_uris *php_uri_parser_rfc3986_parse_ex(const char *uri_str /* Make the resulting URI independent of the 'uri_str'. */ uriMakeOwnerMmA(&uri, mm); - if ( - has_text_range(&uri.portText) - && port_str_to_zend_long_checked(uri.portText.first, get_text_range_length(&uri.portText)) == -1 - ) { - if (!silent) { - zend_throw_exception(uri_invalid_uri_exception_ce, "The port is out of range", 0); - } + if (has_text_range(&uri.portText) && get_text_range_length(&uri.portText) > 0) { + if (port_str_to_zend_long_checked(uri.portText.first, get_text_range_length(&uri.portText)) == -1) { + if (!silent) { + zend_throw_exception(uri_invalid_uri_exception_ce, "The port is out of range", 0); + } - goto fail; + goto fail; + } } php_uri_parser_rfc3986_uris *uriparser_uris = uriparser_create_uris(); diff --git a/ext/zend_test/tests/gh19720.phpt b/ext/zend_test/tests/gh19720.phpt new file mode 100644 index 0000000000000..627444c4793a8 --- /dev/null +++ b/ext/zend_test/tests/gh19720.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-19720 (Assertion failure when error handler throws when accessing a deprecated constant) +--EXTENSIONS-- +zend_test +--FILE-- + 42]; +} + +set_error_handler(function ($_, $errstr) { + throw new Exception($errstr); +}); + +try { + var_dump(Test::MyConst); +} catch (Exception $e) { + echo $e->getMessage(), "\n"; +} +?> +--EXPECT-- +Constant ZEND_TEST_DEPRECATED is deprecated