Commit 9705fda1bbb for php

commit 9705fda1bbb4e9458fb79bccf63bdcdb731dcd22
Merge: b9ea38ef639 d6373dfe150
Author: Ilija Tovilo <ilija.tovilo@me.com>
Date:   Wed Oct 21 16:34:56 2026 +0200

    Merge branch 'PHP-8.6' into master

    * PHP-8.6:
      Add NEWS entry
      Avoid state corruption via bailout

diff --cc Zend/zend_API.h
index cc6ed3c8e10,ba67948c12b..d1064970dcd
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@@ -514,11 -549,71 +514,71 @@@ static zend_always_inline void array_in
  	array_init_size(arg, 0);
  }

+ static zend_always_inline void array_init_singleton(zval *arg)
+ {
+ 	ZVAL_ARR(arg, zend_new_array_singleton());
+ }
+
+ /* Fallible array_init()/object_init(): on failure return false and leave arg as
+  * IS_NULL, so arg stays safe to destroy. */
+ static zend_always_inline bool _array_finit(zval *arg, size_t size)
+ {
+ 	zend_array *ht = zend_fnew_array(size);
+ 	if (UNEXPECTED(ht == NULL)) {
+ 		ZVAL_NULL(arg);
+ 		return false;
+ 	}
+ 	ZVAL_ARR(arg, ht);
+ 	return true;
+ }
+
+ static zend_always_inline bool _array_finit_ex(zval *arg, size_t size, bool packed)
+ {
+ 	zend_array *ht = zend_fnew_array(size);
+ 	if (UNEXPECTED(ht == NULL)) {
+ 		ZVAL_NULL(arg);
+ 		return false;
+ 	}
+ 	if (UNEXPECTED(zend_hash_real_finit(ht, packed, /* fallible */ true) == FAILURE)) {
+ 		efree(ht);
+ 		ZVAL_NULL(arg);
+ 		return false;
+ 	}
+ 	ZVAL_ARR(arg, ht);
+ 	return true;
+ }
+
+ static zend_always_inline bool array_finit(zval *arg)
+ {
+ 	return _array_finit(arg, 0);
+ }
+
+ static zend_always_inline bool array_finit_size(zval *arg, size_t size)
+ {
+ 	return _array_finit(arg, size);
+ }
+
+ static zend_always_inline bool array_finit_size_ex(zval *arg, size_t size, bool packed)
+ {
+ 	return _array_finit_ex(arg, size, packed);
+ }
+
+ static zend_always_inline bool array_finit_size_packed(zval *arg, size_t size)
+ {
+ 	return _array_finit_ex(arg, size, /* packed */ true);
+ }
+
+ static zend_always_inline bool array_finit_size_mixed(zval *arg, size_t size)
+ {
+ 	return _array_finit_ex(arg, size, /* packed */ false);
+ }
+
  ZEND_API void object_init(zval *arg);
+ ZEND_API bool object_finit(zval *arg);
  ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *ce);
 -ZEND_API zend_result object_init_with_constructor(zval *arg, zend_class_entry *class_type, uint32_t param_count, zval *params, HashTable *named_params);
 +ZEND_API zend_result object_init_with_constructor(zval *arg, zend_class_entry *ce, uint32_t param_count, zval *params, HashTable *named_params);
  ZEND_API zend_result object_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties);
 -ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type);
 +ZEND_API void object_properties_init(zend_object *object, zend_class_entry *ce);
  ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properties);
  ZEND_API void object_properties_load(zend_object *object, const HashTable *properties);

diff --cc Zend/zend_alloc.c
index e3317b3a9a3,050fb252e78..b293ee1a51d
--- a/Zend/zend_alloc.c
+++ b/Zend/zend_alloc.c
@@@ -393,31 -405,160 +405,160 @@@ ZEND_NORETURN static ZEND_COLD void zen
  	abort();
  }

- ZEND_NORETURN static ZEND_COLD void zend_mm_safe_error(zend_mm_heap *heap,
- 	const char *format,
- 	size_t limit,
- #if ZEND_DEBUG
- 	const char *filename,
- 	uint32_t lineno,
- #endif
- 	size_t size)
 -static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void);
