Skip to content
7 changes: 7 additions & 0 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -4327,8 +4327,15 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_fcall_interrupt(zend_execute_data *ca
} \
} while (0)

#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
# define ZEND_VM_KIND_TAILCALL_SAVE_OPLINE() SAVE_OPLINE()
#else
# define ZEND_VM_KIND_TAILCALL_SAVE_OPLINE()
#endif

#define ZEND_VM_LOOP_INTERRUPT_CHECK() do { \
if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { \
ZEND_VM_KIND_TAILCALL_SAVE_OPLINE(); \
ZEND_VM_LOOP_INTERRUPT(); \
} \
} while (0)
Expand Down
2 changes: 1 addition & 1 deletion ext/date/php_date.c
Original file line number Diff line number Diff line change
Expand Up @@ -5058,7 +5058,7 @@ static bool date_period_init_iso8601_string(php_period_obj *dpobj, zend_class_en
zend_string_release(func);
return false;
}
if (dpobj->end == NULL && recurrences == 0) {
if (dpobj->end == NULL && *recurrences == 0) {
zend_string *func = get_active_function_or_method_name();
zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain an end date or a recurrence count, \"%s\" given", ZSTR_VAL(func), isostr);
zend_string_release(func);
Expand Down
4 changes: 2 additions & 2 deletions ext/date/tests/date_period_bad_iso_format.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,5 @@ DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must
DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given

Deprecated: Calling DatePeriod::__construct(string $isostr, int $options = 0) is deprecated, use DatePeriod::createFromISO8601String() instead in %s on line %d
DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d
DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): Recurrence count must be greater or equal to 1 and lower than %d
DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain an end date or a recurrence count, "2012-07-01T00:00:00Z/P7D" given
DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): ISO interval must contain an end date or a recurrence count, "2012-07-01T00:00:00Z/P7D" given
44 changes: 35 additions & 9 deletions ext/sqlite3/sqlite3.c
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ PHP_METHOD(SQLite3, query)
}
/* }}} */

