mirror of
https://github.com/php/php-src.git
synced 2024-09-21 09:57:23 +00:00
Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2: Prevents double call to internal iterator rewind handler adds failing test case for #12060
This commit is contained in:
commit
d7273c5963
3
NEWS
3
NEWS
@ -8,6 +8,9 @@ PHP NEWS
|
||||
(Girgias)
|
||||
. Fixed bug GH-12073 (Segfault when freeing incompletely initialized
|
||||
closures). (ilutov)
|
||||
. Fixed bug GH-12060 (Internal iterator rewind handler is called twice).
|
||||
(ju1ius)
|
||||
|
||||
|
||||
- FPM:
|
||||
. Fixed GH-12077 (PHP 8.3.0RC1 borked socket-close-on-exec.phpt).
|
||||
|
@ -623,6 +623,7 @@ ZEND_METHOD(InternalIterator, rewind) {
|
||||
RETURN_THROWS();
|
||||
}
|
||||
|
||||
intern->rewind_called = 1;
|
||||
if (!intern->iter->funcs->rewind) {
|
||||
/* Allow calling rewind() if no iteration has happened yet,
|
||||
* even if the iterator does not support rewinding. */
|
||||
|
@ -4,5 +4,5 @@ PHP_ARG_ENABLE([zend-test],
|
||||
[Enable zend_test extension])])
|
||||
|
||||
if test "$PHP_ZEND_TEST" != "no"; then
|
||||
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c object_handlers.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
|
||||
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c iterators.c object_handlers.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
|
||||
fi
|
||||
|
@ -3,6 +3,6 @@
|
||||
ARG_ENABLE("zend-test", "enable zend_test extension", "no");
|
||||
|
||||
if (PHP_ZEND_TEST != "no") {
|
||||
EXTENSION("zend_test", "test.c observer.c fiber.c object_handlers.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
||||
EXTENSION("zend_test", "test.c observer.c fiber.c iterators.c object_handlers.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
||||
ADD_FLAG("CFLAGS_ZEND_TEST", "/D PHP_ZEND_TEST_EXPORTS ");
|
||||
}
|
||||
|
121
ext/zend_test/iterators.c
Normal file
121
ext/zend_test/iterators.c
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#include "iterators.h"
|
||||
#include "zend_API.h"
|
||||
#include "iterators_arginfo.h"
|
||||
|
||||
#include <zend_interfaces.h>
|
||||
#include "php.h"
|
||||
|
||||
#define DUMP(s) php_output_write((s), sizeof((s)) - 1)
|
||||
|
||||
static zend_class_entry *traversable_test_ce;
|
||||
|
||||
// Dummy iterator that yields numbers from 0..4,
|
||||
// while printing operations to the output buffer
|
||||
typedef struct {
|
||||
zend_object_iterator intern;
|
||||
zval current;
|
||||
} test_traversable_it;
|
||||
|
||||
static test_traversable_it *test_traversable_it_fetch(zend_object_iterator *iter) {
|
||||
return (test_traversable_it *)iter;
|
||||
}
|
||||
|
||||
static void test_traversable_it_dtor(zend_object_iterator *iter) {
|
||||
DUMP("TraversableTest::drop\n");
|
||||
test_traversable_it *iterator = test_traversable_it_fetch(iter);
|
||||
zval_ptr_dtor(&iterator->intern.data);
|
||||
}
|
||||
|
||||
static void test_traversable_it_rewind(zend_object_iterator *iter) {
|
||||
DUMP("TraversableTest::rewind\n");
|
||||
test_traversable_it *iterator = test_traversable_it_fetch(iter);
|
||||
ZVAL_LONG(&iterator->current, 0);
|
||||
}
|
||||
|
||||
static void test_traversable_it_next(zend_object_iterator *iter) {
|
||||
DUMP("TraversableTest::next\n");
|
||||
test_traversable_it *iterator = test_traversable_it_fetch(iter);
|
||||
ZVAL_LONG(&iterator->current, Z_LVAL(iterator->current) + 1);
|
||||
}
|
||||
|
||||
static int test_traversable_it_valid(zend_object_iterator *iter) {
|
||||
DUMP("TraversableTest::valid\n");
|
||||
test_traversable_it *iterator = test_traversable_it_fetch(iter);
|
||||
if (Z_LVAL(iterator->current) < 4) {
|
||||
return SUCCESS;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
static void test_traversable_it_key(zend_object_iterator *iter, zval *return_value) {
|
||||
DUMP("TraversableTest::key\n");
|
||||
test_traversable_it *iterator = test_traversable_it_fetch(iter);
|
||||
ZVAL_LONG(return_value, Z_LVAL(iterator->current));
|
||||
}
|
||||
|
||||
static zval *test_traversable_it_current(zend_object_iterator *iter) {
|
||||
DUMP("TraversableTest::current\n");
|
||||
test_traversable_it *iterator = test_traversable_it_fetch(iter);
|
||||
return &iterator->current;
|
||||
}
|
||||
|
||||
static const zend_object_iterator_funcs test_traversable_it_vtable = {
|
||||
test_traversable_it_dtor,
|
||||
test_traversable_it_valid,
|
||||
test_traversable_it_current,
|
||||
test_traversable_it_key,
|
||||
test_traversable_it_next,
|
||||
test_traversable_it_rewind,
|
||||
NULL, // invalidate_current
|
||||
NULL, // get_gc
|
||||
};
|
||||
|
||||
static zend_object_iterator *test_traversable_get_iterator(
|
||||
zend_class_entry *ce,
|
||||
zval *object,
|
||||
int by_ref
|
||||
) {
|
||||
test_traversable_it *iterator;
|
||||
|
||||
if (by_ref) {
|
||||
zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iterator = emalloc(sizeof(test_traversable_it));
|
||||
zend_iterator_init((zend_object_iterator*)iterator);
|
||||
|
||||
ZVAL_OBJ_COPY(&iterator->intern.data, Z_OBJ_P(object));
|
||||
iterator->intern.funcs = &test_traversable_it_vtable;
|
||||
ZVAL_LONG(&iterator->current, 0);
|
||||
|
||||
return (zend_object_iterator*)iterator;
|
||||
}
|
||||
|
||||
ZEND_METHOD(ZendTest_Iterators_TraversableTest, __construct) {
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
}
|
||||
|
||||
ZEND_METHOD(ZendTest_Iterators_TraversableTest, getIterator) {
|
||||
ZEND_PARSE_PARAMETERS_NONE();
|
||||
zend_create_internal_iterator_zval(return_value, ZEND_THIS);
|
||||
}
|
||||
|
||||
void zend_test_iterators_init(void) {
|
||||
traversable_test_ce = register_class_ZendTest_Iterators_TraversableTest(zend_ce_aggregate);
|
||||
traversable_test_ce->get_iterator = test_traversable_get_iterator;
|
||||
}
|
21
ext/zend_test/iterators.h
Normal file
21
ext/zend_test/iterators.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| https://www.php.net/license/3_01.txt |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
#ifndef ZEND_TEST_ITERATORS_H
|
||||
#define ZEND_TEST_ITERATORS_H
|
||||
|
||||
void zend_test_iterators_init(void);
|
||||
|
||||
#endif
|
||||
|
14
ext/zend_test/iterators.stub.php
Normal file
14
ext/zend_test/iterators.stub.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @generate-class-entries static
|
||||
* @undocumentable
|
||||
*/
|
||||
|
||||
namespace ZendTest\Iterators;
|
||||
|
||||
final class TraversableTest implements \IteratorAggregate
|
||||
{
|
||||
public function __construct() {}
|
||||
public function getIterator(): \Iterator {}
|
||||
}
|
31
ext/zend_test/iterators_arginfo.h
generated
Normal file
31
ext/zend_test/iterators_arginfo.h
generated
Normal file
@ -0,0 +1,31 @@
|
||||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: f9558686a7393ddd4ba3302e811f70d4496317ee */
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ZendTest_Iterators_TraversableTest___construct, 0, 0, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ZendTest_Iterators_TraversableTest_getIterator, 0, 0, Iterator, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
|
||||
static ZEND_METHOD(ZendTest_Iterators_TraversableTest, __construct);
|
||||
static ZEND_METHOD(ZendTest_Iterators_TraversableTest, getIterator);
|
||||
|
||||
|
||||
static const zend_function_entry class_ZendTest_Iterators_TraversableTest_methods[] = {
|
||||
ZEND_ME(ZendTest_Iterators_TraversableTest, __construct, arginfo_class_ZendTest_Iterators_TraversableTest___construct, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(ZendTest_Iterators_TraversableTest, getIterator, arginfo_class_ZendTest_Iterators_TraversableTest_getIterator, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
static zend_class_entry *register_class_ZendTest_Iterators_TraversableTest(zend_class_entry *class_entry_IteratorAggregate)
|
||||
{
|
||||
zend_class_entry ce, *class_entry;
|
||||
|
||||
INIT_NS_CLASS_ENTRY(ce, "ZendTest\\Iterators", "TraversableTest", class_ZendTest_Iterators_TraversableTest_methods);
|
||||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||
class_entry->ce_flags |= ZEND_ACC_FINAL;
|
||||
zend_class_implements(class_entry, 1, class_entry_IteratorAggregate);
|
||||
|
||||
return class_entry;
|
||||
}
|
@ -24,6 +24,7 @@
|
||||
#include "php_test.h"
|
||||
#include "observer.h"
|
||||
#include "fiber.h"
|
||||
#include "iterators.h"
|
||||
#include "object_handlers.h"
|
||||
#include "zend_attributes.h"
|
||||
#include "zend_enum.h"
|
||||
@ -1073,6 +1074,7 @@ PHP_MINIT_FUNCTION(zend_test)
|
||||
|
||||
zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU);
|
||||
zend_test_fiber_init();
|
||||
zend_test_iterators_init();
|
||||
zend_test_object_handlers_init();
|
||||
|
||||
le_throwing_resource = zend_register_list_destructors_ex(le_throwing_resource_dtor, NULL, "throwing resource", module_number);
|
||||
|
40
ext/zend_test/tests/iterators/double-rewind.phpt
Normal file
40
ext/zend_test/tests/iterators/double-rewind.phpt
Normal file
@ -0,0 +1,40 @@
|
||||
--TEST--
|
||||
Tests that internal iterator's rewind function is called once
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$subject = new \ZendTest\Iterators\TraversableTest();
|
||||
$it = $subject->getIterator();
|
||||
var_dump($it);
|
||||
foreach ($it as $key => $value) {
|
||||
echo "{$key} => {$value}\n";
|
||||
}
|
||||
?>
|
||||
--EXPECT--
|
||||
object(InternalIterator)#3 (0) {
|
||||
}
|
||||
TraversableTest::rewind
|
||||
TraversableTest::valid
|
||||
TraversableTest::current
|
||||
TraversableTest::key
|
||||
0 => 0
|
||||
TraversableTest::next
|
||||
TraversableTest::valid
|
||||
TraversableTest::current
|
||||
TraversableTest::key
|
||||
1 => 1
|
||||
TraversableTest::next
|
||||
TraversableTest::valid
|
||||
TraversableTest::current
|
||||
TraversableTest::key
|
||||
2 => 2
|
||||
TraversableTest::next
|
||||
TraversableTest::valid
|
||||
TraversableTest::current
|
||||
TraversableTest::key
|
||||
3 => 3
|
||||
TraversableTest::next
|
||||
TraversableTest::valid
|
||||
TraversableTest::drop
|
Loading…
Reference in New Issue
Block a user