++ZEND_NORETURN static ZEND_COLD void zend_out_of_memory(void);
+
+ static ZEND_COLD void zend_mm_delayed_verror(const char *format, va_list args)
  {
+ 	if (ZEND_HAS_OOM()) {
+ 		return;
+ 	}

- 	heap->overflow = 1;
- 	zend_try {
- 		zend_error_noreturn(E_ERROR,
- 			format,
- 			limit,
- #if ZEND_DEBUG
- 			filename,
- 			lineno,
- #endif
- 			size);
- 	} zend_catch {
- 	}  zend_end_try();
- 	heap->overflow = 0;
- 	zend_bailout();
- 	exit(1);
+ 	zend_string *script_filename = NULL;
+ 	uint32_t script_lineno = 0;
+
+ 	if (zend_is_executing()) {
+ 		script_filename = zend_get_executed_filename_ex();
+ 		script_lineno = zend_get_executed_lineno();
+ 	} else if (zend_is_compiling()) {
+ 		script_filename = zend_get_compiled_filename();
+ 		script_lineno = zend_get_compiled_lineno();
+ 	}
+
+ 	if (script_filename == NULL) {
+ 		script_filename = ZSTR_KNOWN(ZEND_STR_UNKNOWN_CAPITALIZED);
+ 		script_lineno = 0;
+ 	}
+
+ 	char buf[1024];
+ 	vsnprintf(buf, sizeof(buf), format, args);
+
+ 	EG(delayed_oom).message = zend_string_init(buf, strlen(buf), /* persistent */ true);
+ 	GC_MAKE_PERSISTENT_LOCAL(EG(delayed_oom).message);
+ 	zend_string_addref(script_filename);
+ 	EG(delayed_oom).filename = script_filename;
+ 	EG(delayed_oom).lineno = script_lineno;
+ 	EG(delayed_oom).state = ZEND_OOM_STATE_PENDING;
+
 -	zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
++	atomic_store(&EG(vm_interrupt), true);
+ }
+
+ ZEND_ATTRIBUTE_FORMAT(printf, 1, 2)
+ static ZEND_COLD void zend_mm_delayed_error(const char *format, ...)
+ {
+ 	va_list args;
+ 	va_start(args, format);
+ 	zend_mm_delayed_verror(format, args);
+ 	va_end(args);
+ }
+
+ ZEND_ATTRIBUTE_FORMAT(printf, 2, 3)
+ ZEND_API ZEND_COLD void zend_mm_delayed_error_or_panic(bool delay, const char *format, ...)
+ {
+ 	va_list args;
+ 	va_start(args, format);
+
+ 	if (delay) {
+ 		zend_mm_delayed_verror(format, args);
+ 	} else {
+ 		char buf[1024];
+ 		vsnprintf(buf, sizeof(buf), format, args);
+ 		zend_mm_panic(buf);
+ 	}
+
+ 	va_end(args);
+ }
+
+ ZEND_COLD void zend_mm_oom_info_dtor(zend_oom_info *info)
+ {
+ 	if (info->message) {
+ 		zend_string_release(info->message);
+ 		info->message = NULL;
+ 	}
+ 	if (info->filename) {
+ 		zend_string_release(info->filename);
+ 		info->filename = NULL;
+ 	}
+ }
+
+ #ifdef ZEND_MM_LIMIT
 -static ZEND_COLD ZEND_NORETURN void zend_mm_hard_limit_error(zend_mm_heap *heap,
++ZEND_NORETURN static ZEND_COLD void zend_mm_hard_limit_error(zend_mm_heap *heap,
+ 		size_t add_size ZEND_FILE_LINE_DC)
+ {
+ 	zend_string *script_filename = NULL;
+ 	uint32_t script_lineno = 0;
+
+ 	if (zend_is_executing()) {
+ 		script_filename = zend_get_executed_filename_ex();
+ 		script_lineno = zend_get_executed_lineno();
+ 	} else if (zend_is_compiling()) {
+ 		script_filename = zend_get_compiled_filename();
+ 		script_lineno = zend_get_compiled_lineno();
+ 	}
+
+ 	if (script_filename == NULL) {
+ 		script_filename = ZSTR_KNOWN(ZEND_STR_UNKNOWN_CAPITALIZED);
+ 		script_lineno = 0;
+ 	}
+
+ 	fprintf(stderr,
+ # if ZEND_DEBUG
+ 			"Hard memory limit of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes) in %s on line %d\n",
+ # else
+ 			"Hard memory limit of %zu bytes exhausted (tried to allocate %zu bytes) in %s on line %d\n",
+ # endif
+ 			heap->hard_limit
+ 			ZEND_FILE_LINE_RELAY_CC,
+ 			add_size,
+ 			ZSTR_VAL(script_filename),
+ 			script_lineno);
+
+ 	/* See http://support.microsoft.com/kb/190351 */
+ # ifdef ZEND_WIN32
+ 	fflush(stderr);
+ # endif
+
+ 	_exit(137);
+ }
+ #endif /* ZEND_MM_LIMIT */
+
+ /* Returns FAILURE if allocation should fail (in case the heap is fallible).
+  * When the soft limit is to be exceeded, a delayed OOM error is queued.
+  * When the hard limit is to be exceeded, the function does not return.
+  */
+ static zend_always_inline zend_result zend_mm_check_limit(zend_mm_heap *heap, size_t add_size, bool gc, bool *did_gc ZEND_FILE_LINE_DC)
+ {
+ #if ZEND_MM_LIMIT
+ 	/* Is the soft limit exceeded or going to be exceeded? */
+ 	if (UNEXPECTED(heap->limit < heap->real_size || add_size > heap->limit - heap->real_size)) {
+ 		if (gc && zend_mm_gc(heap)) {
+ 			if (did_gc) {
+ 				*did_gc = true;
+ 			}
+ 		}
+ 		ZEND_ASSERT(heap->hard_limit >= heap->limit && heap->hard_limit >= heap->real_size);
+ 		if (!heap->fallible && add_size > heap->hard_limit - heap->real_size) {
+ 			zend_mm_hard_limit_error(heap, add_size ZEND_FILE_LINE_RELAY_CC);
+ 		}
+ 		/* Check soft limit again as gc may have reduced memory usage */
+ 		if (!gc || (heap->limit < heap->real_size || add_size > heap->limit - heap->real_size)) {
+ 			if (!ZEND_HAS_OOM()) {
+ 				zend_mm_delayed_error(
+ # if ZEND_DEBUG
+ 						"Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)",
+ # else
+ 						"Allowed memory size of %zu bytes exhausted (tried to allocate %zu bytes)",
+ # endif
+ 						heap->limit
+ 						ZEND_FILE_LINE_RELAY_CC,
+ 						add_size);
+ 			}
+
+ 			return heap->fallible ? FAILURE : SUCCESS;
+ 		}
+ 	}
+ #endif /* ZEND_MM_LIMIT */
+
+ 	return SUCCESS;
  }

  #ifdef _WIN32
diff --cc Zend/zend_execute.c
index e7923d76996,4e82fa20759..a5700627043
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@@ -4344,9 -4344,11 +4344,11 @@@ ZEND_API void ZEND_FASTCALL zend_free_c

  ZEND_API ZEND_COLD void ZEND_FASTCALL zend_fcall_interrupt(zend_execute_data *call)
  {
 -	zend_atomic_bool_store_ex(&EG(vm_interrupt), false);
 -	if (zend_atomic_bool_load_ex(&EG(timed_out))) {
 +	atomic_store(&EG(vm_interrupt), false);
 +	if (atomic_load(&EG(timed_out))) {
  		zend_timeout();
+ 	} else if (ZEND_HAS_OOM()) {
+ 		zend_handle_delayed_oom();
  	} else if (zend_interrupt_function) {
  		zend_interrupt_function(call);
  	}
diff --cc Zend/zend_execute_API.c
index 09cf6c18cd1,75126daa55f..cfb78f1b14f
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@@ -1099,21 -1122,24 +1119,24 @@@ cleanup_args
  			zval_ptr_dtor(fci->retval);
  			ZVAL_UNDEF(fci->retval);
  		}
+ 	}

- 		/* This flag is regularly checked while running user functions, but not internal
- 		 * So see whether interrupt flag was set while the function was running... */
- 		if (atomic_exchange(&EG(vm_interrupt), false)) {
- 			if (atomic_load(&EG(timed_out))) {
- 				zend_timeout();
- 			} else if (zend_interrupt_function) {
- 				zend_interrupt_function(EG(current_execute_data));
- 			}
 -	if (UNEXPECTED(zend_atomic_bool_exchange_ex(&EG(vm_interrupt), false))) {
 -		if (zend_atomic_bool_load_ex(&EG(timed_out))) {
++	if (UNEXPECTED(atomic_exchange(&EG(vm_interrupt), false))) {
++		if (atomic_load(&EG(timed_out))) {
+ 			zend_timeout();
+ 		} else if (ZEND_HAS_OOM()) {
+ 			zend_handle_delayed_oom();
+ 			zval_ptr_dtor(fci->retval);
+ 			ZVAL_UNDEF(fci->retval);
+ 		} else if (zend_interrupt_function) {
+ 			zend_interrupt_function(EG(current_execute_data));
  		}
+ 	}

- 		if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
- 			OBJ_RELEASE(Z_OBJ(call->This));
- 		}
+ 	if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
+ 		OBJ_RELEASE(Z_OBJ(call->This));
  	}
+
  	EG(fake_scope) = orig_fake_scope;

  	if (pinned_this) {
diff --cc Zend/zend_globals.h
index c3d1ce3c67a,c3034f8c8ed..419f9cc07c7
--- a/Zend/zend_globals.h
+++ b/Zend/zend_globals.h
@@@ -26,6 -26,8 +26,7 @@@

  #include "zend_globals_macros.h"

+ #include "zend_alloc.h"
 -#include "zend_atomic.h"
  #include "zend_stack.h"
  #include "zend_ptr_stack.h"
  #include "zend_hash.h"
diff --cc Zend/zend_hash.h
index 3bd71bab8dc,e7c86808182..cb8a2256aa6
--- a/Zend/zend_hash.h
+++ b/Zend/zend_hash.h
@@@ -100,6 -93,17 +101,8 @@@ extern ZEND_API const HashTable zend_em
  		Z_TYPE_INFO_P(__z) = IS_ARRAY; \
  	} while (0)

+ #define HASH_NOMEM ((zval*)-1)
+
 -typedef struct _zend_hash_key {
 -	zend_ulong h;
 -	zend_string *key;
 -} zend_hash_key;
 -
 -typedef bool (*merge_checker_func_t)(HashTable *target_ht, zval *source_data, zend_hash_key *hash_key, void *pParam);
 -
 -BEGIN_EXTERN_C()
 -
  /* startup/shutdown */
  ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, bool persistent);
  ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht);
