Skip to content

Commit 2a46d43

Browse files
committed
Merge branch 'master' into htmlspecialchars
2 parents c6cb392 + 13e0fb9 commit 2a46d43

File tree

200 files changed

+5547
-2406
lines changed

Some content is hidden

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

200 files changed

+5547
-2406
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
/ext/pdo_sqlite @SakiTakamachi
4545
/ext/pgsql @devnexen
4646
/ext/random @TimWolla @zeriyoshi
47+
/ext/reflection @DanielEScherzer
4748
/ext/session @Girgias
4849
/ext/simplexml @nielsdos
4950
/ext/soap @nielsdos

EXTENSIONS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ STATUS: Working
412412
-------------------------------------------------------------------------------
413413
EXTENSION: random
414414
PRIMARY MAINTAINER Go Kudo <zeriyoshi@php.net> (2022 - 2024)
415-
Tim Düsterhus <timwolla@php.net> (2022 - 2024)
415+
Tim Düsterhus <timwolla@php.net> (2022 - 2025)
416416
MAINTENANCE: Maintained
417417
STATUS: Working
418418
SINCE: 8.2.0
@@ -426,6 +426,7 @@ EXTENSION: reflection
426426
PRIMARY MAINTAINER: Marcus Börger <helly@php.net> (2003 - 2009)
427427
Johannes Schlüter <johannes@php.net> (2006 - 2014)
428428
Nikita Popov <nikic@php.net> (2019 - 2020)
429+
Daniel Scherzer <daniel.e.scherzer@gmail.com> (2025 - 2025)
429430
MAINTENANCE: Maintained
430431
STATUS: Working
431432
-------------------------------------------------------------------------------

NEWS

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ PHP NEWS
3737
(ilutov)
3838
. Fixed bug GH-18033 (NULL-ptr dereference when using register_tick_function
3939
in destructor). (nielsdos)
40+
. Fixed bug GH-18026 (Improve "expecting token" error for ampersand). (ilutov)
41+
. Added the (void) cast to indicate that not using a value is intentional.
42+
(timwolla)
43+
. Added get_error_handler(), get_exception_handler() functions. (Arnaud)
4044

4145
- Curl:
4246
. Added curl_multi_get_handles(). (timwolla)
@@ -59,6 +63,10 @@ PHP NEWS
5963
- Fileinfo:
6064
. Upgrade to file 5.46. (nielsdos)
6165

66+
- FPM:
67+
. Fixed GH-17645 (FPM with httpd ProxyPass does not decode script path).
68+
(Jakub Zelenka)
69+
6270
- GD:
6371
. Fixed bug #68629 (Transparent artifacts when using imagerotate). (pierre,
6472
cmb)
@@ -88,6 +96,8 @@ PHP NEWS
8896

8997
- PCRE:
9098
. Upgraded to pre2lib from 10.44 to 10.45. (nielsdos)
99+
. Remove PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK from pcre compile options.
100+
(mvorisek)
91101

92102
- PDO_PGSQL:
93103
. Added Iterable support for PDO::pgsqlCopyFromArray. (KentarouTakeda)
@@ -102,6 +112,8 @@ PHP NEWS
102112
. pg_connect checks if connection_string contains any null byte,
103113
pg_close_stmt check if the statement contains any null byte.
104114
(David Carlier)
115+
. Added pg_service to get the connection current service identifier.
116+
(David Carlier)
105117

106118
- POSIX:
107119
. Added POSIX_SC_OPEN_MAX constant to get the number of file descriptors
@@ -118,12 +130,18 @@ PHP NEWS
118130
(DanielEScherzer)
119131
. Fixed bug GH-12856 (ReflectionClass::getStaticPropertyValue() returns UNDEF
120132
zval for uninitialized typed properties). (nielsdos)
133+
. Fixed bug GH-15766 (ReflectionClass::toString() should have better output
134+
for enums). (DanielEScherzer)
121135

