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
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ PHP NEWS
. Fixed GMP integer string parsing to reject strings containing NUL bytes
instead of silently truncating them. (Weilin Du)

- Intl:
. Fixed grammatical issues in Normalizer invalid form and IntlCalendar time
zone offset error messages. (Weilin Du)

- ODBC:
. Fixed bug GH-22668 (Heap buffer over-read when a column value exceeds the
driver-reported display size). (iliaal)
Expand Down
1 change: 1 addition & 0 deletions UPGRADING.INTERNALS
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ PHP 8.6 INTERNALS UPGRADE NOTES
(sendfile, splice, copy_file_range, TransmitFile), and is now used by
php_stream_copy_to_stream_ex(). The mmap-based copy fallback was removed.
. Added zend_string_equals_cstr_ci().
. Added zend_string_ends_with() and related variants.

========================
2. Build system changes
Expand Down
26 changes: 26 additions & 0 deletions Zend/tests/partial_application/bound_arg_strict_types.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
Partial application checks bound arguments with the creating scope's strict_types
--FILE--
<?php
declare(strict_types=1);

function f(int $a, $b) { return $a; }

try {
f("3", ?);
} catch (\TypeError $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}

function make() {
try {
f("3", ?);
} catch (\TypeError $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
}
make();
?>
--EXPECT--
TypeError: f(): Argument #1 ($a) must be of type int, string given
TypeError: f(): Argument #1 ($a) must be of type int, string given
18 changes: 9 additions & 9 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1153,7 +1153,7 @@ static bool zend_check_intersection_type_from_list(

static zend_always_inline bool zend_check_type_slow(
const zend_type *type, zval *arg, const zend_reference *ref,
bool is_return_type, bool is_internal)
bool current_frame, bool is_internal)
{
if (ZEND_TYPE_IS_COMPLEX(*type) && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
zend_class_entry *ce;
Expand Down Expand Up @@ -1199,23 +1199,23 @@ static zend_always_inline bool zend_check_type_slow(
/* We cannot have conversions for typed refs. */
return 0;
}
if (is_internal && is_return_type) {
if (is_internal && current_frame) {
/* For internal returns, the type has to match exactly, because we're not
* going to check it for non-debug builds, and there will be no chance to
* apply coercions. */
return 0;
}

return zend_verify_scalar_type_hint(type_mask, arg,
is_return_type ? ZEND_RET_USES_STRICT_TYPES() : ZEND_ARG_USES_STRICT_TYPES(),
current_frame ? ZEND_RET_USES_STRICT_TYPES() : ZEND_ARG_USES_STRICT_TYPES(),
is_internal);

/* Special handling for IS_VOID is not necessary (for return types),
* because this case is already checked at compile-time. */
}

static zend_always_inline bool zend_check_type(
const zend_type *type, zval *arg, bool is_return_type, bool is_internal)
const zend_type *type, zval *arg, bool current_frame, bool is_internal)
{
const zend_reference *ref = NULL;
ZEND_ASSERT(ZEND_TYPE_IS_SET(*type));
Expand All @@ -1229,21 +1229,21 @@ static zend_always_inline bool zend_check_type(
return 1;
}

return zend_check_type_slow(type, arg, ref, is_return_type, is_internal);
return zend_check_type_slow(type, arg, ref, current_frame, is_internal);
}

/* We can not expose zend_check_type() directly because it's inline and uses static functions */
ZEND_API bool zend_check_type_ex(
const zend_type *type, zval *arg, bool is_return_type, bool is_internal)
const zend_type *type, zval *arg, bool current_frame, bool is_internal)
{
return zend_check_type(type, arg, is_return_type, is_internal);
return zend_check_type(type, arg, current_frame, is_internal);
}

ZEND_API bool zend_check_user_type_slow(
const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type)
const zend_type *type, zval *arg, const zend_reference *ref, bool current_frame)
{
return zend_check_type_slow(
type, arg, ref, is_return_type, /* is_internal */ false);
type, arg, ref, current_frame, /* is_internal */ false);
}

static zend_always_inline bool zend_verify_recv_arg_type(const zend_function *zf, uint32_t arg_num, zval *arg)
Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ ZEND_API zend_never_inline ZEND_COLD void zend_verify_never_error(
const zend_function *zf);
ZEND_API bool zend_verify_ref_array_assignable(zend_reference *ref);
ZEND_API bool zend_check_user_type_slow(
const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type);
const zend_type *type, zval *arg, const zend_reference *ref, bool current_frame);
ZEND_API bool zend_check_type_ex(
const zend_type *type, zval *arg, bool is_return_type, bool is_internal);
const zend_type *type, zval *arg, bool current_frame, bool is_internal);