diff --cc Zend/zend_vm_def.h
index cf8d626bbdb,3ea6d7250ab..871edf3aed7
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@@ -10724,8 -10729,11 +10731,11 @@@ ZEND_VM_HELPER(zend_interrupt_helper, A
  #else
  	SAVE_OPLINE();
  #endif
 -	if (zend_atomic_bool_load_ex(&EG(timed_out))) {
 +	if (atomic_load(&EG(timed_out))) {
  		zend_timeout();
+ 	} else if (ZEND_HAS_OOM()) {
+ 		zend_handle_delayed_oom();
+ 		HANDLE_EXCEPTION();
  	} else if (zend_interrupt_function) {
  		zend_interrupt_function(execute_data);
  		if (EG(exception)) {
diff --cc Zend/zend_vm_execute.h
index 88dab2fd86c,8b6a5533fa3..bdd7bea9bc7
Binary files differ
diff --cc ext/mbstring/libmbfl/mbfl/mbfl_encoding.h
index 620d8e07198,e71737318bf..6abc042ff09
--- a/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h
+++ b/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h
@@@ -162,17 -162,34 +162,31 @@@ static inline void mb_convert_buf_init(
  	buf->error_mode = err_mode;
  }

+ static inline zend_result mb_convert_buf_ensure(mb_convert_buf *buf, unsigned char **out, unsigned char **limit, size_t needed)
+ {
+ 	ZEND_ASSERT(*out <= *limit);
+ 	if ((size_t)(*limit - *out) < needed) {
+ 		size_t oldsize = *limit - (unsigned char*)ZSTR_VAL((buf)->str);
+ 		size_t newsize = oldsize + MAX(oldsize >> 1, needed);
+ 		zend_string *newstr = safe_ferealloc((buf)->str, 1, newsize, _ZSTR_STRUCT_SIZE(0), /* fallible */ true);
+ 		if (!newstr) {
 -			/* An earlier growth may have moved the buffer. */
 -			buf->out = *out;
 -			buf->limit = *limit;
+ 			return FAILURE;
+ 		}
+ 		*out = (unsigned char*)ZSTR_VAL(newstr) + (*out - (unsigned char*)ZSTR_VAL((buf)->str));
+ 		*limit = (unsigned char*)ZSTR_VAL(newstr) + newsize;
+ 		(buf)->str = newstr;
+ 	}
+ 	return SUCCESS;
+ }
+
  #define MB_CONVERT_BUF_ENSURE(buf, out, limit, needed) \
- 	ZEND_ASSERT(out <= limit); \
- 	if ((size_t)(limit - out) < (needed)) { \
- 		size_t oldsize = limit - (unsigned char*)ZSTR_VAL((buf)->str); \
- 		size_t newsize = oldsize + MAX(oldsize >> 1, needed); \
- 		zend_string *newstr = erealloc((buf)->str, _ZSTR_STRUCT_SIZE(newsize)); \
- 		out = (unsigned char*)ZSTR_VAL(newstr) + (out - (unsigned char*)ZSTR_VAL((buf)->str)); \
- 		limit = (unsigned char*)ZSTR_VAL(newstr) + newsize; \
- 		(buf)->str = newstr; \
+ 	if (!MB_CONVERT_BUF_ENSURE_EX(buf, out, limit, needed)) { \
+ 		return; \
  	}

+ #define MB_CONVERT_BUF_ENSURE_EX(buf, out, limit, needed) \
+ 	EXPECTED(mb_convert_buf_ensure(buf, &(out), &(limit), (needed)) == SUCCESS)
+
  #define MB_CONVERT_BUF_STORE(buf, _out, _limit) (buf)->out = _out; (buf)->limit = _limit

  #define MB_CONVERT_BUF_LOAD(buf, _out, _limit) _out = (buf)->out; _limit = (buf)->limit
diff --cc ext/opcache/ZendAccelerator.c
index 2317bc4a12e,8f88ce4bea2..2318f5b28c8
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@@ -2721,9 -2725,11 +2725,11 @@@ static zend_class_entry* zend_accel_inh
  	entry->next = proto->inheritance_cache;

  	ZCSG(map_ptr_last) = CG(map_ptr_last);
 -	ZEND_ATOMIC_FENCE_RELEASE();
 +	atomic_thread_fence(memory_order_release);
  	proto->inheritance_cache = entry;

+ 	zend_accel_pending_ce_cache_commit();
+
  	zend_shared_alloc_destroy_xlat_table();

  	zend_shared_alloc_unlock();
diff --cc ext/pcre/php_pcre.c
index 256b67e9e4c,fd239eb887f..4f49b6fbf69
--- a/ext/pcre/php_pcre.c
+++ b/ext/pcre/php_pcre.c
@@@ -1310,9 -1340,12 +1339,12 @@@ matched
  								add_offset_pair(
  									match_sets[i], subject, offsets[2*i], offsets[2*i+1],
  									NULL, unmatched_as_null);
+ 								if (ZEND_HAS_OOM()) {
+ 									goto oom;
+ 								}
  							}
  						} else {
 -							for (i = 0; i < count; i++) {
 +							for (int i = 0; i < count; i++) {
  								zval val;
  								populate_match_value(
  									&val, subject, offsets[2*i], offsets[2*i+1], unmatched_as_null);
@@@ -1472,6 -1518,25 +1517,25 @@@ error
  	} else {
  		RETVAL_FALSE;
  	}
+ 	return;
+
+ oom:
+ 	if (match_data != mdata) {
+ 		pcre2_match_data_free(match_data);
+ 	}
+ 	if (match_sets) {
 -		for (i = 0; i < num_subpats; i++) {
++		for (uint32_t i = 0; i < num_subpats; i++) {
+ 			zend_array_destroy(match_sets[i]);
+ 		}
+ 		efree(match_sets);
+ 	}
+ 	if (marks) {
+ 		zend_array_destroy(marks);
+ 	}
+ 	if (subpats) {
+ 		zend_hash_clean(Z_ARRVAL_P(subpats));
+ 	}
+ 	RETURN_OOM();
  }
  /* }}} */

@@@ -1560,9 -1625,17 +1624,13 @@@ static zend_string *preg_do_repl_func(z
  	zval	     arg;				/* Argument to pass to function */

  	array_init_size(&arg, count + (mark ? 1 : 0));
- 	populate_subpat_array(Z_ARRVAL(arg), ZSTR_VAL(subject), offsets, subpat_names, num_subpats, count, mark, flags);
 -	zend_result result = populate_subpat_array(Z_ARRVAL(arg), subject, offsets, subpat_names, num_subpats, count, mark, flags);
++	zend_result result = populate_subpat_array(Z_ARRVAL(arg), ZSTR_VAL(subject), offsets, subpat_names, num_subpats, count, mark, flags);
+ 	if (UNEXPECTED(result == FAILURE)) {
+ 		zval_ptr_dtor(&arg);
+ 		return NULL;
+ 	}

 -	fci->retval = &retval;
 -	fci->param_count = 1;
 -	fci->params = &arg;
 -	fci->consumed_args = zend_fci_consumed_arg(0);
 -	zend_call_function(fci, fcc);
 +	zend_call_known_fcc_ex(fcc, &retval, 1, &arg, NULL, zend_fci_consumed_arg(0));
  	zval_ptr_dtor(&arg);
  	if (EXPECTED(Z_TYPE(retval) == IS_STRING)) {
  		return Z_STR(retval);
@@@ -1948,10 -2030,10 +2025,10 @@@ matched

  			/* Use custom function to get replacement string and its length. */
  			zend_string *eval_result = preg_do_repl_func(
 -				fci, fcc, ZSTR_VAL(subject_str), offsets, subpat_names, num_subpats, count,
 +				fcc, subject_str, offsets, subpat_names, num_subpats, count,
  				pcre2_get_mark(match_data), flags);

- 			if (UNEXPECTED(eval_result == NULL)) {
+ 			if (UNEXPECTED(!eval_result)) {
  				goto error;
  			}
  			new_len = zend_safe_address_guarded(1, ZSTR_LEN(eval_result) + ZSTR_MAX_OVERHEAD, new_len) -ZSTR_MAX_OVERHEAD;
diff --cc ext/session/tests/rfc1867_sid_invalid.phpt
index 687fbcd96b5,53c2c0e5e6e..5f410883aba
--- a/ext/session/tests/rfc1867_sid_invalid.phpt
+++ b/ext/session/tests/rfc1867_sid_invalid.phpt
@@@ -43,9 -43,13 +43,9 @@@ session_start()
  var_dump(session_id());
  var_dump(basename(__FILE__) == $_POST[ini_get("session.upload_progress.name")]);
  var_dump($_FILES);
- var_dump($_SESSION["upload_progress_" . basename(__FILE__)]);
+ var_dump($_SESSION);
  session_destroy();
  ?>
 ---CLEAN--
 -<?php
 -@unlink(__DIR__ . DIRECTORY_SEPARATOR . "rfc1867_sid_invalid.post.txt");
 -?>
  --EXPECTF--
  Warning: PHP Request Startup: Session ID is too long or contains illegal characters. Only the A-Z, a-z, 0-9, "-", and "," characters are allowed in Unknown on line 0

diff --cc ext/standard/array.c
index 0b184efc399,39422639418..39e23bf8738
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@@ -7124,127 -7156,120 +7155,132 @@@ PHP_FUNCTION(array_map
  			}
  		}

 +		if (!maxlen) {
 +			RETURN_EMPTY_ARRAY();
 +		}
 +
- 		array_init_size(return_value, maxlen);
- 		zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
+ 		if (UNEXPECTED(!array_finit_size_packed(return_value, maxlen))) {
+ 			RETURN_OOM();
+ 		}

 -		if (!ZEND_FCI_INITIALIZED(fci)) {
 -			uint32_t *array_pos = ecalloc(n_arrays, sizeof(HashPosition));
 -			zval zv;
 -
 -			/* We iterate through all the arrays at once. */
 -			for (k = 0; k < maxlen; k++) {
 -
 -				/* If no callback, the result will be an array, consisting of current
 -				 * entries from all arrays. */
 -				if (ZEND_HAS_OOM()) {
 -					efree(array_pos);
 -					RETURN_OOM();
 -				}
 -				array_init_size(&result, n_arrays);
 -
 -				for (i = 0; i < n_arrays; i++) {
 -					/* If this array still has elements, add the current one to the
 -					 * parameter list, otherwise use null value. */
 -					uint32_t pos = array_pos[i];
 -					if (HT_IS_PACKED(Z_ARRVAL(arrays[i]))) {
 -						while (1) {
 -							if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
 -								ZVAL_NULL(&zv);
 -								break;
 -							} else if (Z_TYPE(Z_ARRVAL(arrays[i])->arPacked[pos]) != IS_UNDEF) {
 -								ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arPacked[pos]);
 -								array_pos[i] = pos + 1;
 -								break;
 -							}
 -							pos++;
 -						}
 -					} else {
 -						while (1) {
 -							if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
 -								ZVAL_NULL(&zv);
 -								break;
 -							} else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
 -								ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arData[pos].val);
 -								array_pos[i] = pos + 1;
 -								break;
 +		ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
 +			if (!ZEND_FCI_INITIALIZED(fci)) {
 +				uint32_t *array_pos = ecalloc(n_arrays, sizeof(HashPosition));
 +				zval zv;
 +
 +				/* We iterate through all the arrays at once. */
 +				for (k = 0; k < maxlen; k++) {
 +
 +					/* If no callback, the result will be an array, consisting of current
 +					 * entries from all arrays. */
++					if (ZEND_HAS_OOM()) {
++						efree(array_pos);
++						RETURN_OOM();
++					}
 +					array_init_size(&result, n_arrays);
 +
 +					zend_hash_real_init_packed(Z_ARRVAL(result));
 +					ZEND_HASH_FILL_PACKED(Z_ARRVAL(result)) {
 +						for (i = 0; i < n_arrays; i++) {
 +							/* If this array still has elements, add the current one to the
 +							 * parameter list, otherwise use null value. */
 +							uint32_t pos = array_pos[i];
 +							if (HT_IS_PACKED(Z_ARRVAL(arrays[i]))) {
 +								while (1) {
 +									if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
 +										ZEND_HASH_FILL_SET_NULL();
 +										break;
 +									} else if (Z_TYPE(Z_ARRVAL(arrays[i])->arPacked[pos]) != IS_UNDEF) {
 +										ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arPacked[pos]);
 +										ZEND_HASH_FILL_SET(&zv);
 +										array_pos[i] = pos + 1;
 +										break;
 +									}
 +									pos++;
 +								}
 +							} else {
 +								while (1) {
 +									if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
 +										ZEND_HASH_FILL_SET_NULL();
 +										break;
 +									} else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
 +										ZVAL_COPY(&zv, &Z_ARRVAL(arrays[i])->arData[pos].val);
 +										ZEND_HASH_FILL_SET(&zv);
 +										array_pos[i] = pos + 1;
 +										break;
 +									}
 +									pos++;
 +								}
  							}
 -							pos++;
 +							ZEND_HASH_FILL_NEXT();
  						}
 -					}
 -					zend_hash_next_index_insert_new(Z_ARRVAL(result), &zv);
 -				}
 -
 -				zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &result);
 -			}
 +					} ZEND_HASH_FILL_END();

 -			efree(array_pos);
 -		} else {
 -			zval *params = (zval *)safe_emalloc(n_arrays, sizeof(zval), 0);
 -
 -			/* Remember next starting point in the array, initialize those as zeros. */
 -			for (i = 0; i < n_arrays; i++) {
 -				Z_EXTRA(params[i]) = 0;
 -			}
 +					ZEND_HASH_FILL_ADD(&result);
 +				}

 -			fci.retval = &result;
 -			fci.param_count = n_arrays;
 -			fci.params = params;
 +				efree(array_pos);
 +			} else {
 +				zval *params = (zval *)safe_emalloc(n_arrays, sizeof(zval), 0);

 -			/* We iterate through all the arrays at once. */
 -			for (k = 0; k < maxlen; k++) {
 +				/* Remember next starting point in the array, initialize those as zeros. */
  				for (i = 0; i < n_arrays; i++) {
 -					/* If this array still has elements, add the current one to the
 -					 * parameter list, otherwise use null value. */
 -					uint32_t pos = Z_EXTRA(params[i]);
 -					if (HT_IS_PACKED(Z_ARRVAL(arrays[i]))) {
 -						while (1) {
 -							if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
 -								ZVAL_NULL(&params[i]);
 -								break;
 -							} else if (Z_TYPE(Z_ARRVAL(arrays[i])->arPacked[pos]) != IS_UNDEF) {
 -								ZVAL_COPY_VALUE(&params[i], &Z_ARRVAL(arrays[i])->arPacked[pos]);
 -								Z_EXTRA(params[i]) = pos + 1;
 -								break;
 +					Z_EXTRA(params[i]) = 0;
 +				}
 +
 +				fci.retval = &result;
 +				fci.param_count = n_arrays;
 +				fci.params = params;
 +
 +				/* We iterate through all the arrays at once. */
 +				for (k = 0; k < maxlen; k++) {
 +					for (i = 0; i < n_arrays; i++) {
 +						/* If this array still has elements, add the current one to the
 +						 * parameter list, otherwise use null value. */
 +						uint32_t pos = Z_EXTRA(params[i]);
 +						if (HT_IS_PACKED(Z_ARRVAL(arrays[i]))) {
 +							while (1) {
 +								if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
 +									ZVAL_NULL(&params[i]);
 +									break;
 +								} else if (Z_TYPE(Z_ARRVAL(arrays[i])->arPacked[pos]) != IS_UNDEF) {
 +									ZVAL_COPY_VALUE(&params[i], &Z_ARRVAL(arrays[i])->arPacked[pos]);
 +									Z_EXTRA(params[i]) = pos + 1;
 +									break;
 +								}
 +								pos++;
  							}
 -							pos++;
 -						}
 -					} else {
 -						while (1) {
 -							if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
 -								ZVAL_NULL(&params[i]);
 -								break;
 -							} else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
 -								ZVAL_COPY_VALUE(&params[i], &Z_ARRVAL(arrays[i])->arData[pos].val);
 -								Z_EXTRA(params[i]) = pos + 1;
 -								break;
 +						} else {
 +							while (1) {
 +								if (pos >= Z_ARRVAL(arrays[i])->nNumUsed) {
 +									ZVAL_NULL(&params[i]);
 +									break;
 +								} else if (Z_TYPE(Z_ARRVAL(arrays[i])->arData[pos].val) != IS_UNDEF) {
 +									ZVAL_COPY_VALUE(&params[i], &Z_ARRVAL(arrays[i])->arData[pos].val);
 +									Z_EXTRA(params[i]) = pos + 1;
 +									break;
 +								}
 +								pos++;
  							}
 -							pos++;
  						}
  					}
 -				}

 -				zend_result ret = zend_call_function(&fci, &fci_cache);
 -				ZEND_ASSERT(ret == SUCCESS);
 -				ZEND_IGNORE_VALUE(ret);
 +					zend_result ret = zend_call_function(&fci, &fci_cache);
 +					ZEND_ASSERT(ret == SUCCESS);
 +					ZEND_IGNORE_VALUE(ret);

 -				if (Z_TYPE(result) == IS_UNDEF) {
 -					efree(params);
 -					RETURN_THROWS();
 +					if (Z_TYPE(result) == IS_UNDEF) {
 +						ZEND_HASH_FILL_FINISH();
 +						efree(params);
 +						RETURN_THROWS();
 +					}
 +
 +					ZEND_HASH_FILL_ADD(&result);
  				}

 -				zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &result);
 +				efree(params);
  			}
 -
 -			efree(params);
 -		}
 +		} ZEND_HASH_FILL_END();
  	}
  }
  /* }}} */
