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
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ PHP NEWS
. Fixed UConverter::transcode() silently truncating from_subst and to_subst
option lengths greater than 127 bytes. (Weilin Du)

- IO:
. Added new polling API. (Jakub Zelenka)

- JSON:
. Enriched JSON last error / exception message with error location.
(Juan Morales)
Expand Down
21 changes: 21 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ PHP 8.6 UPGRADE NOTES
IntlNumberRangeFormatter::IDENTITY_FALLBACK_RANGE identity fallbacks.
It is supported from icu 63.

- IO:
. Added new polling API.
RFC: https://wiki.php.net/rfc/poll_api

- JSON:
. Added extra info about error location to the JSON error messages returned
from json_last_error_msg() and JsonException message.
Expand Down Expand Up @@ -351,6 +355,23 @@ PHP 8.6 UPGRADE NOTES
. enum StreamErrorMode
. enum StreamErrorCode
RFC: https://wiki.php.net/rfc/stream_errors
. Io\Poll\Context
. Io\Poll\Watcher
. enum Io\Poll\Backend
. enum Io\Poll\Event
. interface Io\Poll\Handle
. Io\IoException
. Io\Poll\PollException
. Io\Poll\FailedPollOperationException
. Io\Poll\FailedContextInitializationException
. Io\Poll\FailedHandleAddException
. Io\Poll\FailedWatcherModificationException
. Io\Poll\FailedPollWaitException
. Io\Poll\BackendUnavailableException
. Io\Poll\InactiveWatcherException
. Io\Poll\HandleAlreadyWatchedException
. Io\Poll\InvalidHandleException
. StreamPollHandle

========================================
8. Removed Extensions and SAPIs
Expand Down
35 changes: 35 additions & 0 deletions Zend/tests/type_coercion/gh22112.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
--TEST--
GH-22112 (Assertion failure when error handler throws during NaN to bool/string coercion at function entry)
--FILE--
<?php

set_error_handler(function ($errno, $errstr) {
throw new Exception($errstr);
});

function take_bool(bool $v) {
echo "take_bool entered\n";
}

function take_string(string $v) {
echo "take_string entered\n";
}

$nan = fdiv(0, 0);

try {
take_bool($nan);
} catch (Exception $e) {
echo "bool: ", $e->getMessage(), "\n";
}

try {
take_string($nan);
} catch (Exception $e) {
echo "string: ", $e->getMessage(), "\n";
}