#if ZEND_DEBUG
ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_execute_data *call);
Expand Down
10 changes: 8 additions & 2 deletions Zend/zend_partial.c
Original file line number Diff line number Diff line change
Expand Up @@ -1105,8 +1105,14 @@ static void zp_bind(zval *result, zend_function *function, uint32_t argc, zval *
arg_info = NULL;
}
if (arg_info && ZEND_TYPE_IS_SET(arg_info->type)
&& UNEXPECTED(!zend_check_type_ex(&arg_info->type, var, 0, 0))) {
zend_verify_arg_error(function, arg_info, offset+1, var);
&& UNEXPECTED(!zend_check_type_ex(&arg_info->type, var,
/* current_frame */ true, /* is_internal */ false))) {
zend_string *need_msg = zend_type_to_string_resolved(arg_info->type,
function->common.scope);
zend_argument_type_error_ex(function, offset + 1,
"must be of type %s, %s given",
ZSTR_VAL(need_msg), zend_zval_value_name(var));
zend_string_release(need_msg);
zval_ptr_dtor(result);
ZVAL_NULL(result);
zp_free_unbound_args(offset, argc, argv);
Expand Down
26 changes: 26 additions & 0 deletions Zend/zend_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,32 @@ static zend_always_inline bool zend_string_starts_with_ci(const zend_string *str
#define zend_string_starts_with_literal_ci(str, prefix) \
zend_string_starts_with_cstr_ci(str, "" prefix, sizeof(prefix) - 1)

static zend_always_inline bool zend_string_ends_with_cstr(const zend_string *str, const char *suffix, size_t suffix_length)
{
return ZSTR_LEN(str) >= suffix_length && !memcmp(ZSTR_VAL(str) + ZSTR_LEN(str) - suffix_length, suffix, suffix_length);
}

static zend_always_inline bool zend_string_ends_with(const zend_string *str, const zend_string *suffix)
{
return zend_string_ends_with_cstr(str, ZSTR_VAL(suffix), ZSTR_LEN(suffix));
}

#define zend_string_ends_with_literal(str, suffix) \
zend_string_ends_with_cstr(str, "" suffix, sizeof(suffix) - 1)

static zend_always_inline bool zend_string_ends_with_cstr_ci(const zend_string *str, const char *suffix, size_t suffix_length)
{
return ZSTR_LEN(str) >= suffix_length && !strncasecmp(ZSTR_VAL(str) + ZSTR_LEN(str) - suffix_length, suffix, suffix_length);
}

static zend_always_inline bool zend_string_ends_with_ci(const zend_string *str, const zend_string *suffix)
{
return zend_string_ends_with_cstr_ci(str, ZSTR_VAL(suffix), ZSTR_LEN(suffix));
}

#define zend_string_ends_with_literal_ci(str, suffix) \
zend_string_ends_with_cstr_ci(str, "" suffix, sizeof(suffix) - 1)

/*
* DJBX33A (Daniel J. Bernstein, Times 33 with Addition)
*
Expand Down
7 changes: 1 addition & 6 deletions ext/curl/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@
#include <curl/curl.h>
#include <curl/easy.h>

/* As of curl 7.11.1 this is no longer defined inside curl.h */
#ifndef HttpPost
#define HttpPost curl_httppost
#endif

#include "zend_smart_str.h"
#include "ext/standard/info.h"
#include "ext/standard/file.h"
Expand Down Expand Up @@ -1110,7 +1105,7 @@ void init_curl_handle(php_curl *ch)

memset(&ch->err, 0, sizeof(struct _php_curl_error));

zend_llist_init(&ch->to_free->post, sizeof(struct HttpPost *), (llist_dtor_func_t)curl_free_post, 0);
zend_llist_init(&ch->to_free->post, sizeof(struct curl_httppost *), (llist_dtor_func_t)curl_free_post, 0);
zend_llist_init(&ch->to_free->stream, sizeof(struct mime_data_cb_arg *), (llist_dtor_func_t)curl_free_cb_arg, 0);

zend_hash_init(&ch->to_free->slist, 4, NULL, curl_free_slist, 0);
Expand Down
2 changes: 1 addition & 1 deletion ext/intl/common/common_date.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ U_CFUNC TimeZone *timezone_convert_datetimezone(

if (UNEXPECTED(offset_mins <= -24 * 60 || offset_mins >= 24 * 60)) {
intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR,
"object has an time zone offset that's too large");
"object has a time zone offset that is too large");
return NULL;
}

Expand Down
4 changes: 2 additions & 2 deletions ext/intl/normalizer/normalizer_normalize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ U_CFUNC PHP_FUNCTION( normalizer_normalize )
case NORMALIZER_FORM_KC_CF:
break;
default:
zend_argument_value_error(2, "must be a a valid normalization form");
zend_argument_value_error(2, "must be a valid normalization form");
RETURN_THROWS();
}

Expand Down Expand Up @@ -232,7 +232,7 @@ U_CFUNC PHP_FUNCTION( normalizer_is_normalized )
case NORMALIZER_FORM_KC_CF:
break;
default:
zend_argument_value_error(2, "must be a a valid normalization form");
zend_argument_value_error(2, "must be a valid normalization form");
RETURN_THROWS();
}

