Skip to content

Commit 8525ece

Browse files
committed
Merge branch 'master'
2 parents a2a86c8 + b39ff33 commit 8525ece

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1130
-215
lines changed

.github/workflows/push.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ on:
2020
- '**'
2121
permissions:
2222
contents: read
23+
concurrency:
24+
group: ${{ github.workflow }}-${{ github.event.pull_request.url || github.run_id }}
25+
cancel-in-progress: true
2326
env:
2427
CC: ccache gcc
2528
CXX: ccache g++
@@ -186,7 +189,7 @@ jobs:
186189
- name: git config
187190
run: git config --global core.autocrlf false && git config --global core.eol lf
188191
- name: git checkout
189-
uses: actions/checkout@v2
192+
uses: actions/checkout@v3
190193
- name: Setup MySQL
191194
run: |
192195
choco install mysql -y --no-progress --params="/port:3306"

TSRM/threads.m4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ void *thread_routine(void *data) {
7373
return data;
7474
}
7575
76-
int main() {
76+
int main(void) {
7777
pthread_t thd;
7878
pthread_mutexattr_t mattr;
7979
int data = 1;

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ PHP 8.3 UPGRADE NOTES
9696
. password_hash() will now chain the underlying Random\RandomException
9797
as the ValueError’s $previous Exception when salt generation fails.
9898
. proc_open() $command array must now have at least one non empty element.
99+
. array_sum() and array_product() now warn when values in the array cannot be converted to int/float.
100+
Previously arrays and objects where ignored whilst every other value was cast to int.
101+
Moreover, objects that define a numeric cast (e.g. GMP) are now casted instead of ignored.
102+
RFC: https://wiki.php.net/rfc/saner-array-sum-product
99103

100104
========================================
101105
6. New Functions

UPGRADING.INTERNALS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ PHP 8.3 INTERNALS UPGRADE NOTES
3737
* The return types of the following functions have been changed from
3838
`bool` to `zend_result`:
3939
- zend_fiber_init_context()
40+
* The fast_add_function() has been removed, use add_function() that will
41+
call the static inline add_function_fast() instead.
4042

4143
========================
4244
2. Build system changes

Zend/Zend.m4

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ int stack_grows_downwards(uintptr_t arg) {
162162
return (uintptr_t)&local < arg;
163163
}
164164
165-
int main() {
165+
int main(void) {
166166
int local;
167167
168168
f = stack_grows_downwards;
@@ -250,7 +250,7 @@ typedef union _mm_align_test {
250250
#define ZEND_MM_ALIGNMENT (sizeof(mm_align_test))
251251
#endif
252252
253-
int main()
253+
int main(void)
254254
{
255255
size_t i = ZEND_MM_ALIGNMENT;
256256
int zeros = 0;

Zend/tests/gh10709.phpt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
GH-10709: Recursive class constant evaluation
3+
--FILE--
4+
<?php
5+
6+
class B { const C = A::C . "B"; }
7+
8+
spl_autoload_register(function ($class) {
9+
class A { const C = "A"; }
10+
var_dump(B::C);
11+
});
12+
13+
try {
14+
new B();
15+
} catch (Error $e) {
16+
echo $e->getMessage(), "\n";
17+
}
18+
19+
?>
20+
--EXPECT--
21+
string(2) "AB"

Zend/tests/gh10709_2.phpt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-10709: Recursive class constant evaluation
3+
--FILE--
4+
<?php
5+
6+
class B {
7+
public $prop = A::C;
8+
}
9+
10+
spl_autoload_register(function ($class) {
11+
class A { const C = "A"; }
12+
var_dump(new B());
13+
});
14+
15+
try {
16+
var_dump(new B());
17+
} catch (Error $e) {
18+
echo $e->getMessage(), "\n";
19+
}
20+
21+
?>
22+
--EXPECT--
23+
object(B)#2 (1) {
24+
["prop"]=>
25+
string(1) "A"
26+
}
27+
object(B)#2 (1) {
28+
["prop"]=>
29+
string(1) "A"
30+
}

Zend/tests/gh10709_3.phpt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
GH-10709: Recursive class constant evaluation with outer call failing
3+
--FILE--
4+
<?php
5+
6+
class S {
7+
public function __toString() {
8+
static $i = 0;
9+
$i++;
10+
if ($i === 1) {
11+
return 'S';
12+
} else {
13+
throw new \Exception('Thrown from S');
14+
}
15+
}
16+
}
17+
18+
const S = new S();
19+
20+
class B {
21+
public $prop = A::C . S;
22+
}
23+
24+
spl_autoload_register(function ($class) {
25+
class A { const C = "A"; }
26+
var_dump(new B());
27+
});
28+
29+
var_dump(new B());
30+
31+
?>
32+
--EXPECTF--
33+
object(B)#3 (1) {
34+
["prop"]=>
35+
string(2) "AS"
36+
}
37+
38+
Fatal error: Uncaught Exception: Thrown from S in %s:%d
39+
Stack trace:
40+
#0 %s(%d): [constant expression]()
41+
#1 %s(%d): S->__toString()
42+
#2 {main}
43+
thrown in %s on line %d

Zend/tests/readonly_props/readonly_clone_error1.phpt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
--TEST--
22
Readonly property cannot be reset twice during cloning
3-
--SKIPIF--
4-
<?php
5-
if (function_exists('opcache_get_status') && (opcache_get_status()["jit"]["enabled"] ?? false)) {
6-
die('skip Not yet implemented for JIT');
7-
}
8-
?>
93
--FILE--
104
<?php
115

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
Readonly property cannot be op-assigned twice during cloning
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public function __construct(
8+
public readonly int $bar
9+
) {}
10+
11+
public function __clone()
12+
{
13+
$this->bar += 2;
14+
var_dump($this);
15+
$this->bar += 3;
16+
}
17+
}
18+
19+
$foo = new Foo(1);
20+
21+
try {
22+
clone $foo;
23+
} catch (Error $exception) {
24+
echo $exception->getMessage() . "\n";
25+
}
26+
27+
try {
28+
clone $foo;
29+
} catch (Error $exception) {
30+
echo $exception->getMessage() . "\n";
31+
}
32+
33+
?>
34+
--EXPECT--
35+
object(Foo)#2 (1) {
36+
["bar"]=>
37+
int(3)
38+
}
39+
Cannot modify readonly property Foo::$bar
40+
object(Foo)#2 (1) {
41+
["bar"]=>
42+
int(3)
43+
}
44+
Cannot modify readonly property Foo::$bar
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
--TEST--
2+
Readonly property clone indirect variation for JIT
3+
--FILE--
4+
<?php
5+
6+
trait CloneSetOnceTrait {
7+
public function __clone() {
8+
$this->prop[] = 1;
9+
}
10+
}
11+
12+
trait CloneSetTwiceTrait {
13+
public function __clone() {
14+
$this->prop[] = 1;
15+
$this->prop[] = 2;
16+
}
17+
}
18+
19+
class TestSetOnce {
20+
use CloneSetOnceTrait;
21+
public readonly array $prop;
22+
public function __construct() {
23+
$this->prop = [];
24+
}
25+
}
26+
27+
class TestSetTwice {
28+
use CloneSetTwiceTrait;
29+
public readonly array $prop;
30+
public function __construct() {
31+
$this->prop = [];
32+
}
33+
}
34+
35+
try {
36+
var_dump(clone (new TestSetOnce()));
37+
} catch (Error $e) {
38+
echo $e->getMessage(), "\n";
39+
}
40+
41+
try {
42+
var_dump(clone (new TestSetOnce()));
43+
} catch (Error $e) {
44+
echo $e->getMessage(), "\n";
45+
}
46+
47+
try {
48+
var_dump(clone (new TestSetTwice()));
49+
} catch (Error $e) {
50+
echo $e->getMessage(), "\n";
51+
}
52+
53+
try {
54+
var_dump(clone (new TestSetTwice()));
55+
} catch (Error $e) {
56+
echo $e->getMessage(), "\n";
57+
}
58+
59+
?>
60+
--EXPECT--
61+
object(TestSetOnce)#2 (1) {
62+
["prop"]=>
63+
array(1) {
64+
[0]=>
65+
int(1)
66+
}
67+
}
68+
object(TestSetOnce)#1 (1) {
69+
["prop"]=>
70+
array(1) {
71+
[0]=>
72+
int(1)
73+
}
74+
}
75+
Cannot modify readonly property TestSetTwice::$prop
76+
Cannot modify readonly property TestSetTwice::$prop