?>
--EXPECT--
bool: unexpected NAN value was coerced to bool
string: unexpected NAN value was coerced to string
9 changes: 8 additions & 1 deletion Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,11 @@ ZEND_API zpp_parse_bool_status ZEND_FASTCALL zend_parse_arg_bool_weak(const zval
if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("bool", arg_num)) {
return ZPP_PARSE_BOOL_STATUS_ERROR;
}
return zend_is_true(arg);
bool result = zend_is_true(arg);
if (UNEXPECTED(EG(exception))) {
return ZPP_PARSE_BOOL_STATUS_ERROR;
}
return result;
}
return ZPP_PARSE_BOOL_STATUS_ERROR;
}
Expand Down Expand Up @@ -735,6 +739,9 @@ ZEND_API zend_string* ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, uint32_t
return NULL;
}
convert_to_string(arg);
if (UNEXPECTED(EG(exception))) {
return NULL;
}
return Z_STR_P(arg);
} else if (UNEXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
zend_object *zobj = Z_OBJ_P(arg);
Expand Down
12 changes: 12 additions & 0 deletions Zend/zend_object_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1825,6 +1825,18 @@ ZEND_API ZEND_ATTRIBUTE_NONNULL zend_function *zend_get_call_trampoline_func(
}
/* }}} */

ZEND_API void zend_free_trampoline(zend_function *func)
{
ZEND_ASSERT(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE);

if (func == &EG(trampoline)) {
EG(trampoline).common.attributes = NULL;
EG(trampoline).common.function_name = NULL;
} else {
efree(func);
}
}

static ZEND_FUNCTION(zend_parent_hook_get_trampoline)
{
zend_object *obj = Z_PTR_P(ZEND_THIS);
Expand Down
56 changes: 25 additions & 31 deletions Zend/zend_object_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,10 @@ struct _zend_object_handlers {
BEGIN_EXTERN_C()
extern const ZEND_API zend_object_handlers std_object_handlers;

#define zend_get_std_object_handlers() \
(&std_object_handlers)

#define zend_get_function_root_class(fbc) \
((fbc)->common.prototype ? (fbc)->common.prototype->common.scope : (fbc)->common.scope)
static zend_always_inline const zend_object_handlers *zend_get_std_object_handlers(void)
{
return &std_object_handlers;
}

#define ZEND_PROPERTY_ISSET 0x0 /* Property exists and is not NULL */
#define ZEND_PROPERTY_NOT_EMPTY ZEND_ISEMPTY /* Property is not empty */
Expand Down Expand Up @@ -290,18 +289,20 @@ static zend_always_inline HashTable *zend_std_get_properties_ex(zend_object *obj
/* Implements the fast path for array cast */
ZEND_API HashTable *zend_std_build_object_properties_array(zend_object *zobj);

#define ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(object) ( \
/* We can use zend_std_build_object_properties_array() for objects \
* without properties ht and with standard handlers */ \
Z_OBJ_P(object)->properties == NULL \
&& Z_OBJ_HT_P(object)->get_properties_for == NULL \
&& Z_OBJ_HT_P(object)->get_properties == zend_std_get_properties \
/* For initialized proxies we need to forward to the real instance */ \
&& ( \
!zend_object_is_lazy_proxy(Z_OBJ_P(object)) \
|| !zend_lazy_object_initialized(Z_OBJ_P(object)) \
) \
)
static zend_always_inline bool ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(const zval *zv) {
/* We can use zend_std_build_object_properties_array() for objects
* without properties ht and with standard handlers */
const zend_object *obj = Z_OBJ_P(zv);

return obj->properties == NULL
&& obj->handlers->get_properties_for == NULL
&& obj->handlers->get_properties == zend_std_get_properties
/* For initialized proxies we need to forward to the real instance */
&& (
!zend_object_is_lazy_proxy(obj)
|| !zend_lazy_object_initialized(obj)
);
}

/* Handler for objects that cannot be meaningfully compared.
* Only objects with the same identity will be considered equal. */
Expand All @@ -312,6 +313,7 @@ ZEND_API bool zend_check_protected(const zend_class_entry *ce, const zend_class_
ZEND_API zend_result zend_check_property_access(const zend_object *zobj, zend_string *prop_info_name, bool is_dynamic);

ZEND_API ZEND_ATTRIBUTE_NONNULL zend_function *zend_get_call_trampoline_func(const zend_function *fbc, zend_string *method_name);
ZEND_API void zend_free_trampoline(zend_function *func);

ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *member);

Expand All @@ -335,20 +337,12 @@ ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_p

void zend_object_handlers_startup(void);

#define zend_release_properties(ht) do { \
if (ht) { \
zend_array_release(ht); \
} \
} while (0)

#define zend_free_trampoline(func) do { \
if ((func) == &EG(trampoline)) { \
EG(trampoline).common.attributes = NULL; \
EG(trampoline).common.function_name = NULL; \
} else { \
efree(func); \
} \
} while (0)
static zend_always_inline void zend_release_properties(HashTable *ht)
{
if (ht) {
zend_array_release(ht);
}
}

/* Fallback to default comparison implementation if the arguments aren't both objects
* and have the same compare() handler. You'll likely want to use this unless you
Expand Down
5 changes: 5 additions & 0 deletions Zend/zend_objects_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ static inline zend_property_info *zend_get_typed_property_info_for_slot(zend_obj
return NULL;
}

static zend_always_inline zend_class_entry *zend_get_function_root_class(const zend_function *fbc)
{
return fbc->common.prototype ? fbc->common.prototype->common.scope : fbc->common.scope;
}

static zend_always_inline bool zend_check_method_accessible(const zend_function *fn, const zend_class_entry *scope)
{
if (!(fn->common.fn_flags & ZEND_ACC_PUBLIC)
Expand Down
29 changes: 15 additions & 14 deletions Zend/zend_observer.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ extern ZEND_API bool zend_observer_errors_observed;
extern ZEND_API bool zend_observer_function_declared_observed;
extern ZEND_API bool zend_observer_class_linked_observed;

#define ZEND_OBSERVER_HANDLE(function) (ZEND_USER_CODE((function)->type) \
? zend_observer_fcall_op_array_extension : zend_observer_fcall_internal_function_extension)
static zend_always_inline int ZEND_OBSERVER_HANDLE(const zend_function *function) {
return ZEND_USER_CODE(function->common.type) ? zend_observer_fcall_op_array_extension : zend_observer_fcall_internal_function_extension;
}

#define ZEND_OBSERVER_DATA(function) \
((zend_observer_fcall_begin_handler *)&ZEND_OP_ARRAY_EXTENSION((&(function)->common), ZEND_OBSERVER_HANDLE(function)))
Expand All @@ -45,18 +46,6 @@ extern ZEND_API bool zend_observer_class_linked_observed;
/* Omit zend_observer_fcall_internal_function_extension check, they are set at the same time. */
#define ZEND_OBSERVER_ENABLED (zend_observer_fcall_op_array_extension != -1)

#define ZEND_OBSERVER_FCALL_BEGIN(execute_data) do { \
if (ZEND_OBSERVER_ENABLED) { \
zend_observer_fcall_begin(execute_data); \
} \
} while (0)

#define ZEND_OBSERVER_FCALL_END(execute_data, return_value) do { \
if (ZEND_OBSERVER_ENABLED) { \
zend_observer_fcall_end(execute_data, return_value); \
} \
} while (0)

typedef void (*zend_observer_fcall_begin_handler)(zend_execute_data *execute_data);
typedef void (*zend_observer_fcall_end_handler)(zend_execute_data *execute_data, zval *retval);