Expand Down
2 changes: 1 addition & 1 deletion ext/intl/tests/calendar_fromDateTime_error.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ DateMalformedStringException: Failed to parse time string (foobar) at position 0
NULL
string(88) "IntlCalendar::fromDateTime(): DateTime object is unconstructed: U_ILLEGAL_ARGUMENT_ERROR"
NULL
string(103) "IntlCalendar::fromDateTime(): object has an time zone offset that's too large: U_ILLEGAL_ARGUMENT_ERROR"
string(103) "IntlCalendar::fromDateTime(): object has a time zone offset that is too large: U_ILLEGAL_ARGUMENT_ERROR"
NULL
string(127) "IntlCalendar::fromDateTime(): time zone id 'WEST' extracted from ext/date DateTimeZone not recognized: U_ILLEGAL_ARGUMENT_ERROR"
2 changes: 1 addition & 1 deletion ext/intl/tests/calendar_setTimeZone_error2.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ bool(false)
string(126) "IntlCalendar::setTimeZone(): time zone id 'WEST' extracted from ext/date DateTimeZone not recognized: U_ILLEGAL_ARGUMENT_ERROR"
string(16) "Europe/Amsterdam"
bool(false)
string(102) "IntlCalendar::setTimeZone(): object has an time zone offset that's too large: U_ILLEGAL_ARGUMENT_ERROR"
string(102) "IntlCalendar::setTimeZone(): object has a time zone offset that is too large: U_ILLEGAL_ARGUMENT_ERROR"
string(16) "Europe/Amsterdam"
4 changes: 2 additions & 2 deletions ext/opcache/jit/zend_jit_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1974,7 +1974,7 @@ static bool ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_arg_info *arg
zend_execute_data *execute_data = EG(current_execute_data);
const zend_op *opline = EX(opline);
bool ret = zend_check_user_type_slow(
&arg_info->type, arg, /* ref */ NULL, /* is_return_type */ false);
&arg_info->type, arg, /* ref */ NULL, /* current_frame */ false);
if (UNEXPECTED(!ret)) {
zend_verify_arg_error(EX(func), arg_info, opline->op1.num, arg);
return false;
Expand All @@ -1991,7 +1991,7 @@ static void ZEND_FASTCALL zend_jit_verify_return_slow(zval *arg, const zend_op_a
}
}
if (UNEXPECTED(!zend_check_user_type_slow(
&arg_info->type, arg, /* ref */ NULL, /* is_return_type */ true))) {
&arg_info->type, arg, /* ref */ NULL, /* current_frame */ true))) {
zend_verify_return_error((zend_function*)op_array, arg);
}
}
Expand Down
8 changes: 1 addition & 7 deletions ext/standard/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -1861,13 +1861,7 @@ PHP_FUNCTION(str_ends_with)
Z_PARAM_STR(needle)
ZEND_PARSE_PARAMETERS_END();

if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
RETURN_FALSE;
}

RETURN_BOOL(memcmp(
ZSTR_VAL(haystack) + ZSTR_LEN(haystack) - ZSTR_LEN(needle),
ZSTR_VAL(needle), ZSTR_LEN(needle)) == 0);
RETURN_BOOL(zend_string_ends_with(haystack, needle));
}
/* }}} */

Expand Down
26 changes: 11 additions & 15 deletions main/poll/poll_handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,22 @@
static php_socket_t php_poll_handle_default_get_fd(php_poll_handle_object *handle)
{
zval retval;
zval obj;
zval func_name;

ZVAL_OBJ(&obj, &handle->std);

/* Prepare function name as zval */
ZVAL_STRING(&func_name, "getFileDescriptor");
/* Grab getFileDescriptor() method pointer which is stored in lowercase in the function table */
zend_function *method = zend_hash_str_find_ptr_lc(&handle->std.ce->function_table, ZEND_STRL("getfiledescriptor"));
ZEND_ASSERT(method && "no default method???");

/* Call getFileDescriptor() method */
if (EXPECTED(call_user_function(NULL, &obj, &func_name, &retval, 0, NULL) == SUCCESS)) {
if (Z_TYPE(retval) == IS_LONG) {
php_socket_t fd = Z_LVAL(retval) < 0 ? SOCK_ERR : (php_socket_t) Z_LVAL(retval);
zval_ptr_dtor(&retval);
zval_ptr_dtor(&func_name); /* Clean up function name */
return fd;
}
zval_ptr_dtor(&retval);
zend_call_known_function(method, &handle->std, handle->std.ce, &retval, 0, NULL, NULL);

/* No need to deref the return value as the class is final and thus the method cannot be changed to return by-ref */
if (EXPECTED(Z_TYPE(retval) == IS_LONG)) {
php_socket_t fd = Z_LVAL(retval) < 0 ? SOCK_ERR : (php_socket_t) Z_LVAL(retval);
/* No need to clean the retval as we know it is an integer, and thus it's just on the stack */
return fd;
}

zval_ptr_dtor(&func_name); /* Clean up function name */
zval_ptr_dtor(&retval);
return SOCK_ERR; /* Invalid socket */
}

Expand Down