mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Merge branch 'PHP-8.1' into PHP-8.2
* PHP-8.1: Prevents double call to internal iterator rewind handler adds failing test case for #12060
This commit is contained in:
commit
c672a06954
10 changed files with 234 additions and 2 deletions
2
NEWS
2
NEWS
|
@ -10,6 +10,8 @@ PHP NEWS
|
||||||
(Girgias)
|
(Girgias)
|
||||||
. Fixed bug GH-12073 (Segfault when freeing incompletely initialized
|
. Fixed bug GH-12073 (Segfault when freeing incompletely initialized
|
||||||
closures). (ilutov)
|
closures). (ilutov)
|
||||||
|
. Fixed bug GH-12060 (Internal iterator rewind handler is called twice).
|
||||||
|
(ju1ius)
|
||||||
|
|
||||||
- DOM:
|
- DOM:
|
||||||
. Fix memory leak when setting an invalid DOMDocument encoding. (nielsdos)
|
. Fix memory leak when setting an invalid DOMDocument encoding. (nielsdos)
|
||||||
|
|
|
@ -623,6 +623,7 @@ ZEND_METHOD(InternalIterator, rewind) {
|
||||||
RETURN_THROWS();
|
RETURN_THROWS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intern->rewind_called = 1;
|
||||||
if (!intern->iter->funcs->rewind) {
|
if (!intern->iter->funcs->rewind) {
|
||||||
/* Allow calling rewind() if no iteration has happened yet,
|
/* Allow calling rewind() if no iteration has happened yet,
|
||||||
* even if the iterator does not support rewinding. */
|
* even if the iterator does not support rewinding. */
|
||||||
|
|
|
@ -4,5 +4,5 @@ PHP_ARG_ENABLE([zend-test],
|
||||||
[Enable zend_test extension])])
|
[Enable zend_test extension])])
|
||||||
|
|
||||||
if test "$PHP_ZEND_TEST" != "no"; then
|
if test "$PHP_ZEND_TEST" != "no"; then
|
||||||
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
|
PHP_NEW_EXTENSION(zend_test, test.c observer.c fiber.c iterators.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
ARG_ENABLE("zend-test", "enable zend_test extension", "no");
|
ARG_ENABLE("zend-test", "enable zend_test extension", "no");
|
||||||
|
|
||||||
if (PHP_ZEND_TEST != "no") {
|
if (PHP_ZEND_TEST != "no") {
|
||||||
EXTENSION("zend_test", "test.c observer.c fiber.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
EXTENSION("zend_test", "test.c observer.c fiber.c iterators.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
|
||||||
ADD_FLAG("CFLAGS_ZEND_TEST", "/D PHP_ZEND_TEST_EXPORTS ");
|
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 "php_test.h"
|
||||||
#include "observer.h"
|
#include "observer.h"
|
||||||
#include "fiber.h"
|
#include "fiber.h"
|
||||||
|
#include "iterators.h"
|
||||||
#include "zend_attributes.h"
|
#include "zend_attributes.h"
|
||||||
#include "zend_enum.h"
|
#include "zend_enum.h"
|
||||||
#include "zend_interfaces.h"
|
#include "zend_interfaces.h"
|
||||||
|
@ -845,6 +846,7 @@ PHP_MINIT_FUNCTION(zend_test)
|
||||||
|
|
||||||
zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU);
|
zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU);
|
||||||
zend_test_fiber_init();
|
zend_test_fiber_init();
|
||||||
|
zend_test_iterators_init();
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
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…
Add table
Add a link
Reference in a new issue