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
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ PHP NEWS
(Arnaud)
. Fixed bug GH-19306 (Generator can be resumed while fetching next value from
delegated Generator). (Arnaud)
. Fixed bug GH-19326 (Calling Generator::throw() on a running generator with
a non-Generator delegate crashes). (Arnaud)

- Curl:
. Add support for CURLINFO_CONN_ID in curl_getinfo() (thecaliskan)
Expand Down
18 changes: 18 additions & 0 deletions Zend/tests/gh19304.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
GH-19304: Incorrect anonymous class type name assertion
--FILE--
<?php

$foo = new class {
public self $v;
};

try {
$foo->v = 0;
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECT--
Cannot assign int to property class@anonymous::$v of type class@anonymous
36 changes: 36 additions & 0 deletions Zend/tests/gh19326.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--TEST--
GH-19326: Calling Generator::throw() on a running generator with a non-Generator delegate crashes
--FILE--
<?php

class It implements IteratorAggregate {
public function getIterator(): Generator {
yield "";
Fiber::suspend();
}
}

function g() {
yield from new It();
}

$b = g();
$b->rewind();

$fiber = new Fiber(function () use ($b) {
$b->next();
});

$fiber->start();

try {
$b->throw(new Exception('test'));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

$fiber->resume();

?>
--EXPECT--
Cannot resume an already running generator
1 change: 0 additions & 1 deletion Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1393,7 +1393,6 @@ static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scop
* null byte here, to avoid larger parts of the type being omitted by printing code later. */
size_t len = strlen(ZSTR_VAL(name));
if (len != ZSTR_LEN(name)) {
ZEND_ASSERT(scope && "This should only happen with resolved types");
return zend_string_init(ZSTR_VAL(name), len, 0);
}
return zend_string_copy(name);
Expand Down
14 changes: 12 additions & 2 deletions Zend/zend_generators.c
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,14 @@ ZEND_API zend_execute_data *zend_generator_check_placeholder_frame(zend_execute_
return ptr;
}

static void zend_generator_throw_exception(zend_generator *generator, zval *exception)
static zend_result zend_generator_throw_exception(zend_generator *generator, zval *exception)
{
if (generator->flags & ZEND_GENERATOR_CURRENTLY_RUNNING) {
zval_ptr_dtor(exception);
zend_throw_error(NULL, "Cannot resume an already running generator");
return FAILURE;
}

zend_execute_data *original_execute_data = EG(current_execute_data);

/* Throw the exception in the context of the generator. Decrementing the opline
Expand All @@ -520,6 +526,8 @@ static void zend_generator_throw_exception(zend_generator *generator, zval *exce
}

EG(current_execute_data) = original_execute_data;

return SUCCESS;
}

static void zend_generator_add_child(zend_generator *generator, zend_generator *child)
Expand Down Expand Up @@ -1026,7 +1034,9 @@ ZEND_METHOD(Generator, throw)
if (generator->execute_data) {
zend_generator *root = zend_generator_get_current(generator);

zend_generator_throw_exception(root, exception);
if (zend_generator_throw_exception(root, exception) == FAILURE) {
return;
}

zend_generator_resume(generator);

Expand Down
12 changes: 8 additions & 4 deletions ext/standard/array.c
Original file line number Diff line number Diff line change
Expand Up @@ -6051,7 +6051,7 @@ PHP_FUNCTION(array_multisort)
for (i = 0; i < MULTISORT_LAST; i++) {
parse_state[i] = 0;
}
func = ARRAYG(multisort_func) = ecalloc(argc, sizeof(bucket_compare_func_t));
func = ecalloc(argc, sizeof(bucket_compare_func_t));

/* Here we go through the input arguments and parse them. Each one can
* be either an array or a sort flag which follows an array. If not
Expand All @@ -6067,7 +6067,7 @@ PHP_FUNCTION(array_multisort)
/* We see the next array, so we update the sort flags of
* the previous array and reset the sort flags. */
if (i > 0) {
ARRAYG(multisort_func)[num_arrays - 1] = php_get_data_compare_func_unstable(sort_type, sort_order != PHP_SORT_ASC);
func[num_arrays - 1] = php_get_data_compare_func_unstable(sort_type, sort_order != PHP_SORT_ASC);
sort_order = PHP_SORT_ASC;
sort_type = PHP_SORT_REGULAR;
}
Expand Down Expand Up @@ -6119,8 +6119,6 @@ PHP_FUNCTION(array_multisort)
MULTISORT_ABORT;
}
}
/* Take care of the last array sort flags. */
ARRAYG(multisort_func)[num_arrays - 1] = php_get_data_compare_func_unstable(sort_type, sort_order != PHP_SORT_ASC);

/* Make sure the arrays are of the same size. */
array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
Expand All @@ -6138,6 +6136,11 @@ PHP_FUNCTION(array_multisort)
RETURN_TRUE;
}