Expand Down Expand Up @@ -87,6 +76,12 @@ ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(zend_execute_data *execute
/* prechecked: the call is actually observed. */
ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin_prechecked(zend_execute_data *execute_data, zend_observer_fcall_begin_handler *observer_data);

static zend_always_inline void ZEND_OBSERVER_FCALL_BEGIN(zend_execute_data *execute_data) {
if (ZEND_OBSERVER_ENABLED) {
zend_observer_fcall_begin(execute_data);
}
}

static zend_always_inline bool zend_observer_handler_is_unobserved(const zend_observer_fcall_begin_handler *handler) {
return *handler == ZEND_OBSERVER_NONE_OBSERVED;
}
Expand Down Expand Up @@ -126,6 +121,12 @@ static zend_always_inline void zend_observer_fcall_end(zend_execute_data *execut
}
}

static zend_always_inline void ZEND_OBSERVER_FCALL_END(zend_execute_data *execute_data, zval *return_value) {
if (ZEND_OBSERVER_ENABLED) {
zend_observer_fcall_end(execute_data, return_value);
}
}

ZEND_API void zend_observer_fcall_end_all(void);

typedef void (*zend_observer_function_declared_cb)(zend_op_array *op_array, zend_string *name);
Expand Down
44 changes: 44 additions & 0 deletions build/php.m4
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,50 @@ int main(void) {
])
])

AC_DEFUN([PHP_POLL_MECHANISMS],
[
AC_MSG_CHECKING([for polling mechanisms])
poll_mechanisms=""

AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
#include <sys/epoll.h>
], [
int fd = epoll_create(1);
return fd;
])], [
AC_DEFINE([HAVE_EPOLL], [1], [Define if epoll is available])
poll_mechanisms="$poll_mechanisms epoll"

AC_CHECK_FUNCS([epoll_pwait2], [], [], [#include <sys/epoll.h>])
])

AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
#include <sys/event.h>
#include <sys/time.h>
], [
int kq = kqueue();
return kq;
])], [
AC_DEFINE([HAVE_KQUEUE], [1], [Define if kqueue is available])
poll_mechanisms="$poll_mechanisms kqueue"
])

AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
#include <port.h>
], [
int port = port_create();
return port;
])], [
AC_DEFINE([HAVE_EVENT_PORTS], [1], [Define if event ports are available])
poll_mechanisms="$poll_mechanisms eventport"
])

dnl Set poll mechanisms including poll that is always available
poll_mechanisms="$poll_mechanisms poll"

AC_MSG_RESULT([$poll_mechanisms])
])

dnl ----------------------------------------------------------------------------
dnl Library/function existence and build sanity checks.
dnl ----------------------------------------------------------------------------
Expand Down
12 changes: 12 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ AC_CHECK_HEADERS(m4_normalize([
])

PHP_FOPENCOOKIE
PHP_POLL_MECHANISMS
PHP_BROKEN_GETCWD
AS_VAR_IF([GCC], [yes], [PHP_BROKEN_GCC_STRLEN_OPT])

Expand Down Expand Up @@ -1682,6 +1683,17 @@ PHP_ADD_SOURCES_X([main],
[PHP_FASTCGI_OBJS],
[no])

PHP_ADD_SOURCES([main/poll], m4_normalize([
poll_backend_epoll.c
poll_backend_eventport.c
poll_backend_kqueue.c
poll_backend_poll.c
poll_core.c
poll_fd_table.c
poll_handle.c
]),
[-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1])

PHP_ADD_SOURCES([main/streams], m4_normalize([
cast.c
filter.c
Expand Down
4 changes: 1 addition & 3 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -4635,9 +4635,7 @@ ZEND_METHOD(ReflectionClass, getProperty)
str_name = ZSTR_VAL(name);
if ((tmp = strstr(ZSTR_VAL(name), "::")) != NULL) {
classname_len = tmp - ZSTR_VAL(name);
classname = zend_string_alloc(classname_len, 0);
zend_str_tolower_copy(ZSTR_VAL(classname), ZSTR_VAL(name), classname_len);
ZSTR_VAL(classname)[classname_len] = '\0';
classname = zend_string_init(ZSTR_VAL(name), classname_len, 0);
str_name_len = ZSTR_LEN(name) - (classname_len + 2);
str_name = tmp + 2;

Expand Down
2 changes: 1 addition & 1 deletion ext/reflection/tests/ReflectionClass_getProperty_003.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -244,4 +244,4 @@ Fully qualified property name X::$privC does not specify a base class of C
--- (Reflecting on X::doesNotExist) ---
Fully qualified property name X::$doesNotExist does not specify a base class of C
--- (Reflecting on doesNotexist::doesNotExist) ---
Class "doesnotexist" does not exist
Class "doesNotexist" does not exist
2 changes: 1 addition & 1 deletion ext/reflection/tests/ReflectionClass_getProperty_004.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,4 @@ Fully qualified property name X::$privC does not specify a base class of C
--- (Reflecting on X::doesNotExist) ---
Fully qualified property name X::$doesNotExist does not specify a base class of C
--- (Reflecting on doesNotexist::doesNotExist) ---
Class "doesnotexist" does not exist
Class "doesNotexist" does not exist
Loading
Loading