122136
- Session:
123137
. session_start() throws a ValueError on option argument if not a hashmap
124138
or a TypeError if read_and_close value is not compatible with int.
125139
(David Carlier)
126140

141+
- SimpleXML:
142+
. Fixed bug GH-12231 (SimpleXML xpath should warn when returning other return
143+
types than node lists). (nielsdos)
144+
127145
- SNMP:
128146
. snmpget, snmpset, snmp_get2, snmp_set2, snmp_get3, snmp_set3 and
129147
SNMP::__construct() throw an exception on invalid hostname, community
@@ -169,6 +187,8 @@ PHP NEWS
169187
- Standard:
170188
. Fixed crypt() tests on musl when using --with-external-libcrypt
171189
(Michael Orlitzky).
190+
. Fixed bug GH-18062 (is_callable(func(...), callable_name: $name) for first
191+
class callables returns wrong name). (timwolla)
172192

173193
- Streams:
174194
. Fixed bug GH-16889 (stream_select() timeout useless for pipes on Windows).

UPGRADING

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ PHP 8.5 UPGRADE NOTES
5959
. pcntl_exec() now throws ValueErrors when entries or keys of the
6060
$env_vars parameter contain null bytes.
6161

62+
- PCRE:
63+
. The extension is compiled without semi-deprecated
64+
PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK compile option.
65+
https://github.com/PCRE2Project/pcre2/issues/736#issuecomment-2754024651
66+
6267
- PDO:
6368
. The constructor arguments set in conjunction with PDO::FETCH_CLASS now
6469
follow the usual CUFA (call_user_func_array) semantics.
@@ -82,6 +87,11 @@ PHP 8.5 UPGRADE NOTES
8287
. A ValueError is now thrown when trying to set a cursor name that is too
8388
long on a PDOStatement resulting from the Firebird driver.
8489

90+
- SimpleXML:
91+
- Passing an XPath expression that returns something other than a node set
92+
to SimpleXMLElement::xpath() will now emit a warning and return false,
93+
instead of silently failing and returning an empty array.
94+
8595
- SPL:
8696
. ArrayObject no longer accepts enums, as modifying the $name or $value
8797
properties can break engine assumptions.
@@ -101,6 +111,9 @@ PHP 8.5 UPGRADE NOTES
101111
. Fatal Errors (such as an exceeded maximum execution time) now include a
102112
backtrace.
103113
RFC: https://wiki.php.net/rfc/error_backtraces_v2
114+
. Added the (void) to indicate that not using a value is intentional. The
115+
(void) cast does nothing by itself.
116+
RFC: https://wiki.php.net/rfc/marking_return_value_as_important
104117

105118
- Curl:
106119
. Added support for share handles that are persisted across multiple PHP
@@ -144,6 +157,10 @@ PHP 8.5 UPGRADE NOTES
144157
. Added a new --ini=diff option to print INI settings changed from the builtin
145158
default.
146159

160+
- FPM:
161+
. FPM with httpd ProxyPass decodes the full scirpt path script path. Added
162+
fastcgi.script_path_encoded INI setting to prevent this new behevior.
163+
147164
========================================
148165
4. Deprecated Functionality
149166
========================================
@@ -189,6 +206,11 @@ PHP 8.5 UPGRADE NOTES
189206
. posix_fpathconf checks invalid file descriptors and sets
190207
last_error to EBADF and raises an E_WARNING message.
191208

209+
- Reflection:
210+
. The output of ReflectionClass::toString() for enums has changed to
211+
better indicate that the class is an enum, and that the enum cases
212+
are enum cases rather than normal class constants.
213+
192214
- Session:
193215
. session_start is stricter in regard of the option argument.
194216
It throws a ValueError if the whole is not a hashmap or
@@ -227,6 +249,14 @@ PHP 8.5 UPGRADE NOTES
227249
6. New Functions
228250
========================================
229251