@@@ -7325,45 -7350,10 +7361,46 @@@ PHP_FUNCTION(array_chunk
  		size = num_in;
  	}

- 	array_init_size(return_value, (uint32_t)(((num_in - 1) / size) + 1));
- 	zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
+ 	if (UNEXPECTED(!array_finit_size_packed(return_value, (uint32_t)(((num_in - 1) / size) + 1)))) {
+ 		RETURN_OOM();
+ 	}

 +	if (!preserve_keys) {
 +		/* Every chunk is a list of exactly `size` elements (the last one possibly
 +		 * shorter), so each one can be filled directly. The input is walked by
 +		 * element pointer, so the packed/hash stride is computed only once. */
 +		HashTable *ht = Z_ARRVAL_P(input);
 +		uint32_t elem_size = ZEND_HASH_ELEMENT_SIZE(ht);
 +		zval *zv = ht->arPacked;
 +		uint32_t remaining = (uint32_t)num_in;
 +
 +		while (remaining > 0) {
 +			uint32_t chunk_size = MIN((uint32_t)size, remaining);
 +
 +			array_init_size(&chunk, chunk_size);
 +			zend_hash_real_init_packed(Z_ARRVAL(chunk));
 +			ZEND_HASH_FILL_PACKED(Z_ARRVAL(chunk)) {
 +				uint32_t n = 0;
 +				while (n < chunk_size) {
 +					entry = zv;
 +					zv = ZEND_HASH_NEXT_ELEMENT(zv, elem_size);
 +					if (UNEXPECTED(Z_TYPE_P(entry) == IS_UNDEF)) {
 +						continue;
 +					}
 +					if (UNEXPECTED(Z_ISREF_P(entry)) && Z_REFCOUNT_P(entry) == 1) {
 +						entry = Z_REFVAL_P(entry);
 +					}
 +					Z_TRY_ADDREF_P(entry);
 +					ZEND_HASH_FILL_ADD(entry);
 +					n++;
 +				}
 +			} ZEND_HASH_FILL_END();
 +			zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &chunk);
 +			remaining -= chunk_size;
 +		}
 +		return;
 +	}
 +
  	ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, str_key, entry) {
  		/* If new chunk, create and initialize it. */
  		if (current == 0) {
diff --cc ext/standard/html.c
index 075d629f10b,d47326f4a64..4631b980a0b
--- a/ext/standard/html.c
+++ b/ext/standard/html.c
@@@ -1329,9 -1175,12 +1329,12 @@@ static zend_string *escape_html_entitie
  		maxlen = zend_safe_addmult(oldlen, 2, 0, "html_entities");
  	}

- 	replaced = zend_string_alloc(maxlen, 0);
+ 	replaced = zend_string_falloc(maxlen, /* persistent */ false, /* fallible */ true);
+ 	if (!replaced) {
+ 		return ZSTR_EMPTY_ALLOC();
+ 	}
 -	len = 0;
 -	cursor = 0;
 +	memcpy(ZSTR_VAL(replaced), old, cursor);
 +	len = cursor;
  	while (cursor < oldlen) {
  		const unsigned char *mbsequence = NULL;
  		size_t mbseqlen					= 0,
diff --cc ext/standard/levenshtein.c
index 9ac7689d3bf,399554fab98..0b0dd08fc75
--- a/ext/standard/levenshtein.c
+++ b/ext/standard/levenshtein.c
@@@ -80,15 -91,15 +91,19 @@@ PHP_FUNCTION(levenshtein
  	zend_long cost_rep = 1;
  	zend_long cost_del = 1;

 -	if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|lll", &string1, &string2, &cost_ins, &cost_rep, &cost_del) == FAILURE) {
 -		RETURN_THROWS();
 -	}
 -
 +	ZEND_PARSE_PARAMETERS_START(2, 5)
 +		Z_PARAM_STR(string1)
 +		Z_PARAM_STR(string2)
 +		Z_PARAM_OPTIONAL
 +		Z_PARAM_LONG(cost_ins)
 +		Z_PARAM_LONG(cost_rep)
 +		Z_PARAM_LONG(cost_del)
 +	ZEND_PARSE_PARAMETERS_END();

- 	RETURN_LONG(reference_levdist(string1, string2, cost_ins, cost_rep, cost_del));
+ 	zend_long distance;
+ 	if (UNEXPECTED(!reference_levdist(string1, string2, cost_ins, cost_rep, cost_del, &distance))) {
+ 		RETURN_OOM();
+ 	}
+ 	RETURN_LONG(distance);
  }
  /* }}} */
diff --cc ext/standard/string.c
index 3775074b590,0a05a1ae36f..59f93854368
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@@ -884,11 -882,16 +899,16 @@@ PHPAPI void php_explode(const zend_stri

  	if (p2 == NULL) {
  		ZVAL_STR_COPY(&tmp, str);
 -		zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
 +		zend_hash_next_index_insert_new(parts, &tmp);
  	} else {
 -		zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
 -		ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
 +		zend_hash_real_init_packed(parts);
 +		ZEND_HASH_FILL_PACKED(parts) {
  			do {
+ 				/* Each piece costs a zval plus a zend_string, so stop once over the limit. */
+ 				if (ZEND_HAS_OOM()) {
+ 					ZEND_HASH_FILL_FINISH();
+ 					return;
+ 				}
  				ZEND_HASH_FILL_GROW();
  				ZEND_HASH_FILL_SET_STR(zend_string_init_fast(p1, p2 - p1));
  				ZEND_HASH_FILL_NEXT();
@@@ -938,8 -946,11 +963,11 @@@ static void php_explode_negative_limit(
  		to_return = limit + found;
  		/* limit is at least -1 therefore no need of bounds checking : i will be always less than found */
  		for (i = 0; i < to_return; i++) { /* this checks also for to_return > 0 */
+ 			if (ZEND_HAS_OOM()) {
+ 				break;
+ 			}
  			ZVAL_STRINGL_FAST(&tmp, positions[i], (positions[i+1] - ZSTR_LEN(delim)) - positions[i]);
 -			zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
 +			zend_hash_next_index_insert_new(parts, &tmp);
  		}
  		efree((void *)positions);
  	}
diff --cc ext/zend_test/observer.c
index 77ce0cc2525,799320357e3..a03c89fc260
--- a/ext/zend_test/observer.c
+++ b/ext/zend_test/observer.c
@@@ -75,8 -75,9 +75,9 @@@ static void observer_begin(zend_execute
  {
  	assert_observer_opline(execute_data);

- 	if (ZT_G(observer_set_vm_interrupt_on_begin)) {
+ 	if (ZT_G(observer_set_vm_interrupt_on_begin)
+ 	 || ZT_G(observer_set_vm_interrupt_on_begin_without_callback)) {
 -		zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
 +		atomic_store(&EG(vm_interrupt), true);
  	}

  	if (!ZT_G(observer_show_output)) {