/* Take care of the last array sort flags. */
func[num_arrays - 1] = php_get_data_compare_func_unstable(sort_type, sort_order != PHP_SORT_ASC);
bucket_compare_func_t *old_multisort_func = ARRAYG(multisort_func);
ARRAYG(multisort_func) = func;

/* Create the indirection array. This array is of size MxN, where
* M is the number of entries in each input array and N is the number
* of the input arrays + 1. The last column is UNDEF to indicate the end
Expand Down Expand Up @@ -6214,6 +6217,7 @@ PHP_FUNCTION(array_multisort)
efree(indirect);
efree(func);
efree(arrays);
ARRAYG(multisort_func) = old_multisort_func;
}
/* }}} */

Expand Down
40 changes: 40 additions & 0 deletions ext/standard/tests/array/gh19300_1.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
--TEST--
GH-19300 (Nested array_multisort invocation with error breaks) - correct invocation variation
--FILE--
<?php
class MyStringable {
public function __construct(private string $data) {}
public function __tostring() {
array_multisort([]); // Trigger update of array sort globals in happy path
return $this->data;
}
}

$inputs = [
new MyStringable('3'),
new MyStringable('1'),
new MyStringable('2'),
];

var_dump(array_multisort($inputs, SORT_STRING));
var_dump($inputs);
?>
--EXPECT--
bool(true)
array(3) {
[0]=>
object(MyStringable)#2 (1) {
["data":"MyStringable":private]=>
string(1) "1"
}
[1]=>
object(MyStringable)#3 (1) {
["data":"MyStringable":private]=>
string(1) "2"
}
[2]=>
object(MyStringable)#1 (1) {
["data":"MyStringable":private]=>
string(1) "3"
}
}
40 changes: 40 additions & 0 deletions ext/standard/tests/array/gh19300_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
--TEST--
GH-19300 (Nested array_multisort invocation with error breaks) - error variation
--FILE--
<?php

function error_handle($level, $message, $file = '', $line = 0){
try {
array_multisort($a, SORT_ASC); // Trigger multisort abort
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
}
set_error_handler('error_handle');

$inputs = [
new stdClass,
new stdClass,
new stdClass,
];

var_dump(array_multisort($inputs, SORT_NUMERIC));
var_dump($inputs);
?>
--EXPECT--
array_multisort(): Argument #1 ($array) must be an array or a sort flag
array_multisort(): Argument #1 ($array) must be an array or a sort flag
array_multisort(): Argument #1 ($array) must be an array or a sort flag
array_multisort(): Argument #1 ($array) must be an array or a sort flag
bool(true)
array(3) {
[0]=>
object(stdClass)#1 (0) {
}
[1]=>
object(stdClass)#2 (0) {
}
[2]=>
object(stdClass)#3 (0) {
}
}
2 changes: 1 addition & 1 deletion main/streams/transports.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in
}

stream = (factory)(protocol, n,
(char*)name, namelen, persistent_id, options, flags, timeout,
name, namelen, persistent_id, options, flags, timeout,
context STREAMS_REL_CC);

if (stream) {
Expand Down