static void sqlite_value_to_zval(sqlite3_stmt *stmt, int column, zval *data) /* {{{ */
static void sqlite_value_to_zval(php_sqlite3_db_object *db_obj, sqlite3_stmt *stmt, int column, zval *data) /* {{{ */
{
sqlite3_int64 val;

Expand All @@ -613,7 +613,13 @@ static void sqlite_value_to_zval(sqlite3_stmt *stmt, int column, zval *data) /*
val = sqlite3_column_int64(stmt, column);
#if LONG_MAX <= 2147483647
if (val > ZEND_LONG_MAX || val < ZEND_LONG_MIN) {
ZVAL_STRINGL(data, (char *)sqlite3_column_text(stmt, column), sqlite3_column_bytes(stmt, column));
const char *text = (const char *) sqlite3_column_text(stmt, column);
if (UNEXPECTED(text == NULL)) {
php_sqlite3_error(db_obj, SQLITE_NOMEM, "Failed to retrieve column value due to out of memory");
ZVAL_NULL(data);
} else {
ZVAL_STRINGL(data, text, sqlite3_column_bytes(stmt, column));
}
} else {
#endif
ZVAL_LONG(data, (zend_long) val);
Expand All @@ -630,13 +636,33 @@ static void sqlite_value_to_zval(sqlite3_stmt *stmt, int column, zval *data) /*
ZVAL_NULL(data);
break;

case SQLITE3_TEXT:
ZVAL_STRINGL(data, (const char *) sqlite3_column_text(stmt, column), sqlite3_column_bytes(stmt, column));
case SQLITE3_TEXT: {
const char *text = (const char *) sqlite3_column_text(stmt, column);
if (UNEXPECTED(text == NULL)) {
php_sqlite3_error(db_obj, SQLITE_NOMEM, "Failed to retrieve column value due to out of memory");
ZVAL_NULL(data);
} else {
ZVAL_STRINGL(data, text, sqlite3_column_bytes(stmt, column));
}
break;
}

case SQLITE_BLOB:
default:
ZVAL_STRINGL(data, (char*)sqlite3_column_blob(stmt, column), sqlite3_column_bytes(stmt, column));
default: {
const char *blob = (const char *) sqlite3_column_blob(stmt, column);
if (UNEXPECTED(blob == NULL)) {
if (sqlite3_errcode(sqlite3_db_handle(stmt)) == SQLITE_NOMEM) {
php_sqlite3_error(db_obj, SQLITE_NOMEM, "Failed to retrieve column value due to out of memory");
ZVAL_NULL(data);
} else {
/* Zero-length BLOB */
ZVAL_EMPTY_STRING(data);
}
} else {
ZVAL_STRINGL(data, blob, sqlite3_column_bytes(stmt, column));
}
break;
}
}
}
/* }}} */
Expand Down Expand Up @@ -686,14 +712,14 @@ PHP_METHOD(SQLite3, querySingle)
case SQLITE_ROW: /* Valid Row */
{
if (!entire_row) {
sqlite_value_to_zval(stmt, 0, return_value);
sqlite_value_to_zval(db_obj, stmt, 0, return_value);
} else {
int i = 0, count = sqlite3_data_count(stmt);

array_init_size(return_value, count);
for (i = 0; i < count; i++) {
zval data;
sqlite_value_to_zval(stmt, i, &data);
sqlite_value_to_zval(db_obj, stmt, i, &data);
add_assoc_zval(return_value, (char*)sqlite3_column_name(stmt, i), &data);
}
}
Expand Down Expand Up @@ -2447,7 +2473,7 @@ static zend_always_inline void php_sqlite3_fetch_one(int n_cols, php_sqlite3_res
{
for (int i = 0; i < n_cols; i ++) {
zval data;
sqlite_value_to_zval(result_obj->stmt_obj->stmt, i, &data);
sqlite_value_to_zval(result_obj->db_obj, result_obj->stmt_obj->stmt, i, &data);

if (mode & PHP_SQLITE3_NUM) {
add_index_zval(result, i, &data);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
Test Uri\WhatWg\Url component modification - error - modifying multiple components with warnings before throwing an exception
--FILE--
<?php

$url = new Uri\WhatWg\Url("https://example.com")
->withScheme("\tscheme")
->withHost("\tex.com")
->withQuery("\refoo=bar")
->withFragment("\nfoo");

try {
$url->withScheme("0");
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), PHP_EOL;
var_dump($e->errors);
}

?>
--EXPECT--
Uri\WhatWg\InvalidUrlException: The specified scheme is malformed
array(0) {
}
16 changes: 16 additions & 0 deletions ext/uri/uri_parser_whatwg.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ static zend_result php_uri_parser_whatwg_scheme_write(void *uri, zval *value, zv

zval_string_or_null_to_lexbor_str(value, &str);

lxb_url_parser_clean(&lexbor_parser);

if (lxb_url_api_protocol_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors, "scheme");

Expand Down Expand Up @@ -304,6 +306,8 @@ static zend_result php_uri_parser_whatwg_username_write(void *uri, zval *value,

zval_string_or_null_to_lexbor_str(value, &str);

lxb_url_parser_clean(&lexbor_parser);

if (lxb_url_api_username_set(lexbor_uri, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors, "username");

Expand Down Expand Up @@ -333,6 +337,8 @@ static zend_result php_uri_parser_whatwg_password_write(void *uri, zval *value,

zval_string_or_null_to_lexbor_str(value, &str);

lxb_url_parser_clean(&lexbor_parser);

if (lxb_url_api_password_set(lexbor_uri, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors, "password");

Expand Down Expand Up @@ -418,6 +424,8 @@ static zend_result php_uri_parser_whatwg_host_write(void *uri, zval *value, zval

zval_string_or_null_to_lexbor_str(value, &str);

lxb_url_parser_clean(&lexbor_parser);

if (lxb_url_api_hostname_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors, "host");

Expand Down Expand Up @@ -447,6 +455,8 @@ static zend_result php_uri_parser_whatwg_port_write(void *uri, zval *value, zval

zval_long_or_null_to_lexbor_str(value, &str);

lxb_url_parser_clean(&lexbor_parser);

if (lxb_url_api_port_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors, "port");

Expand Down Expand Up @@ -476,6 +486,8 @@ static zend_result php_uri_parser_whatwg_path_write(void *uri, zval *value, zval

zval_string_or_null_to_lexbor_str(value, &str);

lxb_url_parser_clean(&lexbor_parser);

if (lxb_url_api_pathname_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors, "path");

Expand Down Expand Up @@ -505,6 +517,8 @@ static zend_result php_uri_parser_whatwg_query_write(void *uri, zval *value, zva

zval_string_or_null_to_lexbor_str(value, &str);

lxb_url_parser_clean(&lexbor_parser);

if (lxb_url_api_search_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors, "query string");

Expand Down Expand Up @@ -534,6 +548,8 @@ static zend_result php_uri_parser_whatwg_fragment_write(void *uri, zval *value,

zval_string_or_null_to_lexbor_str(value, &str);

lxb_url_parser_clean(&lexbor_parser);

if (lxb_url_api_hash_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
throw_invalid_url_exception_during_write(errors, "fragment");

Expand Down
29 changes: 29 additions & 0 deletions ext/zend_test/tests/observer_vm_interrupt_tailcall_return.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
--TEST--
Observer: VM interrupt during tailcall return to caller
--DESCRIPTION--
This exercises a VM interrupt raised immediately before a user function returns
to a caller that invoked it through DO_FCALL. On the tailcall VM, the caller's
saved opline must point to the opcode after DO_FCALL before a pending interrupt
is handled.
--EXTENSIONS--
zend_test
--INI--
opcache.jit=0
zend_test.observer.set_vm_interrupt_on_begin=1
--FILE--
<?php
function interrupt_before_return(VmInterruptComparable $left, VmInterruptComparable $right): void
{
$left < $right;
}

function call_interrupt_before_return(): void
{
interrupt_before_return(new VmInterruptComparable(2), new VmInterruptComparable(1));
}

call_interrupt_before_return();
echo "ok\n";
?>
--EXPECT--
ok
Loading