252+
- Core:
253+
. get_error_handler() allows retrieving the current user-defined error handler
254+
function.
255+
RFC: https://wiki.php.net/rfc/get-error-exception-handler
256+
. get_exception_handler() allows retrieving the current user-defined exception
257+
handler function.
258+
RFC: https://wiki.php.net/rfc/get-error-exception-handler
259+
230260
- Curl:
231261
. curl_multi_get_handles() allows retrieving all CurlHandles current
232262
attached to a CurlMultiHandle. This includes both handles added using
@@ -248,6 +278,7 @@ PHP 8.5 UPGRADE NOTES
248278
. pg_close_stmt offers an alternative way to close a prepared
249279
statement from the DEALLOCATE sql command in that we can reuse
250280
its name afterwards.
281+
. pg_service returns the ongoing service name of the connection.
251282

252283
- Reflection:
253284
. ReflectionConstant::getFileName() was introduced.

UPGRADING.INTERNALS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ PHP 8.5 INTERNALS UPGRADE NOTES
1919
a value to a non-reference zval.
2020
. Added zval_ptr_safe_dtor() to safely destroy a zval when a destructor
2121
could interfere.
22+
. zend_get_callable_name() now returns the name of the underlying function
23+
for fake closures.
24+
. Added smart_string_append_printf() matching smart_str_append_printf() for
25+
char* instead of zend_string*-based smart strings.
26+
. Added php_build_provider() to retrieve the value of PHP_BUILD_PROVIDER at
27+
runtime.
2228

2329
========================
2430
2. Build system changes