Zend/tests/readonly_props/readonly_clone_success1.phpt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
--TEST--
22
Readonly property can be reset once during cloning
3-
--SKIPIF--
4-
<?php
5-
if (function_exists('opcache_get_status') && (opcache_get_status()["jit"]["enabled"] ?? false)) {
6-
die('skip Not yet implemented for JIT');
7-
}
8-
?>
93
--FILE--
104
<?php
115

Zend/tests/readonly_props/readonly_clone_success3.phpt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
--TEST--
22
__clone() can indirectly modify unlocked readonly properties
3-
--SKIPIF--
4-
<?php
5-
if (function_exists('opcache_get_status') && (opcache_get_status()["jit"]["enabled"] ?? false)) {
6-
die('skip Not yet implemented for JIT');
7-
}
8-
?>
93
--FILE--
104
<?php
115

Zend/zend.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,34 @@ ZEND_API void zend_deactivate(void) /* {{{ */
12811281

12821282
zend_destroy_rsrc_list(&EG(regular_list));
12831283

1284+
/* See GH-8646: https://github.com/php/php-src/issues/8646
1285+
*
1286+
* Interned strings that hold class entries can get a corresponding slot in map_ptr for the CE cache.
1287+
* map_ptr works like a bump allocator: there is a counter which increases to allocate the next slot in the map.
1288+
*
1289+
* For class name strings in non-opcache we have:
1290+
* - on startup: permanent + interned
1291+
* - on request: interned
1292+
* For class name strings in opcache we have:
1293+
* - on startup: permanent + interned
1294+
* - on request: either not interned at all, which we can ignore because they won't get a CE cache entry
1295+
* or they were already permanent + interned
1296+
* or we get a new permanent + interned string in the opcache persistence code
1297+
*
1298+
* Notice that the map_ptr layout always has the permanent strings first, and the request strings after.
1299+
* In non-opcache, a request string may get a slot in map_ptr, and that interned request string
1300+
* gets destroyed at the end of the request. The corresponding map_ptr slot can thereafter never be used again.
1301+
* This causes map_ptr to keep reallocating to larger and larger sizes.
1302+
*
1303+
* We solve it as follows:
1304+
* We can check whether we had any interned request strings, which only happens in non-opcache.
1305+
* If we have any, we reset map_ptr to the last permanent string.
1306+
* We can't lose any permanent strings because of map_ptr's layout.
1307+
*/
1308+
if (zend_hash_num_elements(&CG(interned_strings)) > 0) {
1309+
zend_map_ptr_reset();
1310+
}
1311+
12841312
#if GC_BENCH
12851313
fprintf(stderr, "GC Statistics\n");
12861314
fprintf(stderr, "-------------\n");

0 commit comments

Comments
 (0)