Zend/Optimizer/block_pass.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,9 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
274274
* If it's not local, then the other blocks successors must also eventually either FREE or consume the temporary,
275275
* hence removing the temporary is not safe in the general case, especially when other consumers are not FREE.
276276
* A FREE may not be removed without also removing the source's result, because otherwise that would cause a memory leak. */
277-
if (opline->op1_type == IS_TMP_VAR) {
277+
if (opline->extended_value == ZEND_FREE_VOID_CAST) {
278+
/* Keep the ZEND_FREE opcode alive. */
279+
} else if (opline->op1_type == IS_TMP_VAR) {
278280
src = VAR_SOURCE(opline->op1);
279281
if (src) {
280282
switch (src->opcode) {

Zend/Optimizer/compact_literals.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
165165
HashTable hash;
166166
zend_string *key = NULL;
167167
void *checkpoint = zend_arena_checkpoint(ctx->arena);
168-
int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot;
168+
int *const_slot, *class_slot, *func_slot, *bind_var_slot, *property_slot, *method_slot, *jmp_slot;
169169

170170
if (op_array->last_literal) {
171171
info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info));
@@ -175,6 +175,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
175175
end = opline + op_array->last;
176176
while (opline < end) {
177177
switch (opline->opcode) {
178+
case ZEND_JMP_FRAMELESS:
179+
LITERAL_INFO(opline->op1.constant, 1);
180+
break;
178181
case ZEND_INIT_FCALL_BY_NAME:
179182
LITERAL_INFO(opline->op2.constant, 2);
180183
break;
@@ -480,13 +483,14 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
480483
zend_hash_clean(&hash);
481484
op_array->last_literal = j;
482485

483-
const_slot = zend_arena_alloc(&ctx->arena, j * 6 * sizeof(int));
484-
memset(const_slot, -1, j * 6 * sizeof(int));
486+
const_slot = zend_arena_alloc(&ctx->arena, j * 7 * sizeof(int));
487+
memset(const_slot, -1, j * 7 * sizeof(int));
485488
class_slot = const_slot + j;
486489
func_slot = class_slot + j;
487490
bind_var_slot = func_slot + j;
488491
property_slot = bind_var_slot + j;
489492
method_slot = property_slot + j;
493+
jmp_slot = method_slot + j;
490494

491495
/* Update opcodes to use new literals table */
492496
cache_size = zend_op_array_extension_handles * sizeof(void*);
@@ -773,10 +777,19 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
773777
break;
774778
case ZEND_DECLARE_ANON_CLASS:
775779
case ZEND_DECLARE_CLASS_DELAYED:
776-
case ZEND_JMP_FRAMELESS:
777780
opline->extended_value = cache_size;
778781
cache_size += sizeof(void *);
779782
break;
783+
case ZEND_JMP_FRAMELESS:
784+
// op1 func
785+
if (jmp_slot[opline->op1.constant] >= 0) {
786+
opline->extended_value = jmp_slot[opline->op1.constant];
787+
} else {
788+
opline->extended_value = cache_size;
789+
cache_size += sizeof(void *);
790+
jmp_slot[opline->op1.constant] = opline->extended_value;
791+
}
792+
break;
780793
case ZEND_SEND_VAL:
781794
case ZEND_SEND_VAL_EX:
782795
case ZEND_SEND_VAR:

Zend/Optimizer/dce.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ static inline bool may_have_side_effects(
8080
case ZEND_IS_IDENTICAL:
8181
case ZEND_IS_NOT_IDENTICAL:
8282
case ZEND_QM_ASSIGN:
83-
case ZEND_FREE:
8483
case ZEND_FE_FREE:
8584
case ZEND_TYPE_CHECK:
8685
case ZEND_DEFINED:
@@ -127,6 +126,8 @@ static inline bool may_have_side_effects(
127126
case ZEND_ARRAY_KEY_EXISTS:
128127
/* No side effects */
129128
return 0;
129+
case ZEND_FREE:
130+
return opline->extended_value == ZEND_FREE_VOID_CAST;
130131
case ZEND_ADD_ARRAY_ELEMENT:
131132
/* TODO: We can't free two vars. Keep instruction alive. <?php [0, "$a" => "$b"]; */
132133
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {

Zend/Optimizer/dfa_pass.c

Lines changed: 18 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -407,40 +407,28 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa)
407407
zend_call_info *call_info = func_info->callee_info;
408408

409409
do {
410-
if (call_info->caller_call_opline
411-
&& call_info->caller_call_opline->opcode == ZEND_DO_ICALL
410+
zend_op *op = call_info->caller_init_opline;
411+
412+
if ((op->opcode == ZEND_FRAMELESS_ICALL_2
413+
|| (op->opcode == ZEND_FRAMELESS_ICALL_3 && (op + 1)->op1_type == IS_CONST))
412414
&& call_info->callee_func
413-
&& zend_string_equals_literal(call_info->callee_func->common.function_name, "in_array")
414-
&& (call_info->caller_init_opline->extended_value == 2
415-
|| (call_info->caller_init_opline->extended_value == 3
416-
&& (call_info->caller_call_opline - 1)->opcode == ZEND_SEND_VAL
417-
&& (call_info->caller_call_opline - 1)->op1_type == IS_CONST))) {
418-
419-
zend_op *send_array;
420-
zend_op *send_needly;
415+
&& zend_string_equals_literal_ci(call_info->callee_func->common.function_name, "in_array")) {
416+
421417
bool strict = 0;
418+
bool has_opdata = op->opcode == ZEND_FRAMELESS_ICALL_3;
422419
ZEND_ASSERT(!call_info->is_prototype);
423420

424-
if (call_info->caller_init_opline->extended_value == 2) {
425-
send_array = call_info->caller_call_opline - 1;
426-
send_needly = call_info->caller_call_opline - 2;
427-
} else {
428-
if (zend_is_true(CT_CONSTANT_EX(op_array, (call_info->caller_call_opline - 1)->op1.constant))) {
421+
if (has_opdata) {
422+
if (zend_is_true(CT_CONSTANT_EX(op_array, (op + 1)->op1.constant))) {
429423
strict = 1;
430424
}
431-
send_array = call_info->caller_call_opline - 2;
432-
send_needly = call_info->caller_call_opline - 3;
433425
}
434426

435-
if (send_array->opcode == ZEND_SEND_VAL
436-
&& send_array->op1_type == IS_CONST
437-
&& Z_TYPE_P(CT_CONSTANT_EX(op_array, send_array->op1.constant)) == IS_ARRAY
438-
&& (send_needly->opcode == ZEND_SEND_VAL
439-
|| send_needly->opcode == ZEND_SEND_VAR)
440-
) {
427+
if (op->op2_type == IS_CONST
428+
&& Z_TYPE_P(CT_CONSTANT_EX(op_array, op->op2.constant)) == IS_ARRAY) {
441429
bool ok = 1;
442430

443-
HashTable *src = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, send_array->op1.constant));
431+
HashTable *src = Z_ARRVAL_P(CT_CONSTANT_EX(op_array, op->op2.constant));
444432
HashTable *dst;
445433
zval *val, tmp;
446434
zend_ulong idx;
@@ -471,59 +459,15 @@ int zend_dfa_optimize_calls(zend_op_array *op_array, zend_ssa *ssa)
471459
}
472460

473461
if (ok) {
474-
uint32_t op_num = send_needly - op_array->opcodes;
475-
zend_ssa_op *ssa_op = ssa->ops + op_num;
476-
477-
if (ssa_op->op1_use >= 0) {
478-
/* Reconstruct SSA */
479-
int var_num = ssa_op->op1_use;
480-
zend_ssa_var *var = ssa->vars + var_num;
481-
482-
ZEND_ASSERT(ssa_op->op1_def < 0);
483-
zend_ssa_unlink_use_chain(ssa, op_num, ssa_op->op1_use);
484-
ssa_op->op1_use = -1;
485-
ssa_op->op1_use_chain = -1;
486-
op_num = call_info->caller_call_opline - op_array->opcodes;
487-
ssa_op = ssa->ops + op_num;
488-
ssa_op->op1_use = var_num;
489-
ssa_op->op1_use_chain = var->use_chain;
490-
var->use_chain = op_num;
491-
}
492-
493462
ZVAL_ARR(&tmp, dst);
494463

495464
/* Update opcode */
496-
call_info->caller_call_opline->opcode = ZEND_IN_ARRAY;
497-
call_info->caller_call_opline->extended_value = strict;
498-
call_info->caller_call_opline->op1_type = send_needly->op1_type;
499-
call_info->caller_call_opline->op1.num = send_needly->op1.num;
500-
call_info->caller_call_opline->op2_type = IS_CONST;
501-
call_info->caller_call_opline->op2.constant = zend_optimizer_add_literal(op_array, &tmp);
502-
if (call_info->caller_init_opline->extended_value == 3) {
503-
MAKE_NOP(call_info->caller_call_opline - 1);
504-
}
505-
MAKE_NOP(call_info->caller_init_opline);
506-
MAKE_NOP(send_needly);
507-
MAKE_NOP(send_array);
508-
removed_ops++;
509-
510-
op_num = call_info->caller_call_opline - op_array->opcodes;
511-
ssa_op = ssa->ops + op_num;
512-
if (ssa_op->result_def >= 0) {
513-
int var = ssa_op->result_def;
514-
int use = ssa->vars[var].use_chain;
515-
516-
/* If the result is used only in a JMPZ/JMPNZ, replace result type with
517-
* IS_TMP_VAR, which will enable use of smart branches. Don't do this
518-
* in other cases, as not all opcodes support both VAR and TMP. */
519-
if (ssa->vars[var].phi_use_chain == NULL
520-
&& ssa->ops[use].op1_use == var
521-
&& ssa->ops[use].op1_use_chain == -1
522-
&& (op_array->opcodes[use].opcode == ZEND_JMPZ
523-
|| op_array->opcodes[use].opcode == ZEND_JMPNZ)) {
524-
call_info->caller_call_opline->result_type = IS_TMP_VAR;
525-
op_array->opcodes[use].op1_type = IS_TMP_VAR;
526-
}
465+
op->opcode = ZEND_IN_ARRAY;
466+
op->extended_value = strict;
467+
op->op2.constant = zend_optimizer_add_literal(op_array, &tmp);
468+
if (has_opdata) {
469+
MAKE_NOP(op + 1);
470+
removed_ops++;
527471
}
528472
}
529473
}

0 commit comments

Comments
 (0)