Commit d6373dfe150 for php

commit d6373dfe150a2abc999b81a5e89d5c4cb0b3b1b4
Merge: c20480380a9 c7273b9ba89
Author: Ilija Tovilo <ilija.tovilo@me.com>
Date:   Wed Oct 21 16:33:23 2026 +0200

    Merge branch 'PHP-8.5' into PHP-8.6

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

diff --cc NEWS
index cd863b0443b,36221c702ae..8a2c0b41ec5
--- a/NEWS
+++ b/NEWS
@@@ -1,8 -1,8 +1,11 @@@
  PHP                                                                        NEWS
  |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 -?? ??? ????, PHP 8.5.13
 +?? ??? ????, PHP 8.6.0RC4

  - Core:
++  . Fixed GHSA-w8hw-w9fx-j79w, GHSA-6wmf-4rv5-p3rp (Avoid state corruption via
++    bailout). (CVE-2026-109618, CVE-2026-109619) (Arnaud, ilutov, Jakub Zelenka,
++    ndossche, Nicolas Grekas)
    . Fixed bug GH-24184 (System ID not being reinitialized after an Apache
      graceful restart, potentially causing incompatible OPcache file cache
      entries to be reused). (Levi Morrison)
diff --cc Zend/tests/fibers/get-return-after-bailout.phpt
index 79ab70c98ba,17a1ae6b579..01bf1364ec5
--- a/Zend/tests/fibers/get-return-after-bailout.phpt
+++ b/Zend/tests/fibers/get-return-after-bailout.phpt
@@@ -22,7 -15,7 +15,7 @@@ $fiber->start()

  ?>
  --EXPECTF--
- Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) %sget-return-after-bailout.php on line %d
 -Fatal error: __debuginfo() must return an array in %s on line %d
++Fatal error: __debugInfo() must return an array in %s on line %d

  Fatal error: Uncaught FiberError: Cannot get fiber return value: The fiber exited with a fatal error in %sget-return-after-bailout.php:%d
  Stack trace:
diff --cc Zend/zend.c
index 5befee97eff,b86601cd16e..2cbdd0267c2
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@@ -1511,11 -1511,13 +1516,11 @@@ ZEND_API ZEND_COLD void zend_error_zstr
  	ZVAL_UNDEF(&EG(last_fatal_error_backtrace));

  	/* Report about uncaught exception in case of fatal errors */
- 	if (EG(exception)) {
+ 	if (EG(exception) && EXPECTED(EG(delayed_oom).state != ZEND_OOM_STATE_HANDLING)) {
 -		zend_execute_data *ex;
 -		const zend_op *opline;
 -
  		if (type & E_FATAL_ERRORS) {
 -			ex = EG(current_execute_data);
 -			opline = NULL;
 +			zend_execute_data *ex = EG(current_execute_data);
 +			const zend_op *opline = NULL;
 +
  			while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) {
  				ex = ex->prev_execute_data;
  			}
@@@ -1979,6 -1989,10 +1984,9 @@@ ZEND_API zend_result zend_execute_scrip
  	zend_result ret = SUCCESS;
  	if (op_array) {
  		zend_execute(op_array, retval);
+ 		if (ZEND_HAS_OOM()) {
+ 			zend_handle_delayed_oom();
+ 		}
 -		zend_exception_restore();
  		if (UNEXPECTED(EG(exception))) {
  			if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
  				zend_user_exception_handler();
diff --cc Zend/zend_API.h
index da871e1eb39,917212cc8f9..ba67948c12b
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@@ -539,17 -535,47 +539,77 @@@ ZEND_API const char *zend_get_type_by_c
  #define DLEXPORT
  #endif

 -#define array_init(arg)				ZVAL_ARR((arg), zend_new_array(0))
 -#define array_init_size(arg, size)	ZVAL_ARR((arg), zend_new_array(size))
 -#define array_init_singleton(arg)	ZVAL_ARR((arg), zend_new_array_singleton())
 +static zend_always_inline void array_init_size(zval *arg, uint32_t size)
 +{
 +	ZVAL_ARR(arg, zend_new_array(size));
 +}
 +
 +static zend_always_inline void array_init(zval *arg)
 +{
 +	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;
+ }
+
 -#define array_finit(arg)			_array_finit((arg), 0)
 -#define array_finit_size(arg, size)	_array_finit((arg), (size))
 -#define array_finit_size_ex(arg, size, packed)  _array_finit_ex((arg), (size), (packed))
 -#define array_finit_size_packed(arg, size)	    _array_finit_ex((arg), (size), /* packed */ true)
 -#define array_finit_size_mixed(arg, size)	    _array_finit_ex((arg), (size), /* packed */ false)
++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_and_properties_init(zval *arg, zend_class_entry *ce, HashTable *properties);
@@@ -1094,8 -1121,10 +1173,9 @@@ static zend_always_inline bool ZVAL_FST
  #define RETURN_FALSE					do { RETVAL_FALSE; return; } while (0)
  #define RETURN_TRUE						do { RETVAL_TRUE; return; } while (0)
  #define RETURN_THROWS()					do { ZEND_ASSERT(EG(exception)); (void) return_value; return; } while (0)
+ #define RETURN_OOM()                    do { ZEND_ASSERT(ZEND_HAS_OOM()); (void) return_value; return; } while (0)

  #define HASH_OF(p) (Z_TYPE_P(p)==IS_ARRAY ? Z_ARRVAL_P(p) : ((Z_TYPE_P(p)==IS_OBJECT ? Z_OBJ_HT_P(p)->get_properties(Z_OBJ_P(p)) : NULL)))
 -#define ZVAL_IS_NULL(z) (Z_TYPE_P(z) == IS_NULL)

  /* For compatibility */
  #define ZEND_MINIT			ZEND_MODULE_STARTUP_N
diff --cc Zend/zend_alloc.c
index dcee8e9b2b3,ba5a70287a4..050fb252e78
--- a/Zend/zend_alloc.c
+++ b/Zend/zend_alloc.c
@@@ -1091,24 -1173,15 +1232,17 @@@ get_chunk
  			if (heap->cached_chunks) {
  				heap->cached_chunks_count--;
  				chunk = heap->cached_chunks;
 -				heap->cached_chunks = chunk->next;
 +				/* The list head lives in the heap, which is as reachable as the chunk headers. */
 +				ZEND_MM_CHECK(ZEND_MM_ALIGNED_OFFSET(chunk, ZEND_MM_CHUNK_SIZE) == 0, "zend_mm_heap corrupted");
 +				heap->cached_chunks = zend_mm_get_next_cached_chunk(heap, chunk);
  			} else {
- #if ZEND_MM_LIMIT
- 				if (UNEXPECTED(ZEND_MM_CHUNK_SIZE > heap->limit - heap->real_size)) {
- 					if (zend_mm_gc(heap)) {
- 						goto get_chunk;
- 					} else if (heap->overflow == 0) {
- #if ZEND_DEBUG
- 						zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted at %s:%d (tried to allocate %zu bytes)", heap->limit, __zend_filename, __zend_lineno, size);
- #else
- 						zend_mm_safe_error(heap, "Allowed memory size of %zu bytes exhausted (tried to allocate %zu bytes)", heap->limit, ZEND_MM_PAGE_SIZE * pages_count);
- #endif
- 						return NULL;
- 					}
+ 				bool did_gc = false;
+ 				if (UNEXPECTED(zend_mm_check_limit(heap, ZEND_MM_CHUNK_SIZE, /* gc */ true, &did_gc ZEND_FILE_LINE_RELAY_CC) == FAILURE)) {
+ 					return NULL;
+ 				} else if (did_gc) {
+ 					goto get_chunk;
  				}
- #endif
+
  				chunk = (zend_mm_chunk*)zend_mm_chunk_alloc(heap, ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE);
  				if (UNEXPECTED(chunk == NULL)) {
  					/* insufficient memory */
@@@ -1827,10 -1895,13 +1970,14 @@@ static zend_always_inline void *zend_mm
  				dbg->orig_lineno = __zend_orig_lineno;
  #endif
  				return ret;
+
+ failed:
+ 				/* original block is left untouched */
+ 				return NULL;
  			}  while (0);

 -		} else /* if (info & ZEND_MM_IS_LARGE_RUN) */ {
 +		} else {
 +			ZEND_MM_CHECK(info & ZEND_MM_IS_LRUN, "zend_mm_heap corrupted");
  			ZEND_MM_CHECK(ZEND_MM_ALIGNED_OFFSET(page_offset, ZEND_MM_PAGE_SIZE) == 0, "zend_mm_heap corrupted");
  			old_size = ZEND_MM_LRUN_PAGES(info) * ZEND_MM_PAGE_SIZE;
  			if (size > ZEND_MM_MAX_SMALL_SIZE && size <= ZEND_MM_MAX_LARGE_SIZE) {
@@@ -3702,4 -3986,10 +4106,3 @@@ ZEND_API char * __zend_strdup(const cha
  	}
  	zend_out_of_memory();
  }
--
 -#ifdef ZTS
 -size_t zend_mm_globals_size(void)
 -{
 -	return sizeof(zend_alloc_globals);
 -}
 -#endif
diff --cc Zend/zend_builtin_functions.c
index e02e0afe2bf,10931dd347c..ffd6e9b7fae
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@@ -1711,19 -1722,7 +1711,19 @@@ ZEND_FUNCTION(get_defined_constants
  }
  /* }}} */

 +static bool backtrace_is_arg_sensitive(const zend_execute_data *call, uint32_t offset)
 +{
 +	const zend_attribute *attribute = zend_get_parameter_attribute_str(
 +		call->func->common.attributes,
 +		"sensitiveparameter",
 +		sizeof("sensitiveparameter") - 1,
 +		offset
 +	);
 +
 +	return attribute != NULL;
 +}
 +
- static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /* {{{ */
+ static bool debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /* {{{ */
  {
  	uint32_t num_args = ZEND_CALL_NUM_ARGS(call);

diff --cc Zend/zend_execute.c
index a5f9d1e8c84,6fdf9bad4cf..4e82fa20759
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@@ -4950,9 -4890,23 +4952,21 @@@ static void cleanup_unfinished_calls(ze
  }
  /* }}} */

+ /* Same as cleanup_unfinished_calls(), but only free the call frames. */
+ static void free_unfinished_calls(zend_execute_data *execute_data)
+ {
+ 	zend_execute_data *call = EX(call);
+
+ 	while (UNEXPECTED(call != NULL)) {
+ 		EX(call) = call->prev_execute_data;
+ 		zend_vm_stack_free_call_frame(call);
+ 		call = EX(call);
+ 	}
+ }
+
  static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
  {
 -	int i;
 -
 -	for (i = 0; i < EX(func)->op_array.last_live_range; i++) {
 +	for (uint32_t i = 0; i < EX(func)->op_array.last_live_range; i++) {
  		const zend_live_range *range = &EX(func)->op_array.live_range[i];
  		if (range->start > op_num) {
  			/* further blocks will not be relevant... */
diff --cc Zend/zend_execute_API.c
index 3160bc0e30c,e3c9fc49c90..75126daa55f
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@@ -442,6 -435,14 +449,13 @@@ ZEND_API void zend_shutdown_executor_va
  	}

  	zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown);
+
+ 	/* may be used by zend_error_zstr_at before init_executor */
+ 	ZVAL_UNDEF(&EG(last_fatal_error_backtrace));
+ 	EG(record_errors) = false;
 -	EG(num_errors) = 0;
 -	EG(errors) = NULL;
++	memset(&EG(errors), 0, sizeof(EG(errors)));
+ 	EG(error_handling) = EH_NORMAL;
+ 	EG(exception) = NULL;
  }

  void shutdown_executor(void) /* {{{ */
@@@ -480,9 -483,10 +494,11 @@@
  		 */
  		zend_hash_discard(EG(function_table), EG(persistent_functions_count));
  		zend_hash_discard(EG(class_table), EG(persistent_classes_count));
+ 		EG(objects_store).object_buckets = NULL;
+ 		EG(objects_store).top = 1;
  	} else {
  		zend_vm_stack_destroy();
 +		zend_vm_stack_destroy_caches();

  		if (EG(full_tables_cleanup)) {
  			zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
@@@ -1102,27 -1076,26 +1122,30 @@@ 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 (zend_atomic_bool_exchange_ex(&EG(vm_interrupt), false)) {
- 			if (zend_atomic_bool_load_ex(&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))) {
+ 			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) {
 +		OBJ_RELEASE(pinned_this);
 +	}
 +
  	zend_vm_stack_free_call_frame(call);

  	if (UNEXPECTED(EG(exception))) {
diff --cc Zend/zend_globals.h
index b7835ed6322,73210afb59a..c3034f8c8ed
--- a/Zend/zend_globals.h
+++ b/Zend/zend_globals.h
@@@ -324,25 -321,11 +326,27 @@@ struct _zend_executor_globals

  	zend_strtod_state strtod_state;

 +	HashTable callable_convert_cache;
 +	HashTable partial_function_application_cache;
 +	zend_stack lambda_cache;
 +
 +	zend_vm_stack  vm_stack_page_cache;
 +	uint32_t       vm_stack_page_cache_count;
 +	/* Fibers use a different page size, so they need a separate cache */
 +	zend_vm_stack  fiber_vm_stack_page_cache;
 +	uint32_t       fiber_vm_stack_page_cache_count;
 +
  	void *reserved[ZEND_MAX_RESERVED_RESOURCES];
+
+ 	zend_oom_info delayed_oom;
  };

 +#ifdef ZTS
 +/* Compile-time offsets of the hot globals, in a reserved region just before *_tsrm_ls_cache. */
 +# define ZEND_CG_OFFSET   (-(ptrdiff_t) TSRM_ALIGNED_SIZE(sizeof(zend_compiler_globals)))
 +# define ZEND_EG_OFFSET   (ZEND_CG_OFFSET - (ptrdiff_t) TSRM_ALIGNED_SIZE(sizeof(zend_executor_globals)))
 +#endif
 +
  #define EG_FLAGS_INITIAL				(0)
  #define EG_FLAGS_IN_SHUTDOWN			(1<<0)
  #define EG_FLAGS_OBJECT_STORE_NO_REUSE	(1<<1)
diff --cc Zend/zend_hash.c
index 4640846ecc7,0ed782ddd98..dc4c7a6c91d
--- a/Zend/zend_hash.c
+++ b/Zend/zend_hash.c
@@@ -1110,10 -1280,7 +1286,13 @@@ static zend_always_inline zval *_zend_h
  		if ((flag & (HASH_ADD_NEW|HASH_ADD_NEXT)) != (HASH_ADD_NEW|HASH_ADD_NEXT)
  		 && h < ht->nNumUsed) {
  			zv = ht->arPacked + h;
 -			if (Z_TYPE_P(zv) != IS_UNDEF) {
 +			if (flag & HASH_ADD_NEW) {
 +				ZEND_ASSERT(Z_TYPE_P(zv) == IS_UNDEF);
- 				goto convert_to_hash;
++				zend_result status = zend_hash_fconvert_packed_to_hash(ht, flag & HASH_FALLIBLE);
++				if (ZEND_CONST_COND(flag & HASH_FALLIBLE, true) && UNEXPECTED(status == FAILURE)) {
++					return HASH_NOMEM;
++				}
 +			} else if (Z_TYPE_P(zv) != IS_UNDEF) {
  				if (flag & HASH_LOOKUP) {
  					return zv;
  				}
diff --cc Zend/zend_hash.h
index c7cdbe95866,ecbcedffcfa..e7c86808182
--- a/Zend/zend_hash.h
+++ b/Zend/zend_hash.h
@@@ -217,8 -232,10 +231,11 @@@ static zend_always_inline zval *zend_ha
  /* Find or add NULL, if doesn't exist */
  ZEND_API zval* ZEND_FASTCALL zend_hash_lookup(HashTable *ht, zend_string *key);
  ZEND_API zval* ZEND_FASTCALL zend_hash_index_lookup(HashTable *ht, zend_ulong h);
 +ZEND_API zval* ZEND_FASTCALL zend_hash_str_lookup(HashTable *ht, const char *str, size_t len);

+ ZEND_API zval* ZEND_FASTCALL zend_hash_flookup(HashTable *ht, zend_string *key);
+ ZEND_API zval* ZEND_FASTCALL zend_hash_index_flookup(HashTable *ht, zend_ulong h);
+
  #define ZEND_HASH_INDEX_LOOKUP(_ht, _h, _ret) do { \
  		if (EXPECTED(HT_IS_PACKED(_ht))) { \
  			if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed)) { \
diff --cc Zend/zend_objects.c
index 03ac5de67c7,924448a4cf0..1401e089afd
--- a/Zend/zend_objects.c
+++ b/Zend/zend_objects.c
@@@ -193,25 -194,19 +193,37 @@@ ZEND_API zend_object* ZEND_FASTCALL zen
  	return object;
  }

+ ZEND_API zend_object* ZEND_FASTCALL zend_objects_fnew(zend_class_entry *ce)
+ {
+ 	zend_object *object = femalloc(sizeof(zend_object) + zend_object_properties_size(ce), /* fallible */ true);
+ 	if (UNEXPECTED(!object)) {
+ 		return NULL;
+ 	}
+
+ 	_zend_object_std_init(object, ce);
+ 	object->handlers = &std_object_handlers;
+ 	return object;
+ }
+
 -ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, zend_object *old_object)
 +ZEND_API void ZEND_FASTCALL zend_object_set_properties_reinitable(zend_object *object, bool reinitable)
 +{
 +	if (!ZEND_CLASS_HAS_READONLY_PROPS(object->ce)) {
 +		return;
 +	}
 +
 +	for (uint32_t i = 0; i < object->ce->default_properties_count; i++) {
 +		zval *prop = OBJ_PROP_NUM(object, i);
 +		if (reinitable) {
 +			if (!Z_ISUNDEF_P(prop)) {
 +				Z_PROP_FLAG_P(prop) |= IS_PROP_REINITABLE;
 +			}
 +		} else {
 +			Z_PROP_FLAG_P(prop) &= ~IS_PROP_REINITABLE;
 +		}
 +	}
 +}
 +
 +ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, const zend_object *old_object)
  {
  	bool has_clone_method = old_object->ce->clone != NULL;

diff --cc Zend/zend_objects.h
index 8bb6c053b0c,569007904d9..641f322ffbd
--- a/Zend/zend_objects.h
+++ b/Zend/zend_objects.h
@@@ -24,8 -25,8 +24,9 @@@
  BEGIN_EXTERN_C()
  ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class_entry *ce);
  ZEND_API zend_object* ZEND_FASTCALL zend_objects_new(zend_class_entry *ce);
+ ZEND_API zend_object* ZEND_FASTCALL zend_objects_fnew(zend_class_entry *ce);
 -ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, zend_object *old_object);
 +ZEND_API void ZEND_FASTCALL zend_objects_clone_members(zend_object *new_object, const zend_object *old_object);
 +ZEND_API void ZEND_FASTCALL zend_object_set_properties_reinitable(zend_object *object, bool reinitable);

  ZEND_API void zend_object_std_dtor(zend_object *object);
  ZEND_API void zend_objects_destroy_object(zend_object *object);
diff --cc Zend/zend_operators.h
index 153a6cea6b4,b8326ed2b45..319209de066
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@@ -494,6 -502,12 +496,10 @@@ static zend_always_inline zend_string*
  	return zend_string_toupper_ex(str, false);
  }

+ static zend_always_inline zend_string* zend_string_ftolower(zend_string *str) {
+ 	return zend_string_ftolower_ex(str, false);
+ }
+
 -ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2);
 -ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3);
  ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2);
  ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length);
  ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2);
diff --cc Zend/zend_string.h
index ad66fe168c8,c69ef449061..f1c65217db5
--- a/Zend/zend_string.h
+++ b/Zend/zend_string.h
@@@ -43,8 -38,7 +43,9 @@@ ZEND_API extern zend_string_init_existi
  ZEND_API zend_ulong ZEND_FASTCALL zend_string_hash_func(zend_string *str);
  ZEND_API zend_ulong ZEND_FASTCALL zend_hash_func(const char *str, size_t len);
  ZEND_API zend_string* ZEND_FASTCALL zend_interned_string_find_permanent(zend_string *str);
+ ZEND_API zend_string* ZEND_FASTCALL zend_string_finit_existing_interned(const char *str, size_t len, bool permanent, bool fallible);
 +ZEND_API void ZEND_FASTCALL zend_bin2hex(char *out, const unsigned char *in, size_t in_len);
 +ZEND_API zend_string *zend_bin2hex_str(const unsigned char *in, size_t in_len);

  ZEND_API zend_string *zend_string_concat2(
  	const char *str1, size_t str1_len,
@@@ -339,48 -391,11 +414,53 @@@ static zend_always_inline zend_string *
  	return ret;
  }

+ static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s, size_t n, size_t m, size_t l, bool persistent)
+ {
+ 	return zend_string_safe_frealloc(s, n, m, l, persistent, /* fallible */ false);
+ }
+
 +static zend_always_inline char *zend_cstr_append_char(const char *str, size_t len, char c) {
 +	char *res = (char *)safe_emalloc(len, 1, 2);
 +	if (len > 0) {
 +		memcpy(res, str, len);
 +	}
 +	res[len] = c;
 +	res[len + 1] = '\0';
 +	return res;
 +}
 +
 +static zend_always_inline char *zend_cstr_concat(const char *s1, size_t len1, const char *s2, size_t len2) {
 +	size_t size = zend_safe_address_guarded(1, len1, len2);
 +	size = zend_safe_address_guarded(1, size, 1);
 +	char *res = (char *)emalloc(size);
 +	if (len1 > 0) {
 +		memcpy(res, s1, len1);
 +	}
 +	if (len2 > 0) {
 +		memcpy(res + len1, s2, len2);
 +	}
 +	res[len1 + len2] = '\0';
 +	return res;
 +}
 +
 +static zend_always_inline char *zend_cstr_concat3(const char *s1, size_t len1, const char *s2, size_t len2, const char *s3, size_t len3) {
 +	size_t size = zend_safe_address_guarded(1, len1, len2);
 +	size = zend_safe_address_guarded(1, size, len3);
 +	size = zend_safe_address_guarded(1, size, 1);
 +	char *res = (char *)emalloc(size);
 +	if (len1 > 0) {
 +		memcpy(res, s1, len1);
 +	}
 +	if (len2 > 0) {
 +		memcpy(res + len1, s2, len2);
 +	}
 +	if (len3 > 0) {
 +		memcpy(res + len1 + len2, s3, len3);
 +	}
 +	res[len1 + len2 + len3] = '\0';
 +	return res;
 +}
 +
  static zend_always_inline void zend_string_free(zend_string *s)
  {
  	if (!ZSTR_IS_INTERNED(s)) {
diff --cc Zend/zend_types.h
index b30f53d7f91,7371f57b07c..932d131820d
--- a/Zend/zend_types.h
+++ b/Zend/zend_types.h
@@@ -480,96 -483,93 +480,108 @@@ ZEND_ATTRIBUTE_CONST static zend_always
  #define HT_HASH(ht, idx) \
  	HT_HASH_EX((ht)->arHash, idx)

 -#define HT_SIZE_TO_MASK(nTableSize) \
 -	((uint32_t)(-((nTableSize) + (nTableSize))))
 -#define HT_HASH_SIZE(nTableMask) \
 -	(((size_t)-(uint32_t)(nTableMask)) * sizeof(uint32_t))
 -#define HT_DATA_SIZE(nTableSize) \
 -	((size_t)(nTableSize) * sizeof(Bucket))
 -#define HT_SIZE_EX(nTableSize, nTableMask) \
 -	(HT_DATA_SIZE((nTableSize)) + HT_HASH_SIZE((nTableMask)))
 -#define HT_SIZE(ht) \
 -	HT_SIZE_EX((ht)->nTableSize, (ht)->nTableMask)
 -#define HT_USED_SIZE(ht) \
 -	(HT_HASH_SIZE((ht)->nTableMask) + ((size_t)(ht)->nNumUsed * sizeof(Bucket)))
 -#define HT_PACKED_DATA_SIZE(nTableSize) \
 -	((size_t)(nTableSize) * sizeof(zval))
 -#define HT_PACKED_SIZE_EX(nTableSize, nTableMask) \
 -	(HT_PACKED_DATA_SIZE((nTableSize)) + HT_HASH_SIZE((nTableMask)))
 -#define HT_PACKED_SIZE(ht) \
 -	HT_PACKED_SIZE_EX((ht)->nTableSize, (ht)->nTableMask)
 -#define HT_PACKED_USED_SIZE(ht) \
 -	(HT_HASH_SIZE((ht)->nTableMask) + ((size_t)(ht)->nNumUsed * sizeof(zval)))
 +ZEND_ATTRIBUTE_CONST static zend_always_inline uint32_t HT_SIZE_TO_MASK(uint32_t nTableSize) {
 +	return (uint32_t)(-(nTableSize + nTableSize));
 +}
 +
 +ZEND_ATTRIBUTE_CONST static zend_always_inline size_t HT_HASH_SIZE(uint32_t nTableMask) {
 +	return ((size_t)(-nTableMask)) * sizeof(uint32_t);
 +}
 +
 +ZEND_ATTRIBUTE_CONST static zend_always_inline size_t HT_DATA_SIZE(uint32_t nTableSize) {
 +	return ((size_t)nTableSize) * sizeof(Bucket);
 +}
 +
 +ZEND_ATTRIBUTE_CONST static zend_always_inline size_t HT_SIZE_EX(uint32_t nTableSize, uint32_t nTableMask) {
 +	return HT_DATA_SIZE(nTableSize) + HT_HASH_SIZE(nTableMask);
 +}
 +
 +static zend_always_inline size_t HT_SIZE(const HashTable *ht) {
 +	return HT_SIZE_EX(ht->nTableSize, ht->nTableMask);
 +}
 +
 +static zend_always_inline size_t HT_USED_SIZE(const HashTable *ht) {
 +	return HT_HASH_SIZE(ht->nTableMask) + ((size_t)ht->nNumUsed * sizeof(Bucket));
 +}
 +
 +ZEND_ATTRIBUTE_CONST static zend_always_inline size_t HT_PACKED_DATA_SIZE(uint32_t nTableSize) {
 +	return ((size_t)nTableSize) * sizeof(zval);
 +}
 +
 +ZEND_ATTRIBUTE_CONST static zend_always_inline size_t HT_PACKED_SIZE_EX(uint32_t nTableSize, uint32_t nTableMask) {
 +	return HT_PACKED_DATA_SIZE(nTableSize) + HT_HASH_SIZE(nTableMask);
 +}
 +
 +static zend_always_inline size_t HT_PACKED_SIZE(const HashTable *ht) {
 +	return HT_PACKED_SIZE_EX(ht->nTableSize, ht->nTableMask);
 +}
 +
 +static zend_always_inline size_t HT_PACKED_USED_SIZE(const HashTable *ht) {
 +	return HT_HASH_SIZE(ht->nTableMask) + ((size_t)ht->nNumUsed * sizeof(zval));
 +}
 +
 +static zend_always_inline void HT_HASH_RESET(HashTable *ht) {
 +	char *p = (char*)&HT_HASH(ht, ht->nTableMask);
 +	size_t size = HT_HASH_SIZE(ht->nTableMask);
 +
  #if defined(__AVX2__)
- 	__m256i ymm0 = _mm256_setzero_si256();
- 	ymm0 = _mm256_cmpeq_epi64(ymm0, ymm0);
- 	ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
- 	do {
- 		_mm256_storeu_si256((__m256i*)p, ymm0);
- 		_mm256_storeu_si256((__m256i*)(p+32), ymm0);
- 		p += 64;
- 		size -= 64;
- 	} while (size != 0);
 -# define HT_HASH_RESET(ht) do { \
 -		char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \
 -		size_t size = HT_HASH_SIZE((ht)->nTableMask); \
 -		if (UNEXPECTED(size < 64)) { \
 -			memset(p, HT_INVALID_IDX, size); \
 -		} else { \
 -			__m256i ymm0 = _mm256_setzero_si256(); \
 -			ymm0 = _mm256_cmpeq_epi64(ymm0, ymm0); \
 -			ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \
 -			do { \
 -				_mm256_storeu_si256((__m256i*)p, ymm0); \
 -				_mm256_storeu_si256((__m256i*)(p+32), ymm0); \
 -				p += 64; \
 -				size -= 64; \
 -			} while (size != 0); \
 -		} \
 -	} while (0)
++	if (UNEXPECTED(size < 64)) {
++		memset(p, HT_INVALID_IDX, size);
++	} else {
++		__m256i ymm0 = _mm256_setzero_si256();
++		ymm0 = _mm256_cmpeq_epi64(ymm0, ymm0);
++		ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
++		do {
++			_mm256_storeu_si256((__m256i*)p, ymm0);
++			_mm256_storeu_si256((__m256i*)(p+32), ymm0);
++			p += 64;
++			size -= 64;
++		} while (size != 0);
++	}
  #elif defined(__SSE2__)
- 	__m128i xmm0 = _mm_setzero_si128();
- 	xmm0 = _mm_cmpeq_epi8(xmm0, xmm0);
- 	ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
- 	do {
- 		_mm_storeu_si128((__m128i*)p, xmm0);
- 		_mm_storeu_si128((__m128i*)(p+16), xmm0);
- 		_mm_storeu_si128((__m128i*)(p+32), xmm0);
- 		_mm_storeu_si128((__m128i*)(p+48), xmm0);
- 		p += 64;
- 		size -= 64;
- 	} while (size != 0);
 -# define HT_HASH_RESET(ht) do { \
 -		char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \
 -		size_t size = HT_HASH_SIZE((ht)->nTableMask); \
 -		if (UNEXPECTED(size < 64)) { \
 -			memset(p, HT_INVALID_IDX, size); \
 -		} else { \
 -			__m128i xmm0 = _mm_setzero_si128(); \
 -			xmm0 = _mm_cmpeq_epi8(xmm0, xmm0); \
 -			ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \
 -			do { \
 -				_mm_storeu_si128((__m128i*)p, xmm0); \
 -				_mm_storeu_si128((__m128i*)(p+16), xmm0); \
 -				_mm_storeu_si128((__m128i*)(p+32), xmm0); \
 -				_mm_storeu_si128((__m128i*)(p+48), xmm0); \
 -				p += 64; \
 -				size -= 64; \
 -			} while (size != 0); \
 -		} \
 -	} while (0)
++	if (UNEXPECTED(size < 64)) {
++		memset(p, HT_INVALID_IDX, size);
++	} else {
++		__m128i xmm0 = _mm_setzero_si128();
++		xmm0 = _mm_cmpeq_epi8(xmm0, xmm0);
++		ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
++		do {
++			_mm_storeu_si128((__m128i*)p, xmm0);
++			_mm_storeu_si128((__m128i*)(p+16), xmm0);
++			_mm_storeu_si128((__m128i*)(p+32), xmm0);
++			_mm_storeu_si128((__m128i*)(p+48), xmm0);
++			p += 64;
++			size -= 64;
++		} while (size != 0);
++	}
  #elif defined(__aarch64__) || defined(_M_ARM64)
- 	int32x4_t t = vdupq_n_s32(-1);
- 	ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
- 	do {
- 		vst1q_s32((int32_t*)p, t);
- 		vst1q_s32((int32_t*)(p+16), t);
- 		vst1q_s32((int32_t*)(p+32), t);
- 		vst1q_s32((int32_t*)(p+48), t);
- 		p += 64;
- 		size -= 64;
- 	} while (size != 0);
 -# define HT_HASH_RESET(ht) do { \
 -		char *p = (char*)&HT_HASH(ht, (ht)->nTableMask); \
 -		size_t size = HT_HASH_SIZE((ht)->nTableMask); \
 -		if (UNEXPECTED(size < 64)) { \
 -			memset(p, HT_INVALID_IDX, size); \
 -		} else { \
 -			int32x4_t t = vdupq_n_s32(-1); \
 -			ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0)); \
 -			do { \
 -				vst1q_s32((int32_t*)p, t); \
 -				vst1q_s32((int32_t*)(p+16), t); \
 -				vst1q_s32((int32_t*)(p+32), t); \
 -				vst1q_s32((int32_t*)(p+48), t); \
 -				p += 64; \
 -				size -= 64; \
 -			} while (size != 0); \
 -		} \
 -	} while (0)
++	if (UNEXPECTED(size < 64)) {
++		memset(p, HT_INVALID_IDX, size);
++	} else {
++		int32x4_t t = vdupq_n_s32(-1);
++		ZEND_ASSERT(size >= 64 && ((size & 0x3f) == 0));
++		do {
++			vst1q_s32((int32_t*)p, t);
++			vst1q_s32((int32_t*)(p+16), t);
++			vst1q_s32((int32_t*)(p+32), t);
++			vst1q_s32((int32_t*)(p+48), t);
++			p += 64;
++			size -= 64;
++		} while (size != 0);
++	}
  #else
 -# define HT_HASH_RESET(ht) \
 -	memset(&HT_HASH(ht, (ht)->nTableMask), HT_INVALID_IDX, HT_HASH_SIZE((ht)->nTableMask))
 +	memset(p, HT_INVALID_IDX, size);
  #endif
 -#define HT_HASH_RESET_PACKED(ht) do { \
 -		HT_HASH(ht, -2) = HT_INVALID_IDX; \
 -		HT_HASH(ht, -1) = HT_INVALID_IDX; \
 -	} while (0)
 -#define HT_HASH_TO_BUCKET(ht, idx) \
 -	HT_HASH_TO_BUCKET_EX((ht)->arData, idx)
 +}
 +
 +static zend_always_inline void HT_HASH_RESET_PACKED(HashTable *ht) {
 +	HT_HASH(ht, -2) = HT_INVALID_IDX;
 +	HT_HASH(ht, -1) = HT_INVALID_IDX;
 +}
 +
 +static zend_always_inline Bucket *HT_HASH_TO_BUCKET(HashTable *ht, uint32_t idx) {
 +	return HT_HASH_TO_BUCKET_EX(ht->arData, idx);
 +}

  #define HT_SET_DATA_ADDR(ht, ptr) do { \
  		(ht)->arData = (Bucket*)(((char*)(ptr)) + HT_HASH_SIZE((ht)->nTableMask)); \
diff --cc Zend/zend_vm_def.h
index eb0507da830,533a7d342a1..3ea6d7250ab
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@@ -9968,8 -9785,9 +9971,9 @@@ ZEND_VM_HANDLER(204, ZEND_FRAMELESS_ICA
  #endif
  	{
  		zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
 -		function(EX_VAR(opline->result.var));
 +		function(result);
  	}
+ 	ZEND_VM_FCALL_INTERRUPT_CHECK(execute_data);
  	ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
  }

diff --cc Zend/zend_vm_execute.h
index 2b14b78a43f,df733f525d5..8b6a5533fa3
Binary files differ
diff --cc ext/bz2/bz2.c
index 891e51bd563,b67bb8dbd7e..dd1b87d2bf6
--- a/ext/bz2/bz2.c
+++ b/ext/bz2/bz2.c
@@@ -572,7 -576,11 +578,11 @@@ PHP_FUNCTION(bzdecompress
  			/* no reason to continue if we're going to drop it anyway */
  			break;
  		}
- 		dest = zend_string_safe_realloc(dest, 1, (size_t) bzs.avail_out + 1, (size_t) size, 0);
 -		tmp = zend_string_safe_frealloc(dest, 1, bzs.avail_out+1, (size_t) size, 0, /* fallible */ true);
++		tmp = zend_string_safe_frealloc(dest, 1, (size_t) bzs.avail_out + 1, (size_t) size, 0, /* fallible */ true);
+ 		if (!tmp) {
+ 			goto failure;
+ 		}
+ 		dest = tmp;
  		bzs.next_out = ZSTR_VAL(dest) + size;
  	}

diff --cc ext/curl/tests/responder/get.inc
index f84d4b62858,2ae6120c1a4..edf806ece16
--- a/ext/curl/tests/responder/get.inc
+++ b/ext/curl/tests/responder/get.inc
@@@ -46,12 -46,13 +46,19 @@@
      case 'method':
        echo $_SERVER['REQUEST_METHOD'];
        break;
 +    case 'redirect':
 +      // A 307 preserves the method and body, so libcurl must rewind the upload
 +      // (via CURLOPT_SEEKFUNCTION) before resending it to the new location.
 +      $target = $_GET['target'] ?? 'input';
 +      $code = $_GET['code'] ?? 307;
 +      header('Location: /get.inc?test=' . $target, true, $code);
+     case 'bigbody':
+       $mib = isset($_GET['mib']) ? (int) $_GET['mib'] : 12;
+       header('Content-Type: application/octet-stream');
+       $chunk = str_repeat('x', 1024 * 1024);
+       for ($i = 0; $i < $mib; $i++) {
+         echo $chunk;
+       }
        break;
      default:
        echo "Hello World!\n";
diff --cc ext/date/lib/parse_date.c
index 3380ba73265,9a9ae5523eb..41566f94ed6
--- a/ext/date/lib/parse_date.c
+++ b/ext/date/lib/parse_date.c
@@@ -1,4 -1,4 +1,4 @@@
- /* Generated by re2c 1.0.3 on Wed Aug  5 11:34:24 2026 */
 -/* Generated by re2c 1.0.3 on Thu Oct  1 14:54:40 2026 */
++/* Generated by re2c 1.0.3 on Thu Oct  1 17:09:49 2026 */
  #line 1 "ext/date/lib/parse_date.re"
  /*
   * The MIT License (MIT)
@@@ -1018,11 -1045,11 +1035,11 @@@ static int scan(Scanner *s, timelib_tz_
  std:
  	s->tok = cursor;
  	s->len = 0;
- #line 1151 "ext/date/lib/parse_date.re"
 -#line 1178 "ext/date/lib/parse_date.re"
++#line 1168 "ext/date/lib/parse_date.re"



- #line 1026 "ext/date/lib/parse_date.c"
 -#line 1053 "ext/date/lib/parse_date.c"
++#line 1043 "ext/date/lib/parse_date.c"
  {
  	YYCTYPE yych;
  	unsigned int yyaccept = 0;
@@@ -1203,23 -1230,23 +1220,23 @@@ yy2
  	YYDEBUG(2, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(3, *YYCURSOR);
- #line 1984 "ext/date/lib/parse_date.re"
 -#line 2011 "ext/date/lib/parse_date.re"
++#line 2001 "ext/date/lib/parse_date.re"
  	{
  		s->pos = cursor; s->line++;
  		goto std;
  	}
- #line 1212 "ext/date/lib/parse_date.c"
 -#line 1239 "ext/date/lib/parse_date.c"
++#line 1229 "ext/date/lib/parse_date.c"
  yy4:
  	YYDEBUG(4, *YYCURSOR);
  	++YYCURSOR;
  yy5:
  	YYDEBUG(5, *YYCURSOR);
- #line 1990 "ext/date/lib/parse_date.re"
 -#line 2017 "ext/date/lib/parse_date.re"
++#line 2007 "ext/date/lib/parse_date.re"
  	{
  		add_error(s, TIMELIB_ERR_UNEXPECTED_CHARACTER, "Unexpected character");
  		goto std;
  	}
- #line 1223 "ext/date/lib/parse_date.c"
 -#line 1250 "ext/date/lib/parse_date.c"
++#line 1240 "ext/date/lib/parse_date.c"
  yy6:
  	YYDEBUG(6, *YYCURSOR);
  	yyaccept = 0;
@@@ -1234,11 -1261,11 +1251,11 @@@
  	if (yych <= '9') goto yy58;
  yy8:
  	YYDEBUG(8, *YYCURSOR);
- #line 1979 "ext/date/lib/parse_date.re"
 -#line 2006 "ext/date/lib/parse_date.re"
++#line 1996 "ext/date/lib/parse_date.re"
  	{
  		goto std;
  	}
- #line 1242 "ext/date/lib/parse_date.c"
 -#line 1269 "ext/date/lib/parse_date.c"
++#line 1259 "ext/date/lib/parse_date.c"
  yy9:
  	YYDEBUG(9, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -1272,11 -1299,11 +1289,11 @@@ yy11
  	YYDEBUG(11, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(12, *YYCURSOR);
- #line 1974 "ext/date/lib/parse_date.re"
 -#line 2001 "ext/date/lib/parse_date.re"
++#line 1991 "ext/date/lib/parse_date.re"
  	{
  		goto std;
  	}
- #line 1280 "ext/date/lib/parse_date.c"
 -#line 1307 "ext/date/lib/parse_date.c"
++#line 1297 "ext/date/lib/parse_date.c"
  yy13:
  	YYDEBUG(13, *YYCURSOR);
  	yyaccept = 1;
@@@ -1777,7 -1804,7 +1794,7 @@@ yy19
  	}
  yy20:
  	YYDEBUG(20, *YYCURSOR);
- #line 1889 "ext/date/lib/parse_date.re"
 -#line 1916 "ext/date/lib/parse_date.re"
++#line 1906 "ext/date/lib/parse_date.re"
  	{
  		int tz_not_found;
  		DEBUG_OUTPUT("tzcorrection | tz");
@@@ -1791,7 -1818,7 +1808,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_TIMEZONE;
  	}
- #line 1795 "ext/date/lib/parse_date.c"
 -#line 1822 "ext/date/lib/parse_date.c"
++#line 1812 "ext/date/lib/parse_date.c"
  yy21:
  	YYDEBUG(21, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -3596,7 -3623,7 +3613,7 @@@ yy80
  	}
  yy81:
  	YYDEBUG(81, *YYCURSOR);
- #line 1636 "ext/date/lib/parse_date.re"
 -#line 1663 "ext/date/lib/parse_date.re"
++#line 1653 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("datenoyearrev");
  		TIMELIB_INIT;
@@@ -3607,7 -3634,7 +3624,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_DATE_TEXT;
  	}
- #line 3611 "ext/date/lib/parse_date.c"
 -#line 3638 "ext/date/lib/parse_date.c"
++#line 3628 "ext/date/lib/parse_date.c"
  yy82:
  	YYDEBUG(82, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -4122,7 -4149,7 +4139,7 @@@ yy112
  	}
  	if (yych == '.') goto yy289;
  	YYDEBUG(114, *YYCURSOR);
- #line 1211 "ext/date/lib/parse_date.re"
 -#line 1238 "ext/date/lib/parse_date.re"
++#line 1228 "ext/date/lib/parse_date.re"
  	{
  		timelib_ull i;

@@@ -4147,7 -4174,7 +4164,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_RELATIVE;
  	}
- #line 4151 "ext/date/lib/parse_date.c"
 -#line 4178 "ext/date/lib/parse_date.c"
++#line 4168 "ext/date/lib/parse_date.c"
  yy115:
  	YYDEBUG(115, *YYCURSOR);
  	++YYCURSOR;
@@@ -5873,7 -5900,7 +5890,7 @@@ yy176
  	}
  yy177:
  	YYDEBUG(177, *YYCURSOR);
- #line 1377 "ext/date/lib/parse_date.re"
 -#line 1404 "ext/date/lib/parse_date.re"
++#line 1394 "ext/date/lib/parse_date.re"
  	{
  		int tz_not_found;
  		DEBUG_OUTPUT("timetiny24 | timeshort24 | timelong24 | iso8601long");
@@@ -5900,7 -5927,7 +5917,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_TIME24_WITH_ZONE;
  	}
- #line 5904 "ext/date/lib/parse_date.c"
 -#line 5931 "ext/date/lib/parse_date.c"
++#line 5921 "ext/date/lib/parse_date.c"
  yy178:
  	YYDEBUG(178, *YYCURSOR);
  	yyaccept = 4;
@@@ -6929,7 -6956,7 +6946,7 @@@ yy223
  	}
  yy224:
  	YYDEBUG(224, *YYCURSOR);
- #line 1471 "ext/date/lib/parse_date.re"
 -#line 1498 "ext/date/lib/parse_date.re"
++#line 1488 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("americanshort | american");
@@@ -6944,7 -6971,7 +6961,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_AMERICAN;
  	}
- #line 6948 "ext/date/lib/parse_date.c"
 -#line 6975 "ext/date/lib/parse_date.c"
++#line 6965 "ext/date/lib/parse_date.c"
  yy225:
  	YYDEBUG(225, *YYCURSOR);
  	yyaccept = 5;
@@@ -7187,7 -7214,7 +7204,7 @@@ yy250
  	if (yych <= '9') goto yy431;
  yy251:
  	YYDEBUG(251, *YYCURSOR);
- #line 1553 "ext/date/lib/parse_date.re"
 -#line 1580 "ext/date/lib/parse_date.re"
++#line 1570 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("datefull");
@@@ -7201,7 -7228,7 +7218,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_DATE_FULL;
  	}
- #line 7205 "ext/date/lib/parse_date.c"
 -#line 7232 "ext/date/lib/parse_date.c"
++#line 7222 "ext/date/lib/parse_date.c"
  yy252:
  	YYDEBUG(252, *YYCURSOR);
  	yyaccept = 3;
@@@ -7315,7 -7342,7 +7332,7 @@@ yy259
  	if (yych == 'e') goto yy440;
  yy260:
  	YYDEBUG(260, *YYCURSOR);
- #line 1958 "ext/date/lib/parse_date.re"
 -#line 1985 "ext/date/lib/parse_date.re"
++#line 1975 "ext/date/lib/parse_date.re"
  	{
  		timelib_ull i;
  		DEBUG_OUTPUT("relative");
@@@ -7330,7 -7357,7 +7347,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_RELATIVE;
  	}
- #line 7334 "ext/date/lib/parse_date.c"
 -#line 7361 "ext/date/lib/parse_date.c"
++#line 7351 "ext/date/lib/parse_date.c"
  yy261:
  	YYDEBUG(261, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -7776,7 -7803,7 +7793,7 @@@ yy289
  	if (yych <= '9') goto yy471;
  yy290:
  	YYDEBUG(290, *YYCURSOR);
- #line 1237 "ext/date/lib/parse_date.re"
 -#line 1264 "ext/date/lib/parse_date.re"
++#line 1254 "ext/date/lib/parse_date.re"
  	{
  		timelib_sll i;
  		timelib_ull us;
@@@ -7815,7 -7842,7 +7832,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_RELATIVE;
  	}
- #line 7819 "ext/date/lib/parse_date.c"
 -#line 7846 "ext/date/lib/parse_date.c"
++#line 7836 "ext/date/lib/parse_date.c"
  yy291:
  	YYDEBUG(291, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -7840,7 -7867,7 +7857,7 @@@ yy292
  	}
  yy293:
  	YYDEBUG(293, *YYCURSOR);
- #line 1799 "ext/date/lib/parse_date.re"
 -#line 1826 "ext/date/lib/parse_date.re"
++#line 1816 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("ago");
  		TIMELIB_INIT;
@@@ -7860,7 -7887,7 +7877,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_AGO;
  	}
- #line 7864 "ext/date/lib/parse_date.c"
 -#line 7891 "ext/date/lib/parse_date.c"
++#line 7881 "ext/date/lib/parse_date.c"
  yy294:
  	YYDEBUG(294, *YYCURSOR);
  	yyaccept = 7;
@@@ -7899,7 -7926,7 +7916,7 @@@
  	}
  yy295:
  	YYDEBUG(295, *YYCURSOR);
- #line 1879 "ext/date/lib/parse_date.re"
 -#line 1906 "ext/date/lib/parse_date.re"
++#line 1896 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("monthtext");
  		TIMELIB_INIT;
@@@ -7908,7 -7935,7 +7925,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_DATE_TEXT;
  	}
- #line 7912 "ext/date/lib/parse_date.c"
 -#line 7939 "ext/date/lib/parse_date.c"
++#line 7929 "ext/date/lib/parse_date.c"
  yy296:
  	YYDEBUG(296, *YYCURSOR);
  	yyaccept = 7;
@@@ -8483,7 -8510,7 +8500,7 @@@ yy314
  	}
  yy315:
  	YYDEBUG(315, *YYCURSOR);
- #line 1820 "ext/date/lib/parse_date.re"
 -#line 1847 "ext/date/lib/parse_date.re"
++#line 1837 "ext/date/lib/parse_date.re"
  	{
  		const timelib_relunit* relunit;
  		DEBUG_OUTPUT("daytext");
@@@ -8500,7 -8527,7 +8517,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_WEEKDAY;
  	}
- #line 8504 "ext/date/lib/parse_date.c"
 -#line 8531 "ext/date/lib/parse_date.c"
++#line 8521 "ext/date/lib/parse_date.c"
  yy316:
  	YYDEBUG(316, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -8768,7 -8795,7 +8785,7 @@@ yy324
  	}
  yy325:
  	YYDEBUG(325, *YYCURSOR);
- #line 1622 "ext/date/lib/parse_date.re"
 -#line 1649 "ext/date/lib/parse_date.re"
++#line 1639 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("datetextual | datenoyear");
@@@ -8781,7 -8808,7 +8798,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_DATE_TEXT;
  	}
- #line 8785 "ext/date/lib/parse_date.c"
 -#line 8812 "ext/date/lib/parse_date.c"
++#line 8802 "ext/date/lib/parse_date.c"
  yy326:
  	YYDEBUG(326, *YYCURSOR);
  	yyaccept = 10;
@@@ -9475,7 -9502,7 +9492,7 @@@ yy350
  	}
  yy351:
  	YYDEBUG(351, *YYCURSOR);
- #line 1168 "ext/date/lib/parse_date.re"
 -#line 1195 "ext/date/lib/parse_date.re"
++#line 1185 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("now");
  		TIMELIB_INIT;
@@@ -9483,7 -9510,7 +9500,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_RELATIVE;
  	}
- #line 9487 "ext/date/lib/parse_date.c"
 -#line 9514 "ext/date/lib/parse_date.c"
++#line 9504 "ext/date/lib/parse_date.c"
  yy352:
  	YYDEBUG(352, *YYCURSOR);
  	yyaccept = 2;
@@@ -10986,7 -11013,7 +11003,7 @@@ yy419
  	}
  yy420:
  	YYDEBUG(420, *YYCURSOR);
- #line 1405 "ext/date/lib/parse_date.re"
 -#line 1432 "ext/date/lib/parse_date.re"
++#line 1422 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("gnunocolon");
  		TIMELIB_INIT;
@@@ -11008,7 -11035,7 +11025,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_GNU_NOCOLON;
  	}
- #line 11012 "ext/date/lib/parse_date.c"
 -#line 11039 "ext/date/lib/parse_date.c"
++#line 11029 "ext/date/lib/parse_date.c"
  yy421:
  	YYDEBUG(421, *YYCURSOR);
  	yyaccept = 13;
@@@ -11089,7 -11116,7 +11106,7 @@@
  	}
  yy422:
  	YYDEBUG(422, *YYCURSOR);
- #line 1790 "ext/date/lib/parse_date.re"
 -#line 1817 "ext/date/lib/parse_date.re"
++#line 1807 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("year4");
  		TIMELIB_INIT;
@@@ -11097,7 -11124,7 +11114,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_CLF;
  	}
- #line 11101 "ext/date/lib/parse_date.c"
 -#line 11128 "ext/date/lib/parse_date.c"
++#line 11118 "ext/date/lib/parse_date.c"
  yy423:
  	YYDEBUG(423, *YYCURSOR);
  	yyaccept = 3;
@@@ -11704,7 -11731,7 +11721,7 @@@ yy456
  	YYDEBUG(456, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(457, *YYCURSOR);
- #line 1339 "ext/date/lib/parse_date.re"
 -#line 1366 "ext/date/lib/parse_date.re"
++#line 1356 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("timetiny12 | timeshort12 | timelong12");
  		TIMELIB_INIT;
@@@ -11721,7 -11748,7 +11738,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_TIME12;
  	}
- #line 11725 "ext/date/lib/parse_date.c"
 -#line 11752 "ext/date/lib/parse_date.c"
++#line 11742 "ext/date/lib/parse_date.c"
  yy458:
  	YYDEBUG(458, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -13048,7 -13075,7 +13065,7 @@@ yy525
  	}
  yy526:
  	YYDEBUG(526, *YYCURSOR);
- #line 1177 "ext/date/lib/parse_date.re"
 -#line 1204 "ext/date/lib/parse_date.re"
++#line 1194 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("noon");
  		TIMELIB_INIT;
@@@ -13059,7 -13086,7 +13076,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_RELATIVE;
  	}
- #line 13063 "ext/date/lib/parse_date.c"
 -#line 13090 "ext/date/lib/parse_date.c"
++#line 13080 "ext/date/lib/parse_date.c"
  yy527:
  	YYDEBUG(527, *YYCURSOR);
  	yyaccept = 2;
@@@ -14105,7 -14132,7 +14122,7 @@@ yy566
  	}
  yy567:
  	YYDEBUG(567, *YYCURSOR);
- #line 1539 "ext/date/lib/parse_date.re"
 -#line 1566 "ext/date/lib/parse_date.re"
++#line 1556 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("gnudateshort");
@@@ -14118,7 -14145,7 +14135,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_ISO_DATE;
  	}
- #line 14122 "ext/date/lib/parse_date.c"
 -#line 14149 "ext/date/lib/parse_date.c"
++#line 14139 "ext/date/lib/parse_date.c"
  yy568:
  	YYDEBUG(568, *YYCURSOR);
  	yyaccept = 15;
@@@ -14569,7 -14596,7 +14586,7 @@@ yy599
  	}
  yy600:
  	YYDEBUG(600, *YYCURSOR);
- #line 1608 "ext/date/lib/parse_date.re"
 -#line 1635 "ext/date/lib/parse_date.re"
++#line 1625 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("datenodayrev");
@@@ -14582,7 -14609,7 +14599,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_DATE_NO_DAY;
  	}
- #line 14586 "ext/date/lib/parse_date.c"
 -#line 14613 "ext/date/lib/parse_date.c"
++#line 14603 "ext/date/lib/parse_date.c"
  yy601:
  	YYDEBUG(601, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -15957,7 -15984,7 +15974,7 @@@ yy696
  	YYDEBUG(696, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(697, *YYCURSOR);
- #line 1594 "ext/date/lib/parse_date.re"
 -#line 1621 "ext/date/lib/parse_date.re"
++#line 1611 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("datenoday");
@@@ -15970,7 -15997,7 +15987,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_DATE_NO_DAY;
  	}
- #line 15974 "ext/date/lib/parse_date.c"
 -#line 16001 "ext/date/lib/parse_date.c"
++#line 15991 "ext/date/lib/parse_date.c"
  yy698:
  	YYDEBUG(698, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -16531,7 -16558,7 +16548,7 @@@ yy721
  	}
  yy722:
  	YYDEBUG(722, *YYCURSOR);
- #line 1189 "ext/date/lib/parse_date.re"
 -#line 1216 "ext/date/lib/parse_date.re"
++#line 1206 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("midnight | today");
  		TIMELIB_INIT;
@@@ -16540,7 -16567,7 +16557,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_RELATIVE;
  	}
- #line 16544 "ext/date/lib/parse_date.c"
 -#line 16571 "ext/date/lib/parse_date.c"
++#line 16561 "ext/date/lib/parse_date.c"
  yy723:
  	YYDEBUG(723, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -16850,7 -16877,7 +16867,7 @@@ yy738
  	if (yych <= '9') goto yy897;
  yy739:
  	YYDEBUG(739, *YYCURSOR);
- #line 1580 "ext/date/lib/parse_date.re"
 -#line 1607 "ext/date/lib/parse_date.re"
++#line 1597 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("pointed date YY");
@@@ -16863,7 -16890,7 +16880,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_DATE_FULL_POINTED;
  	}
- #line 16867 "ext/date/lib/parse_date.c"
 -#line 16894 "ext/date/lib/parse_date.c"
++#line 16884 "ext/date/lib/parse_date.c"
  yy740:
  	YYDEBUG(740, *YYCURSOR);
  	yyaccept = 15;
@@@ -16975,7 -17002,7 +16992,7 @@@ yy751
  	}
  yy752:
  	YYDEBUG(752, *YYCURSOR);
- #line 1525 "ext/date/lib/parse_date.re"
 -#line 1552 "ext/date/lib/parse_date.re"
++#line 1542 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("gnudateshorter");
@@@ -16988,7 -17015,7 +17005,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_ISO_DATE;
  	}
- #line 16992 "ext/date/lib/parse_date.c"
 -#line 17019 "ext/date/lib/parse_date.c"
++#line 17009 "ext/date/lib/parse_date.c"
  yy753:
  	YYDEBUG(753, *YYCURSOR);
  	yyaccept = 18;
@@@ -17237,7 -17264,7 +17254,7 @@@ yy776
  	}
  yy777:
  	YYDEBUG(777, *YYCURSOR);
- #line 1451 "ext/date/lib/parse_date.re"
 -#line 1478 "ext/date/lib/parse_date.re"
++#line 1468 "ext/date/lib/parse_date.re"
  	{
  		int tz_not_found;
  		DEBUG_OUTPUT("iso8601nocolon");
@@@ -17256,7 -17283,7 +17273,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_ISO_NOCOLON;
  	}
- #line 17260 "ext/date/lib/parse_date.c"
 -#line 17287 "ext/date/lib/parse_date.c"
++#line 17277 "ext/date/lib/parse_date.c"
  yy778:
  	YYDEBUG(778, *YYCURSOR);
  	yyaccept = 19;
@@@ -18484,7 -18511,7 +18501,7 @@@ yy848
  	}
  yy849:
  	YYDEBUG(849, *YYCURSOR);
- #line 1928 "ext/date/lib/parse_date.re"
 -#line 1955 "ext/date/lib/parse_date.re"
++#line 1945 "ext/date/lib/parse_date.re"
  	{
  		int tz_not_found;
  		DEBUG_OUTPUT("dateshortwithtimeshort | dateshortwithtimelong | dateshortwithtimelongtz");
@@@ -18513,7 -18540,7 +18530,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_SHORTDATE_WITH_TIME;
  	}
- #line 18517 "ext/date/lib/parse_date.c"
 -#line 18544 "ext/date/lib/parse_date.c"
++#line 18534 "ext/date/lib/parse_date.c"
  yy850:
  	YYDEBUG(850, *YYCURSOR);
  	yyaccept = 20;
@@@ -19557,7 -19584,7 +19574,7 @@@ yy925
  	}
  yy926:
  	YYDEBUG(926, *YYCURSOR);
- #line 1686 "ext/date/lib/parse_date.re"
 -#line 1713 "ext/date/lib/parse_date.re"
++#line 1703 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("pgydotd");
@@@ -19570,7 -19597,7 +19587,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_PG_YEARDAY;
  	}
- #line 19574 "ext/date/lib/parse_date.c"
 -#line 19601 "ext/date/lib/parse_date.c"
++#line 19591 "ext/date/lib/parse_date.c"
  yy927:
  	YYDEBUG(927, *YYCURSOR);
  	yyaccept = 21;
@@@ -19824,7 -19851,7 +19841,7 @@@ yy941
  	if (yych <= '7') goto yy1059;
  yy942:
  	YYDEBUG(942, *YYCURSOR);
- #line 1719 "ext/date/lib/parse_date.re"
 -#line 1746 "ext/date/lib/parse_date.re"
++#line 1736 "ext/date/lib/parse_date.re"
  	{
  		timelib_sll w, d;
  		DEBUG_OUTPUT("isoweek");
@@@ -19842,7 -19869,7 +19859,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_ISO_WEEK;
  	}
- #line 19846 "ext/date/lib/parse_date.c"
 -#line 19873 "ext/date/lib/parse_date.c"
++#line 19863 "ext/date/lib/parse_date.c"
  yy943:
  	YYDEBUG(943, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -20318,7 -20345,7 +20335,7 @@@ yy981
  	if (yych == 'e') goto yy1094;
  yy982:
  	YYDEBUG(982, *YYCURSOR);
- #line 1862 "ext/date/lib/parse_date.re"
 -#line 1889 "ext/date/lib/parse_date.re"
++#line 1879 "ext/date/lib/parse_date.re"
  	{
  		timelib_sll i;
  		int         behavior = 0;
@@@ -20334,7 -20361,7 +20351,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_RELATIVE;
  	}
- #line 20338 "ext/date/lib/parse_date.c"
 -#line 20365 "ext/date/lib/parse_date.c"
++#line 20355 "ext/date/lib/parse_date.c"
  yy983:
  	YYDEBUG(983, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -20681,7 -20708,7 +20698,7 @@@ yy1020
  	YYDEBUG(1020, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(1021, *YYCURSOR);
- #line 1568 "ext/date/lib/parse_date.re"
 -#line 1595 "ext/date/lib/parse_date.re"
++#line 1585 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("pointed date YYYY");
  		TIMELIB_INIT;
@@@ -20692,7 -20719,7 +20709,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_DATE_FULL_POINTED;
  	}
- #line 20696 "ext/date/lib/parse_date.c"
 -#line 20723 "ext/date/lib/parse_date.c"
++#line 20713 "ext/date/lib/parse_date.c"
  yy1022:
  	YYDEBUG(1022, *YYCURSOR);
  	++YYCURSOR;
@@@ -20721,7 -20748,7 +20738,7 @@@ yy1024
  	}
  yy1025:
  	YYDEBUG(1025, *YYCURSOR);
- #line 1499 "ext/date/lib/parse_date.re"
 -#line 1526 "ext/date/lib/parse_date.re"
++#line 1516 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("iso8601date2");
@@@ -20734,7 -20761,7 +20751,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_ISO_DATE;
  	}
- #line 20738 "ext/date/lib/parse_date.c"
 -#line 20765 "ext/date/lib/parse_date.c"
++#line 20755 "ext/date/lib/parse_date.c"
  yy1026:
  	YYDEBUG(1026, *YYCURSOR);
  	yyaccept = 15;
@@@ -20954,7 -20981,7 +20971,7 @@@ yy1042
  	}
  yy1043:
  	YYDEBUG(1043, *YYCURSOR);
- #line 1487 "ext/date/lib/parse_date.re"
 -#line 1514 "ext/date/lib/parse_date.re"
++#line 1504 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("iso8601date4 | iso8601date2 | iso8601dateslash | dateslash");
  		TIMELIB_INIT;
@@@ -20965,7 -20992,7 +20982,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_ISO_DATE;
  	}
- #line 20969 "ext/date/lib/parse_date.c"
 -#line 20996 "ext/date/lib/parse_date.c"
++#line 20986 "ext/date/lib/parse_date.c"
  yy1044:
  	YYDEBUG(1044, *YYCURSOR);
  	yyaccept = 26;
@@@ -21080,7 -21107,7 +21097,7 @@@ yy1047
  	}
  yy1048:
  	YYDEBUG(1048, *YYCURSOR);
- #line 1648 "ext/date/lib/parse_date.re"
 -#line 1675 "ext/date/lib/parse_date.re"
++#line 1665 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("datenocolon");
  		TIMELIB_INIT;
@@@ -21091,7 -21118,7 +21108,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_DATE_NOCOLON;
  	}
- #line 21095 "ext/date/lib/parse_date.c"
 -#line 21122 "ext/date/lib/parse_date.c"
++#line 21112 "ext/date/lib/parse_date.c"
  yy1049:
  	YYDEBUG(1049, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -21161,7 -21188,7 +21178,7 @@@ yy1059
  	YYDEBUG(1059, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(1060, *YYCURSOR);
- #line 1700 "ext/date/lib/parse_date.re"
 -#line 1727 "ext/date/lib/parse_date.re"
++#line 1717 "ext/date/lib/parse_date.re"
  	{
  		timelib_sll w, d;
  		DEBUG_OUTPUT("isoweekday");
@@@ -21179,7 -21206,7 +21196,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_ISO_WEEK;
  	}
- #line 21183 "ext/date/lib/parse_date.c"
 -#line 21210 "ext/date/lib/parse_date.c"
++#line 21200 "ext/date/lib/parse_date.c"
  yy1061:
  	YYDEBUG(1061, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -21242,7 -21269,7 +21259,7 @@@ yy1069
  	if (yych <= '9') goto yy1143;
  yy1070:
  	YYDEBUG(1070, *YYCURSOR);
- #line 1738 "ext/date/lib/parse_date.re"
 -#line 1765 "ext/date/lib/parse_date.re"
++#line 1755 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("pgtextshort");
@@@ -21255,7 -21282,7 +21272,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_PG_TEXT;
  	}
- #line 21259 "ext/date/lib/parse_date.c"
 -#line 21286 "ext/date/lib/parse_date.c"
++#line 21276 "ext/date/lib/parse_date.c"
  yy1071:
  	YYDEBUG(1071, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -21728,7 -21755,7 +21745,7 @@@ yy1106
  	++YYCURSOR;
  yy1107:
  	YYDEBUG(1107, *YYCURSOR);
- #line 1199 "ext/date/lib/parse_date.re"
 -#line 1226 "ext/date/lib/parse_date.re"
++#line 1216 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("tomorrow");
  		TIMELIB_INIT;
@@@ -21739,7 -21766,7 +21756,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_RELATIVE;
  	}
- #line 21743 "ext/date/lib/parse_date.c"
 -#line 21770 "ext/date/lib/parse_date.c"
++#line 21760 "ext/date/lib/parse_date.c"
  yy1108:
  	YYDEBUG(1108, *YYCURSOR);
  	yyaccept = 28;
@@@ -22076,7 -22103,7 +22093,7 @@@ yy1140
  	YYDEBUG(1140, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(1141, *YYCURSOR);
- #line 1752 "ext/date/lib/parse_date.re"
 -#line 1779 "ext/date/lib/parse_date.re"
++#line 1769 "ext/date/lib/parse_date.re"
  	{
  		int length = 0;
  		DEBUG_OUTPUT("pgtextreverse");
@@@ -22089,7 -22116,7 +22106,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_PG_TEXT;
  	}
- #line 22093 "ext/date/lib/parse_date.c"
 -#line 22120 "ext/date/lib/parse_date.c"
++#line 22110 "ext/date/lib/parse_date.c"
  yy1142:
  	YYDEBUG(1142, *YYCURSOR);
  	++YYCURSOR;
@@@ -22133,7 -22160,7 +22150,7 @@@ yy1144
  	}
  yy1145:
  	YYDEBUG(1145, *YYCURSOR);
- #line 1294 "ext/date/lib/parse_date.re"
 -#line 1321 "ext/date/lib/parse_date.re"
++#line 1311 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("backof | frontof");
  		TIMELIB_INIT;
@@@ -22155,7 -22182,7 +22172,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_LF_DAY_OF_MONTH;
  	}
- #line 22159 "ext/date/lib/parse_date.c"
 -#line 22186 "ext/date/lib/parse_date.c"
++#line 22176 "ext/date/lib/parse_date.c"
  yy1146:
  	YYDEBUG(1146, *YYCURSOR);
  	yyaccept = 29;
@@@ -22479,7 -22506,7 +22496,7 @@@ yy1171
  	}
  yy1172:
  	YYDEBUG(1172, *YYCURSOR);
- #line 1838 "ext/date/lib/parse_date.re"
 -#line 1865 "ext/date/lib/parse_date.re"
++#line 1855 "ext/date/lib/parse_date.re"
  	{
  		timelib_sll i;
  		int         behavior = 0;
@@@ -22502,7 -22529,7 +22519,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_RELATIVE;
  	}
- #line 22506 "ext/date/lib/parse_date.c"
 -#line 22533 "ext/date/lib/parse_date.c"
++#line 22523 "ext/date/lib/parse_date.c"
  yy1173:
  	YYDEBUG(1173, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -22514,7 -22541,7 +22531,7 @@@ yy1174
  	++YYCURSOR;
  yy1175:
  	YYDEBUG(1175, *YYCURSOR);
- #line 1156 "ext/date/lib/parse_date.re"
 -#line 1183 "ext/date/lib/parse_date.re"
++#line 1173 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("yesterday");
  		TIMELIB_INIT;
@@@ -22525,7 -22552,7 +22542,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_RELATIVE;
  	}
- #line 22529 "ext/date/lib/parse_date.c"
 -#line 22556 "ext/date/lib/parse_date.c"
++#line 22546 "ext/date/lib/parse_date.c"
  yy1176:
  	YYDEBUG(1176, *YYCURSOR);
  	yyaccept = 31;
@@@ -23018,7 -23045,7 +23035,7 @@@ yy1222
  	YYDEBUG(1222, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(1223, *YYCURSOR);
- #line 1904 "ext/date/lib/parse_date.re"
 -#line 1931 "ext/date/lib/parse_date.re"
++#line 1921 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("dateshortwithtimeshort12 | dateshortwithtimelong12");
  		TIMELIB_INIT;
@@@ -23041,7 -23068,7 +23058,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_SHORTDATE_WITH_TIME;
  	}
- #line 23045 "ext/date/lib/parse_date.c"
 -#line 23072 "ext/date/lib/parse_date.c"
++#line 23062 "ext/date/lib/parse_date.c"
  yy1224:
  	YYDEBUG(1224, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -23543,7 -23570,7 +23560,7 @@@ yy1268
  	YYDEBUG(1268, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(1269, *YYCURSOR);
- #line 1317 "ext/date/lib/parse_date.re"
 -#line 1344 "ext/date/lib/parse_date.re"
++#line 1334 "ext/date/lib/parse_date.re"
  	{
  		timelib_sll i;
  		int         behavior = 0;
@@@ -23564,7 -23591,7 +23581,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_WEEK_DAY_OF_MONTH;
  	}
- #line 23568 "ext/date/lib/parse_date.c"
 -#line 23595 "ext/date/lib/parse_date.c"
++#line 23585 "ext/date/lib/parse_date.c"
  yy1270:
  	YYDEBUG(1270, *YYCURSOR);
  	yyaccept = 24;
@@@ -23611,7 -23638,7 +23628,7 @@@ yy1273
  	YYDEBUG(1273, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(1274, *YYCURSOR);
- #line 1277 "ext/date/lib/parse_date.re"
 -#line 1304 "ext/date/lib/parse_date.re"
++#line 1294 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("firstdayof | lastdayof");
  		TIMELIB_INIT;
@@@ -23627,12 -23654,12 +23644,12 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_LF_DAY_OF_MONTH;
  	}
- #line 23631 "ext/date/lib/parse_date.c"
 -#line 23658 "ext/date/lib/parse_date.c"
++#line 23648 "ext/date/lib/parse_date.c"
  yy1275:
  	YYDEBUG(1275, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(1276, *YYCURSOR);
- #line 1513 "ext/date/lib/parse_date.re"
 -#line 1540 "ext/date/lib/parse_date.re"
++#line 1530 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("iso8601datex");
  		TIMELIB_INIT;
@@@ -23643,7 -23670,7 +23660,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_ISO_DATE;
  	}
- #line 23647 "ext/date/lib/parse_date.c"
 -#line 23674 "ext/date/lib/parse_date.c"
++#line 23664 "ext/date/lib/parse_date.c"
  yy1277:
  	YYDEBUG(1277, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -23746,7 -23773,7 +23763,7 @@@ yy1290
  	YYDEBUG(1290, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(1291, *YYCURSOR);
- #line 1357 "ext/date/lib/parse_date.re"
 -#line 1384 "ext/date/lib/parse_date.re"
++#line 1374 "ext/date/lib/parse_date.re"
  	{
  		DEBUG_OUTPUT("mssqltime");
  		TIMELIB_INIT;
@@@ -23765,7 -23792,7 +23782,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_TIME24_WITH_ZONE;
  	}
- #line 23769 "ext/date/lib/parse_date.c"
 -#line 23796 "ext/date/lib/parse_date.c"
++#line 23786 "ext/date/lib/parse_date.c"
  yy1292:
  	YYDEBUG(1292, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -24189,7 -24216,7 +24206,7 @@@ yy1328
  	if (yych <= '9') goto yy1331;
  yy1329:
  	YYDEBUG(1329, *YYCURSOR);
- #line 1660 "ext/date/lib/parse_date.re"
 -#line 1687 "ext/date/lib/parse_date.re"
++#line 1677 "ext/date/lib/parse_date.re"
  	{
  		int tz_not_found;
  		DEBUG_OUTPUT("xmlrpc | xmlrpcnocolon | soap | wddx | exif");
@@@ -24214,7 -24241,7 +24231,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_XMLRPC_SOAP;
  	}
- #line 24218 "ext/date/lib/parse_date.c"
 -#line 24245 "ext/date/lib/parse_date.c"
++#line 24235 "ext/date/lib/parse_date.c"
  yy1330:
  	YYDEBUG(1330, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -24584,7 -24611,7 +24601,7 @@@ yy1374
  	if (yych <= ':') goto yy1383;
  yy1375:
  	YYDEBUG(1375, *YYCURSOR);
- #line 1766 "ext/date/lib/parse_date.re"
 -#line 1793 "ext/date/lib/parse_date.re"
++#line 1783 "ext/date/lib/parse_date.re"
  	{
  		int tz_not_found;
  		DEBUG_OUTPUT("clf");
@@@ -24607,7 -24634,7 +24624,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_CLF;
  	}
- #line 24611 "ext/date/lib/parse_date.c"
 -#line 24638 "ext/date/lib/parse_date.c"
++#line 24628 "ext/date/lib/parse_date.c"
  yy1376:
  	YYDEBUG(1376, *YYCURSOR);
  	yyaccept = 33;
@@@ -24839,7 -24866,7 +24856,7 @@@ yy1406
  	if (yych == ':') goto yy1286;
  	goto yy1329;
  }
- #line 1994 "ext/date/lib/parse_date.re"
 -#line 2021 "ext/date/lib/parse_date.re"
++#line 2011 "ext/date/lib/parse_date.re"

  }

diff --cc ext/date/lib/parse_iso_intervals.c
index 8f9221e6aa0,aef0838909b..0ae4888caac
--- a/ext/date/lib/parse_iso_intervals.c
+++ b/ext/date/lib/parse_iso_intervals.c
@@@ -1,4 -1,4 +1,4 @@@
- /* Generated by re2c 1.0.3 on Wed Aug  5 11:34:39 2026 */
 -/* Generated by re2c 1.0.3 on Thu Oct  1 14:55:09 2026 */
++/* Generated by re2c 1.0.3 on Thu Oct  1 17:09:40 2026 */
  #line 1 "ext/date/lib/parse_iso_intervals.re"
  /*
   * The MIT License (MIT)
@@@ -166,11 -181,11 +171,11 @@@ static int scan(Scanner *s
  std:
  	s->tok = cursor;
  	s->len = 0;
- #line 194 "ext/date/lib/parse_iso_intervals.re"
 -#line 209 "ext/date/lib/parse_iso_intervals.re"
++#line 199 "ext/date/lib/parse_iso_intervals.re"



- #line 174 "ext/date/lib/parse_iso_intervals.c"
 -#line 189 "ext/date/lib/parse_iso_intervals.c"
++#line 179 "ext/date/lib/parse_iso_intervals.c"
  {
  	YYCTYPE yych;
  	unsigned int yyaccept = 0;
@@@ -237,32 -252,32 +242,32 @@@ yy2
  	YYDEBUG(2, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(3, *YYCURSOR);
- #line 301 "ext/date/lib/parse_iso_intervals.re"
 -#line 316 "ext/date/lib/parse_iso_intervals.re"
++#line 306 "ext/date/lib/parse_iso_intervals.re"
  	{
  		s->pos = cursor; s->line++;
  		goto std;
  	}
- #line 246 "ext/date/lib/parse_iso_intervals.c"
 -#line 261 "ext/date/lib/parse_iso_intervals.c"
++#line 251 "ext/date/lib/parse_iso_intervals.c"
  yy4:
  	YYDEBUG(4, *YYCURSOR);
  	++YYCURSOR;
  yy5:
  	YYDEBUG(5, *YYCURSOR);
- #line 307 "ext/date/lib/parse_iso_intervals.re"
 -#line 322 "ext/date/lib/parse_iso_intervals.re"
++#line 312 "ext/date/lib/parse_iso_intervals.re"
  	{
  		add_error(s, "Unexpected character");
  		goto std;
  	}
- #line 257 "ext/date/lib/parse_iso_intervals.c"
 -#line 272 "ext/date/lib/parse_iso_intervals.c"
++#line 262 "ext/date/lib/parse_iso_intervals.c"
  yy6:
  	YYDEBUG(6, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(7, *YYCURSOR);
- #line 296 "ext/date/lib/parse_iso_intervals.re"
 -#line 311 "ext/date/lib/parse_iso_intervals.re"
++#line 301 "ext/date/lib/parse_iso_intervals.re"
  	{
  		goto std;
  	}
- #line 266 "ext/date/lib/parse_iso_intervals.c"
 -#line 281 "ext/date/lib/parse_iso_intervals.c"
++#line 271 "ext/date/lib/parse_iso_intervals.c"
  yy8:
  	YYDEBUG(8, *YYCURSOR);
  	yyaccept = 0;
@@@ -279,7 -294,7 +284,7 @@@ yy9
  	if (yych == 'T') goto yy15;
  yy10:
  	YYDEBUG(10, *YYCURSOR);
- #line 234 "ext/date/lib/parse_iso_intervals.re"
 -#line 249 "ext/date/lib/parse_iso_intervals.re"
++#line 239 "ext/date/lib/parse_iso_intervals.re"
  	{
  		timelib_sll nr;
  		int         in_time = 0;
@@@ -320,7 -335,7 +325,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_PERIOD;
  	}
- #line 324 "ext/date/lib/parse_iso_intervals.c"
 -#line 339 "ext/date/lib/parse_iso_intervals.c"
++#line 329 "ext/date/lib/parse_iso_intervals.c"
  yy11:
  	YYDEBUG(11, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -379,7 -394,7 +384,7 @@@ yy16
  		goto yy16;
  	}
  	YYDEBUG(18, *YYCURSOR);
- #line 199 "ext/date/lib/parse_iso_intervals.re"
 -#line 214 "ext/date/lib/parse_iso_intervals.re"
++#line 204 "ext/date/lib/parse_iso_intervals.re"
  	{
  		DEBUG_OUTPUT("recurrences");
  		TIMELIB_INIT;
@@@ -389,7 -404,7 +394,7 @@@
  		s->have_recurrences = 1;
  		return TIMELIB_PERIOD;
  	}
- #line 393 "ext/date/lib/parse_iso_intervals.c"
 -#line 408 "ext/date/lib/parse_iso_intervals.c"
++#line 398 "ext/date/lib/parse_iso_intervals.c"
  yy19:
  	YYDEBUG(19, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -884,7 -899,7 +889,7 @@@ yy89
  	YYDEBUG(89, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(90, *YYCURSOR);
- #line 210 "ext/date/lib/parse_iso_intervals.re"
 -#line 225 "ext/date/lib/parse_iso_intervals.re"
++#line 215 "ext/date/lib/parse_iso_intervals.re"
  	{
  		timelib_time *current;

@@@ -907,7 -922,7 +912,7 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_ISO_DATE;
  	}
- #line 911 "ext/date/lib/parse_iso_intervals.c"
 -#line 926 "ext/date/lib/parse_iso_intervals.c"
++#line 916 "ext/date/lib/parse_iso_intervals.c"
  yy91:
  	YYDEBUG(91, *YYCURSOR);
  	yych = *++YYCURSOR;
@@@ -927,7 -942,7 +932,7 @@@
  	YYDEBUG(95, *YYCURSOR);
  	++YYCURSOR;
  	YYDEBUG(96, *YYCURSOR);
- #line 276 "ext/date/lib/parse_iso_intervals.re"
 -#line 291 "ext/date/lib/parse_iso_intervals.re"
++#line 281 "ext/date/lib/parse_iso_intervals.re"
  	{
  		DEBUG_OUTPUT("combinedrep");
  		TIMELIB_INIT;
@@@ -946,9 -961,9 +951,9 @@@
  		TIMELIB_DEINIT;
  		return TIMELIB_PERIOD;
  	}
- #line 950 "ext/date/lib/parse_iso_intervals.c"
 -#line 965 "ext/date/lib/parse_iso_intervals.c"
++#line 955 "ext/date/lib/parse_iso_intervals.c"
  }
- #line 311 "ext/date/lib/parse_iso_intervals.re"
 -#line 326 "ext/date/lib/parse_iso_intervals.re"
++#line 316 "ext/date/lib/parse_iso_intervals.re"

  }
  #ifdef PHP_WIN32
diff --cc ext/exif/exif.c
index 503cf3609e8,b63c29751e5..9d62c3e7611
--- a/ext/exif/exif.c
+++ b/ext/exif/exif.c
@@@ -4938,8 -4944,15 +4999,15 @@@ PHP_FUNCTION(exif_read_data
  	exif_discard_imageinfo(&ImageInfo);

  #ifdef EXIF_DEBUG
 -	php_error_docref1(NULL, (Z_TYPE_P(stream) == IS_RESOURCE ? "<stream>" : Z_STRVAL_P(stream)), E_NOTICE, "Done");
 +	php_error_docref(NULL, E_NOTICE, "Done");
  #endif
+ 	return;
+
+ oom:
+ 	exif_discard_imageinfo(&ImageInfo);
+ 	zval_ptr_dtor(return_value);
+ 	ZVAL_NULL(return_value);
+ 	RETURN_OOM();
  }
  /* }}} */

diff --cc ext/exif/tests/oom_exif_thumbnail_tiff.phpt
index 00000000000,a074e7c1283..77970a20f6e
mode 000000,100644..100644
--- a/ext/exif/tests/oom_exif_thumbnail_tiff.phpt
+++ b/ext/exif/tests/oom_exif_thumbnail_tiff.phpt
@@@ -1,0 -1,32 +1,32 @@@
+ --TEST--
+ exif_thumbnail() rejects a TIFF thumbnail that is not present in the file
+ --EXTENSIONS--
+ exif
+ --INI--
+ memory_limit=128M
+ --FILE--
+ <?php
+ // 68 byte TIFF whose thumbnail IFD claims a 4 GiB StripByteCounts.
+ $ifd1_off = 8 + 2 + 2*12 + 4;
+ $t  = "II*\x00" . pack("V", 8);
+ $t .= pack("v", 2);
+ $t .= pack("vvVV", 0x0100, 4, 1, 1);          // ImageWidth
+ $t .= pack("vvVV", 0x0101, 4, 1, 1);          // ImageLength
+ $t .= pack("V", $ifd1_off);                   // next IFD = thumbnail IFD
+ $t .= pack("v", 2);
+ $t .= pack("vvVV", 0x0111, 4, 1, 1);          // StripOffsets
+ $t .= pack("vvVV", 0x0117, 4, 1, -1);         // StripByteCounts = 4 GiB
+ $t .= pack("V", 0);
+
+ $file = __DIR__ . '/oom_exif_thumbnail_tiff.tif';
+ file_put_contents($file, $t);
+
+ var_dump(exif_thumbnail($file));
+ ?>
+ --CLEAN--
+ <?php
+ @unlink(__DIR__ . '/oom_exif_thumbnail_tiff.tif');
+ ?>
+ --EXPECTF--
 -Warning: exif_thumbnail(%s): Thumbnail goes IFD boundary or end of file reached in %s on line %d
++Warning: exif_thumbnail(): Thumbnail goes IFD boundary or end of file reached in %s on line %d
+ bool(false)
diff --cc ext/fileinfo/libmagic.patch
index 0855f9937d3,041562d48a9..01c3610db57
--- a/ext/fileinfo/libmagic.patch
+++ b/ext/fileinfo/libmagic.patch
@@@ -1026,9 -1055,9 +1026,9 @@@ diff -u libmagic.orig/buffer.c libmagic
   		goto out;
   	}
  diff -u libmagic.orig/cdf.c libmagic/cdf.c
- --- libmagic.orig/cdf.c	2026-09-16 14:46:34.432258300 +0800
- +++ libmagic/cdf.c	2026-09-16 14:46:34.444782700 +0800
 ---- libmagic.orig/cdf.c	2024-11-25 22:24:59.000000000 +0100
 -+++ libmagic/cdf.c	2026-10-02 19:35:44.175918710 +0200
 -@@ -43,7 +43,9 @@
++--- libmagic.orig/cdf.c	2026-06-08 00:41:27.000000000 +0200
+++++ libmagic/cdf.c	2026-10-02 19:36:22.169786296 +0200
 +@@ -42,7 +42,9 @@
   #include <err.h>
   #endif
   #include <stdlib.h>
@@@ -1038,16 -1067,12 +1038,12 @@@
   #include <string.h>
   #include <time.h>
   #include <ctype.h>
- @@ -90,44 +92,9 @@
-  			    CDF_TOLE8(CAST(uint64_t, x))))
-  #define CDF_GETUINT32(x, y)	cdf_getuint32(x, y)
 -@@ -95,39 +97,39 @@
++@@ -94,39 +96,39 @@
+  #define CDF_REALLOC(p, n) cdf_realloc(__FILE__, __LINE__, (p), (n))
+  #define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u))

- -#define CDF_MALLOC(n) cdf_malloc(__FILE__, __LINE__, (n))
- -#define CDF_REALLOC(p, n) cdf_realloc(__FILE__, __LINE__, (p), (n))
- -#define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u))
  -
- -
- -/*ARGSUSED*/
+  /*ARGSUSED*/
  -file_private void *
  -cdf_malloc(const char *file __attribute__((__unused__)),
  -    size_t line __attribute__((__unused__)), size_t n)
@@@ -1079,14 -1115,16 +1086,16 @@@
  -	if (n == 0)
  -	    n++;
  -	return calloc(n, u);
- -}
- +#define CDF_MALLOC(n) emalloc(n)
- +#define CDF_REALLOC(p, n) erealloc(p, n)
- +#define CDF_CALLOC(n, u) ecalloc(n, u)
+ +	void *data = safe_femalloc(n, u, 0, /* fallible */ true);
+ +	if (!data) {
+ +		return NULL;
+ +	}
+ +	memset(data, 0, n * u);
+ +	return data;
+  }

   #if defined(HAVE_BYTESWAP_H)
-  # define _cdf_tole2(x)	bswap_16(x)
- @@ -333,7 +300,7 @@
 -@@ -334,7 +336,7 @@
++@@ -333,7 +335,7 @@
   	scn->sst_len = 0;
   	scn->sst_dirlen = 0;
   	scn->sst_ss = 0;
@@@ -1095,7 -1133,7 +1104,7 @@@
   	scn->sst_tab = NULL;
   	return -1;
   }
- @@ -341,9 +308,11 @@
 -@@ -342,9 +344,11 @@
++@@ -341,9 +343,11 @@
   file_private size_t
   cdf_check_stream(const cdf_stream_t *sst, const cdf_header_t *h)
   {
@@@ -1107,7 -1145,7 +1116,7 @@@
   	return sst->sst_ss;
   }

- @@ -366,11 +335,11 @@
 -@@ -367,11 +371,11 @@
++@@ -366,11 +370,11 @@
   }

   file_private ssize_t
@@@ -1121,7 -1159,7 +1130,7 @@@
   		goto out;

   	if (info->i_buf != NULL && info->i_len >= siz) {
- @@ -381,7 +350,10 @@
 -@@ -382,7 +386,10 @@
++@@ -381,7 +385,10 @@
   	if (info->i_fd == -1)
   		goto out;

@@@ -1133,7 -1171,7 +1142,7 @@@
   		return -1;

   	return CAST(ssize_t, len);
- @@ -396,7 +368,7 @@
 -@@ -397,7 +404,7 @@
++@@ -396,7 +403,7 @@
   	char buf[512];

   	(void)memcpy(cdf_bo.s, "\01\02\03\04", 4);
@@@ -1142,7 -1180,7 +1151,7 @@@
   		return -1;
   	cdf_unpack_header(h, buf);
   	cdf_swap_header(h);
- @@ -548,14 +520,14 @@
 -@@ -544,14 +551,14 @@
++@@ -548,14 +555,14 @@
   	}
   out:
   	sat->sat_len = i;
@@@ -1160,7 -1198,7 +1169,7 @@@
   	return -1;
   }

- @@ -723,7 +695,7 @@
 -@@ -719,7 +726,7 @@
++@@ -723,7 +730,7 @@
   		return -1;

   	if ((buf = CAST(char *, CDF_MALLOC(ss))) == NULL) {
@@@ -1169,7 -1207,7 +1178,7 @@@
   		return -1;
   	}

- @@ -746,11 +718,11 @@
 -@@ -742,11 +749,11 @@
++@@ -746,11 +753,11 @@
   	if (NEED_SWAP)
   		for (i = 0; i < dir->dir_len; i++)
   			cdf_swap_dir(&dir->dir_tab[i]);
@@@ -1184,7 -1222,7 +1193,7 @@@
   	errno = EFTYPE;
   	return -1;
   }
- @@ -795,7 +767,7 @@
 -@@ -791,7 +798,7 @@
++@@ -795,7 +802,7 @@
   out:
   	errno = EFTYPE;
   out1:
@@@ -1193,7 -1231,7 +1202,7 @@@
   	return -1;
   }

- @@ -957,7 +929,7 @@
 -@@ -953,7 +960,7 @@
++@@ -957,7 +964,7 @@
   	*maxcount = newcount;
   	return inp;
   out:
@@@ -1202,7 -1240,7 +1211,7 @@@
   	*maxcount = 0;
   	*info = NULL;
   	return NULL;
- @@ -1140,7 +1112,7 @@
 -@@ -1136,7 +1143,7 @@
++@@ -1140,7 +1147,7 @@
   	}
   	return 0;
   out:
@@@ -1211,7 -1249,7 +1220,7 @@@
   	*info = NULL;
   	*count = 0;
   	*maxcount = 0;
- @@ -1434,7 +1406,7 @@
 -@@ -1428,7 +1435,7 @@
++@@ -1434,7 +1441,7 @@
   	cdf_directory_t *d;
   	char name[__arraycount(d->d_name)];
   	cdf_stream_t scn;
@@@ -1220,7 -1258,7 +1229,7 @@@

   	static const char *types[] = { "empty", "user storage",
   	    "user stream", "lockbytes", "property", "root storage" };
- @@ -1476,7 +1448,7 @@
 -@@ -1470,7 +1477,7 @@
++@@ -1476,7 +1483,7 @@
   				break;
   			}
   			cdf_dump_stream(&scn);
@@@ -1229,7 -1267,7 +1238,7 @@@
   			break;
   		default:
   			break;
- @@ -1489,7 +1461,7 @@
 -@@ -1483,7 +1490,7 @@
++@@ -1489,7 +1496,7 @@
   cdf_dump_property_info(const cdf_property_info_t *info, size_t count)
   {
   	cdf_timestamp_t tp;
@@@ -1238,7 -1276,7 +1247,7 @@@
   	char buf[64];
   	size_t i, j;

- @@ -1574,7 +1546,7 @@
 -@@ -1568,7 +1575,7 @@
++@@ -1574,7 +1581,7 @@
   	(void)fprintf(stderr, "Class %s\n", buf);
   	(void)fprintf(stderr, "Count %d\n", ssi.si_count);
   	cdf_dump_property_info(info, count);
@@@ -1247,7 -1285,7 +1256,7 @@@
   }


- @@ -1595,7 +1567,7 @@
 -@@ -1589,7 +1596,7 @@
++@@ -1595,7 +1602,7 @@
   		    cdf_u16tos8(sbuf, ce[i].ce_namlen, ce[i].ce_name),
   		    cdf_ctime(&ts.tv_sec, tbuf));
   	}
diff --cc ext/gd/libgd/gd.c
index ccdf95a0a2a,b088aadc840..ede87f24aec
--- a/ext/gd/libgd/gd.c
+++ b/ext/gd/libgd/gd.c
@@@ -4054,474 -3069,207 +4054,475 @@@ BGD_DECLARE(int) gdAlphaBlend(int dst,
      dst_weight = (gdAlphaTransparent - dst_alpha) * src_alpha / gdAlphaMax;
      tot_weight = src_weight + dst_weight;

 -/* -------------------------------------------------------------------- */
 -/*      What red, green and blue result values will we use?             */
 -/* -------------------------------------------------------------------- */
 +    /* -------------------------------------------------------------------- */
 +    /*      What red, green and blue result values will we use?             */
 +    /* -------------------------------------------------------------------- */
      alpha = src_alpha * dst_alpha / gdAlphaMax;

 -    red = (gdTrueColorGetRed(src) * src_weight
 -           + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
 -    green = (gdTrueColorGetGreen(src) * src_weight
 -           + gdTrueColorGetGreen(dst) * dst_weight) / tot_weight;
 -    blue = (gdTrueColorGetBlue(src) * src_weight
 -           + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;
 +    red = (gdTrueColorGetRed(src) * src_weight + gdTrueColorGetRed(dst) * dst_weight) / tot_weight;
 +    green = (gdTrueColorGetGreen(src) * src_weight + gdTrueColorGetGreen(dst) * dst_weight) /
 +            tot_weight;
 +    blue =
 +        (gdTrueColorGetBlue(src) * src_weight + gdTrueColorGetBlue(dst) * dst_weight) / tot_weight;

 -/* -------------------------------------------------------------------- */
 -/*      Return merged result.                                           */
 -/* -------------------------------------------------------------------- */
 +    /* -------------------------------------------------------------------- */
 +    /*      Return merged result.                                           */
 +    /* -------------------------------------------------------------------- */
      return ((alpha << 24) + (red << 16) + (green << 8) + blue);
 +#endif
 +}
 +
 +#if !ENABLE_CORRECTED_LEGACY_COMPOSITING
 +static int gdAlphaOverlayColor(int src, int dst, int max);
 +#endif
 +
 +/**
 + * Function: gdLayerOverlay
 + *
 + * Overlay two colors
 + *
 + * Parameters:
 + *   dst - The color to overlay onto.
 + *   src - The color to overlay.
 + *
 + * See also:
 + *   - <gdImageAlphaBlending>
 + *   - <gdAlphaBlend>
 + *   - <gdLayerMultiply>
 + */
 +BGD_DECLARE(int) gdLayerOverlay(int dst, int src)
 +{
 +#if ENABLE_CORRECTED_LEGACY_COMPOSITING
 +    return gdCompositePixelToGd(gdCompositePixel(GD_OP_OVERLAY, gdCompositePixelFromGd(src),
 +                                                 gdCompositePixelFromGd(dst), 1.0f));
 +#else
 +    int a1, a2;
 +    a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
 +    a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
 +    return (
 +        ((gdAlphaMax - a1 * a2 / gdAlphaMax) << 24) +
 +        (gdAlphaOverlayColor(gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax) << 16) +
 +        (gdAlphaOverlayColor(gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax) << 8) +
 +        (gdAlphaOverlayColor(gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax)));
 +#endif
 +}
 +
 +/* Apply 'overlay' effect - background pixels are colourised by the foreground
 + * colour */
 +#if !ENABLE_CORRECTED_LEGACY_COMPOSITING
 +static int gdAlphaOverlayColor(int src, int dst, int max)
 +{
 +    dst = dst << 1;
 +    if (dst > max) {
 +        /* in the "light" zone */
 +        return dst + (src << 1) - (dst * src / max) - max;
 +    } else {
 +        /* in the "dark" zone */
 +        return dst * src / max;
 +    }
 +}
 +#endif
 +
 +/**
 + * Function: gdLayerMultiply
 + *
 + * Overlay two colors with multiply effect
 + *
 + * Parameters:
 + *   dst - The color to overlay onto.
 + *   src - The color to overlay.
 + *
 + * See also:
 + *   - <gdImageAlphaBlending>
 + *   - <gdAlphaBlend>
 + *   - <gdLayerOverlay>
 + */
 +BGD_DECLARE(int) gdLayerMultiply(int dst, int src)
 +{
 +#if ENABLE_CORRECTED_LEGACY_COMPOSITING
 +    return gdCompositePixelToGd(gdCompositePixel(GD_OP_MULTIPLY, gdCompositePixelFromGd(src),
 +                                                 gdCompositePixelFromGd(dst), 1.0f));
 +#else
 +    int a1, a2, r1, r2, g1, g2, b1, b2;
 +    a1 = gdAlphaMax - gdTrueColorGetAlpha(src);
 +    a2 = gdAlphaMax - gdTrueColorGetAlpha(dst);
 +
 +    r1 = gdRedMax - (a1 * (gdRedMax - gdTrueColorGetRed(src))) / gdAlphaMax;
 +    r2 = gdRedMax - (a2 * (gdRedMax - gdTrueColorGetRed(dst))) / gdAlphaMax;
 +    g1 = gdGreenMax - (a1 * (gdGreenMax - gdTrueColorGetGreen(src))) / gdAlphaMax;
 +    g2 = gdGreenMax - (a2 * (gdGreenMax - gdTrueColorGetGreen(dst))) / gdAlphaMax;
 +    b1 = gdBlueMax - (a1 * (gdBlueMax - gdTrueColorGetBlue(src))) / gdAlphaMax;
 +    b2 = gdBlueMax - (a2 * (gdBlueMax - gdTrueColorGetBlue(dst))) / gdAlphaMax;
 +
 +    a1 = gdAlphaMax - a1;
 +    a2 = gdAlphaMax - a2;
 +    return (((a1 * a2 / gdAlphaMax) << 24) + ((r1 * r2 / gdRedMax) << 16) +
 +            ((g1 * g2 / gdGreenMax) << 8) + ((b1 * b2 / gdBlueMax)));
 +#endif
 +}
 +
 +/**
 + *	Function: gdImageAlphaBlending
 + *
 + *	Set the effect for subsequent drawing operations
 + *
 + *	Note that the effect is used for truecolor images only.
 + *
 + * Parameters:
 + *   im               - The image.
 + *   alphaBlendingArg - The effect.
 + *
 + * See also:
 + *   - <Effects>
 + */
 +BGD_DECLARE(void) gdImageAlphaBlending(gdImagePtr im, int alphaBlendingArg)
 +{
 +    im->alphaBlendingFlag = alphaBlendingArg;
 +}
 +
 +/**
 + * Function: gdImageSaveAlpha
 + *
 + * Sets the save alpha flag
 + *
 + * The save alpha flag specifies whether the alpha channel of the pixels should
 + * be saved. This is supported only for image formats that support full alpha
 + * transparency, e.g. PNG.
 + */
 +BGD_DECLARE(void) gdImageSaveAlpha(gdImagePtr im, int saveAlphaArg)
 +{
 +    im->saveAlphaFlag = saveAlphaArg;
 +}

 +/**
 + * Function: gdImageSetClip
 + *
 + * Sets the clipping rectangle
 + *
 + * The clipping rectangle restricts the drawing area for following drawing
 + * operations.
 + *
 + * Parameters:
 + *   im - The image.
 + *   x1 - The x-coordinate of the upper left corner.
 + *   y1 - The y-coordinate of the upper left corner.
 + *   x2 - The x-coordinate of the lower right corner.
 + *   y2 - The y-coordinate of the lower right corner.
 + *
 + * See also:
 + *   - <gdImageGetClip>
 + */
 +BGD_DECLARE(void)
 +gdImageSetClip(gdImagePtr im, int x1, int y1, int x2, int y2)
 +{
 +    if (x1 < 0) {
 +        x1 = 0;
 +    }
 +    if (x1 >= im->sx) {
 +        x1 = im->sx - 1;
 +    }
 +    if (x2 < 0) {
 +        x2 = 0;
 +    }
 +    if (x2 >= im->sx) {
 +        x2 = im->sx - 1;
 +    }
 +    if (y1 < 0) {
 +        y1 = 0;
 +    }
 +    if (y1 >= im->sy) {
 +        y1 = im->sy - 1;
 +    }
 +    if (y2 < 0) {
 +        y2 = 0;
 +    }
 +    if (y2 >= im->sy) {
 +        y2 = im->sy - 1;
 +    }
 +    im->cx1 = x1;
 +    im->cy1 = y1;
 +    im->cx2 = x2;
 +    im->cy2 = y2;
  }

 -void gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg)
 -{
 -	im->alphaBlendingFlag = alphaBlendingArg;
 +/**
 + * Function: gdImageGetClip
 + *
 + * Gets the current clipping rectangle
 + *
 + * Parameters:
 + *   im - The image.
 + *   x1P - (out) The x-coordinate of the upper left corner.
 + *   y1P - (out) The y-coordinate of the upper left corner.
 + *   x2P - (out) The x-coordinate of the lower right corner.
 + *   y2P - (out) The y-coordinate of the lower right corner.
 + *
 + * See also:
 + *   - <gdImageSetClip>
 + */
 +BGD_DECLARE(void) gdImageGetClip(gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
 +{
 +    *x1P = im->cx1;
 +    *y1P = im->cy1;
 +    *x2P = im->cx2;
 +    *y2P = im->cy2;
  }

 -void gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg)
 +/**
 + * Function: gdImageSetResolution
 + *
 + * Sets the resolution of an image.
 + *
 + * Parameters:
 + *   im    - The image.
 + *   res_x - The horizontal resolution in DPI.
 + *   res_y - The vertical resolution in DPI.
 + *
 + * See also:
 + *   - <gdImageResolutionX>
 + *   - <gdImageResolutionY>
 + */
 +BGD_DECLARE(void)
 +gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y)
  {
 -	im->saveAlphaFlag = saveAlphaArg;
 +    if (res_x > 0)
 +        im->res_x = res_x;
 +    if (res_y > 0)
 +        im->res_y = res_y;
  }

 -int gdLayerOverlay (int dst, int src)
 +#define BLEND_COLOR(a, nc, c, cc)                                                                  \
 +    nc = (cc) + (((((c) - (cc)) * (a)) + ((((c) - (cc)) * (a)) >> 8) + 0x80) >> 8);
 +
 +static void gdImageSetAAPixelColor(gdImagePtr im, int x, int y, int color, int t)
  {
 -	int a1, a2;
 -	a1 = gdAlphaMax - gdTrueColorGetAlpha(dst);
 -	a2 = gdAlphaMax - gdTrueColorGetAlpha(src);
 -	return ( ((gdAlphaMax - a1*a2/gdAlphaMax) << 24) +
 -		(gdAlphaOverlayColor( gdTrueColorGetRed(src), gdTrueColorGetRed(dst), gdRedMax ) << 16) +
 -		(gdAlphaOverlayColor( gdTrueColorGetGreen(src), gdTrueColorGetGreen(dst), gdGreenMax ) << 8) +
 -		(gdAlphaOverlayColor( gdTrueColorGetBlue(src), gdTrueColorGetBlue(dst), gdBlueMax ))
 -		);
 +    int dr, dg, db, p, r, g, b;
 +
 +    /* 2.0.34: watch out for out of range calls */
 +    if (!gdImageBoundsSafeMacro(im, x, y)) {
 +        return;
 +    }
 +    p = gdImageGetPixel(im, x, y);
 +    /* TBB: we have to implement the dont_blend stuff to provide
 +      the full feature set of the old implementation */
 +    if ((p == color) || ((p == im->AA_dont_blend) && (t != 0x00))) {
 +        return;
 +    }
 +    dr = gdTrueColorGetRed(color);
 +    dg = gdTrueColorGetGreen(color);
 +    db = gdTrueColorGetBlue(color);
 +
 +    r = gdTrueColorGetRed(p);
 +    g = gdTrueColorGetGreen(p);
 +    b = gdTrueColorGetBlue(p);
 +
 +    BLEND_COLOR(t, dr, r, dr);
 +    BLEND_COLOR(t, dg, g, dg);
 +    BLEND_COLOR(t, db, b, db);
 +    im->tpixels[y][x] = gdTrueColorAlpha(dr, dg, db, gdAlphaOpaque);
  }

 -static int gdAlphaOverlayColor (int src, int dst, int max )
 +BGD_DECLARE(void) gdImageAALine(gdImagePtr im, int x1, int y1, int x2, int y2, int col)
  {
 -	/* this function implements the algorithm
 -	 *
 -	 * for dst[rgb] < 0.5,
 -	 *   c[rgb] = 2.src[rgb].dst[rgb]
 -	 * and for dst[rgb] > 0.5,
 -	 *   c[rgb] = -2.src[rgb].dst[rgb] + 2.dst[rgb] + 2.src[rgb] - 1
 -	 *
 -	 */
 +    /* keep them as 32bits */
 +    long x, y, inc, frac;
 +    long dx, dy, tmp;
 +    int w, wid, wstart;
 +    int thick = im->thick;
 +
 +    if (!im->trueColor) {
 +        /* TBB: don't crash when the image is of the wrong type */
 +        gdImageLine(im, x1, y1, x2, y2, col);
 +        return;
 +    }
 +
 +    /* TBB: use the clipping rectangle */
 +    if (clip_1d(&x1, &y1, &x2, &y2, im->cx1, im->cx2) == 0)
 +        return;
 +    if (clip_1d(&y1, &x1, &y2, &x2, im->cy1, im->cy2) == 0)
 +        return;
 +
 +    dx = x2 - x1;
 +    dy = y2 - y1;
 +
 +    if (dx == 0 && dy == 0) {
 +        /* TBB: allow setting points */
 +        gdImageSetPixel(im, x1, y1, col);
 +        return;
 +    } else {
 +        double ag;
 +        /* Cast the long to an int to avoid compiler warnings about truncation.
 +         * This isn't a problem as computed dy/dx values came from ints above.
 +         */
 +        ag = fabs(abs((int)dy) < abs((int)dx) ? cos(atan2(dy, dx)) : sin(atan2(dy, dx)));
 +        if (ag != 0) {
 +            wid = thick / ag;
 +        } else {
 +            wid = 1;
 +        }
 +        if (wid == 0) {
 +            wid = 1;
 +        }
 +    }

 -	dst = dst << 1;
 -	if( dst > max ) {
 -		/* in the "light" zone */
 -		return dst + (src << 1) - (dst * src / max) - max;
 -	} else {
 -		/* in the "dark" zone */
 -		return dst * src / max;
 -	}
 +    /* Axis aligned lines */
 +    if (dx == 0) {
 +        gdImageVLine(im, x1, y1, y2, col);
 +        return;
 +    } else if (dy == 0) {
 +        gdImageHLine(im, y1, x1, x2, col);
 +        return;
 +    }
 +
 +    if (abs((int)dx) > abs((int)dy)) {
 +        if (dx < 0) {
 +            tmp = x1;
 +            x1 = x2;
 +            x2 = tmp;
 +            tmp = y1;
 +            y1 = y2;
 +            y2 = tmp;
 +            dx = x2 - x1;
 +            dy = y2 - y1;
 +        }
 +        y = y1;
 +        inc = (dy * 65536) / dx;
 +        frac = 0;
 +        /* TBB: set the last pixel for consistency (<=) */
 +        for (x = x1; x <= x2; x++) {
 +            wstart = y - wid / 2;
 +            for (w = wstart; w < wstart + wid; w++) {
 +                gdImageSetAAPixelColor(im, x, w, col, (frac >> 8) & 0xFF);
 +                gdImageSetAAPixelColor(im, x, w + 1, col, (~frac >> 8) & 0xFF);
 +            }
 +            frac += inc;
 +            if (frac >= 65536) {
 +                frac -= 65536;
 +                y++;
 +            } else if (frac < 0) {
 +                frac += 65536;
 +                y--;
 +            }
 +        }
 +    } else {
 +        if (dy < 0) {
 +            tmp = x1;
 +            x1 = x2;
 +            x2 = tmp;
 +            tmp = y1;
 +            y1 = y2;
 +            y2 = tmp;
 +            dx = x2 - x1;
 +            dy = y2 - y1;
 +        }
 +        x = x1;
 +        inc = (dx * 65536) / dy;
 +        frac = 0;
 +        /* TBB: set the last pixel for consistency (<=) */
 +        for (y = y1; y <= y2; y++) {
 +            wstart = x - wid / 2;
 +            for (w = wstart; w < wstart + wid; w++) {
 +                gdImageSetAAPixelColor(im, w, y, col, (frac >> 8) & 0xFF);
 +                gdImageSetAAPixelColor(im, w + 1, y, col, (~frac >> 8) & 0xFF);
 +            }
 +            frac += inc;
 +            if (frac >= 65536) {
 +                frac -= 65536;
 +                x++;
 +            } else if (frac < 0) {
 +                frac += 65536;
 +                x--;
 +            }
 +        }
 +    }
  }

 -int gdLayerMultiply (int dst, int src)
 -{
 -	int a1, a2, r1, r2, g1, g2, b1, b2;
 -	a1 = gdAlphaMax - gdTrueColorGetAlpha(src);
 -	a2 = gdAlphaMax - gdTrueColorGetAlpha(dst);
 -
 -	r1 = gdRedMax - (a1 * (gdRedMax - gdTrueColorGetRed(src))) / gdAlphaMax;
 -	r2 = gdRedMax - (a2 * (gdRedMax - gdTrueColorGetRed(dst))) / gdAlphaMax;
 -	g1 = gdGreenMax - (a1 * (gdGreenMax - gdTrueColorGetGreen(src))) / gdAlphaMax;
 -	g2 = gdGreenMax - (a2 * (gdGreenMax - gdTrueColorGetGreen(dst))) / gdAlphaMax;
 -	b1 = gdBlueMax - (a1 * (gdBlueMax - gdTrueColorGetBlue(src))) / gdAlphaMax;
 -	b2 = gdBlueMax - (a2 * (gdBlueMax - gdTrueColorGetBlue(dst))) / gdAlphaMax ;
 -
 -	a1 = gdAlphaMax - a1;
 -	a2 = gdAlphaMax - a2;
 -	return ( ((a1*a2/gdAlphaMax) << 24) +
 -			 ((r1*r2/gdRedMax) << 16) +
 -			 ((g1*g2/gdGreenMax) << 8) +
 -			 ((b1*b2/gdBlueMax))
 -		);
 -}
 -
 -void gdImageSetClip (gdImagePtr im, int x1, int y1, int x2, int y2)
 -{
 -	if (x1 < 0) {
 -		x1 = 0;
 -	}
 -	if (x1 >= im->sx) {
 -		x1 = im->sx - 1;
 -	}
 -	if (x2 < 0) {
 -		x2 = 0;
 -	}
 -	if (x2 >= im->sx) {
 -		x2 = im->sx - 1;
 -	}
 -	if (y1 < 0) {
 -		y1 = 0;
 -	}
 -	if (y1 >= im->sy) {
 -		y1 = im->sy - 1;
 -	}
 -	if (y2 < 0) {
 -		y2 = 0;
 -	}
 -	if (y2 >= im->sy) {
 -		y2 = im->sy - 1;
 -	}
 -	im->cx1 = x1;
 -	im->cy1 = y1;
 -	im->cx2 = x2;
 -	im->cy2 = y2;
 -}
 -
 -void gdImageGetClip (gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P)
 -{
 -	*x1P = im->cx1;
 -	*y1P = im->cy1;
 -	*x2P = im->cx2;
 -	*y2P = im->cy2;
 -}
 -
 -void gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y)
 -{
 -	if (res_x > 0) im->res_x = res_x;
 -	if (res_y > 0) im->res_y = res_y;
 -}
 -
 -/* convert a palette image to true color */
 -int gdImagePaletteToTrueColor(gdImagePtr src)
 -{
 -	unsigned int y;
 -	unsigned int yy;
 -
 -	if (src == NULL) {
 -		return 0;
 -	}
 -
 -	if (src->trueColor == 1) {
 -		return 1;
 -	} else {
 -		unsigned int x;
 -		const unsigned int sy = gdImageSY(src);
 -		const unsigned int sx = gdImageSX(src);
 -
 -		// Note: do not revert back to gdMalloc() below ; reason here,
 -		// due to a bug with a certain memory_limit INI value treshold,
 -		// imagepalettetotruecolor crashes with even unrelated ZendMM allocations.
 -		// See GH-17772 for a use case.
 -		src->tpixels = (int **) gdFCalloc(sy, sizeof(int *));
 -		if (src->tpixels == NULL) {
 -			return 0;
 -		}
 -
 -		for (y = 0; y < sy; y++) {
 -			const unsigned char *src_row = src->pixels[y];
 -			int * dst_row;
 -
 -			/* no need to calloc it, we overwrite all pxl anyway */
 -			src->tpixels[y] = (int *) gdFMalloc(sx * sizeof(int));
 -			if (src->tpixels[y] == NULL) {
 -				goto clean_on_error;
 -			}
 +/**
 + * Function: gdImagePaletteToTrueColor
 + *
 + * Convert a palette image to true color
 + *
 + * Parameters:
 + *   src - The image.
 + *
 + * Returns:
 + *   Non-zero if the conversion succeeded, zero otherwise.
 + *
 + * See also:
 + *   - <gdImageTrueColorToPalette>
 + */
 +BGD_DECLARE(int) gdImagePaletteToTrueColor(gdImagePtr src)
 +{
 +    unsigned int y;
 +    unsigned int yy;

 -			dst_row = src->tpixels[y];
 -			for (x = 0; x < sx; x++) {
 -				const unsigned char c = *(src_row + x);
 -				if (c == src->transparent) {
 -					*(dst_row + x) = gdTrueColorAlpha(0, 0, 0, 127);
 -				} else {
 -					*(dst_row + x) = gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
 -				}
 -			}
 -		}
 -	}
 -
 -	/* free old palette buffer (y is sy) */
 -	for (yy = 0; yy < y; yy++) {
 -		gdFree(src->pixels[yy]);
 -	}
 -	gdFree(src->pixels);
 -	src->trueColor = 1;
 -	src->pixels = NULL;
 -	src->alphaBlendingFlag = 0;
 -	src->saveAlphaFlag = 1;
 -
 -	if (src->transparent >= 0) {
 -		const unsigned char c = src->transparent;
 -		src->transparent =  gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
 -	}
 -
 -	return 1;
 +    if (src == NULL) {
 +        return 0;
 +    }
 +
 +    if (src->trueColor == 1) {
 +        return 1;
 +    } else {
 +        unsigned int x;
 +        const unsigned int sy = gdImageSY(src);
 +        const unsigned int sx = gdImageSX(src);
 +
 +        // Note: do not revert back to gdMalloc() below ; reason here,
 +        // due to a bug with a certain memory_limit INI value treshold,
 +        // imagepalettetotruecolor crashes with even unrelated ZendMM allocations.
 +        // See GH-17772 for a use case.
 +        src->tpixels = (int **)gdCalloc(sy, sizeof(int *));
 +        if (src->tpixels == NULL) {
 +            return 0;
 +        }
 +
 +        for (y = 0; y < sy; y++) {
 +            const unsigned char *src_row = src->pixels[y];
 +            int *dst_row;
 +
 +            /* no need to calloc it, we overwrite all pxl anyway */
 +            src->tpixels[y] = (int *)gdMalloc(sx * sizeof(int));
 +            if (src->tpixels[y] == NULL) {
 +                goto clean_on_error;
 +            }
 +
 +            dst_row = src->tpixels[y];
 +            for (x = 0; x < sx; x++) {
 +                const unsigned char c = *(src_row + x);
 +                if (c == src->transparent) {
 +                    *(dst_row + x) = gdTrueColorAlpha(0, 0, 0, 127);
 +                } else {
 +                    *(dst_row + x) =
 +                        gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
 +                }
 +            }
 +        }
 +    }
 +
 +    /* free old palette buffer (y is sy) */
 +    for (yy = 0; yy < y; yy++) {
 +        gdFree(src->pixels[yy]);
 +    }
 +    gdFree(src->pixels);
 +    src->trueColor = 1;
 +    src->pixels = NULL;
 +    src->alphaBlendingFlag = 0;
 +    src->saveAlphaFlag = 1;
 +
 +    if (src->transparent >= 0) {
 +        const unsigned char c = src->transparent;
 +        src->transparent =
 +            gdTrueColorAlpha(src->red[c], src->green[c], src->blue[c], src->alpha[c]);
 +    }
 +
 +    return 1;

  clean_on_error:
 -	/* free new true color buffer (y is not allocated, have failed) */
 -	for (yy = 0; yy < y; yy++) {
 -		gdFree(src->tpixels[yy]);
 -	}
 -	gdFree(src->tpixels);
 -	src->tpixels = NULL;
 -	return 0;
 +    /* free new true color buffer (y is not allocated, have failed) */
 +    for (yy = 0; yy < y; yy++) {
 +        gdFree(src->tpixels[yy]);
 +    }
 +    gdFree(src->tpixels);
++    src->tpixels = NULL;
 +    return 0;
  }
diff --cc ext/gd/libgd/gdhelpers.h
index 931c5fb83a7,981356d4f81..606a1297487
--- a/ext/gd/libgd/gdhelpers.h
+++ b/ext/gd/libgd/gdhelpers.h
@@@ -6,33 -6,27 +6,33 @@@

  /* TBB: strtok_r is not universal; provide an implementation of it. */

 -extern char *gd_strtok_r(char *s, char *sep, char **state);
 +char *gd_strtok_r(char *s, const char *sep, char **state);

  /* These functions wrap memory management. gdFree is
 -	in gd.h, where callers can utilize it to correctly
 -	free memory allocated by these functions with the
 -	right version of free(). */
 -#define gdCalloc(nmemb, size)	ecalloc(nmemb, size)
 -#define gdFCalloc(nmemb, size)	fecalloc(nmemb, size, true)
 -#define gdMalloc(size)		emalloc(size)
 -#define gdRealloc(ptr, size)	erealloc(ptr, size)
 -#define gdFMalloc(size)		femalloc(size, true)
 -#define gdEstrdup(ptr)		estrdup(ptr)
 -#define gdFree(ptr)		efree(ptr)
 -#define gdPMalloc(ptr)		pemalloc(ptr, 1)
 -#define gdPFree(ptr)		pefree(ptr, 1)
 -#define gdPEstrdup(ptr)		pestrdup(ptr, 1)
 +        in gd.h, where callers can utilize it to correctly
 +        free memory allocated by these functions with the
 +        right version of free(). */
- #define gdCalloc(nmemb, size) ecalloc((nmemb), (size))
- #define gdMalloc(size) emalloc(size)
- #define gdRealloc(ptr, size) erealloc(ptr, size)
++#define gdCalloc(nmemb, size) fecalloc((nmemb), (size), /* fallible */ true)
++#define gdMalloc(size) femalloc(size, /* fallible */ true)
++#define gdRealloc(ptr, size) safe_ferealloc(ptr, 1, size, 0, /* fallible */ true)
 +#define gdEstrdup(ptr) estrdup(ptr)
 +#define gdFree(ptr) efree(ptr)
 +#define gdPMalloc(ptr) pemalloc(ptr, 1)
 +#define gdPFree(ptr) pefree(ptr, 1)
 +#define gdPEstrdup(ptr) pestrdup(ptr, 1)
 +
 +/* The extended version of gdReallocEx will free *ptr if the
 + * realloc fails. */
 +void *gdReallocEx(void *ptr, size_t size);
 +
 +/* Internal deterministic allocation hook used by the vector2d failure tests. */
 +void *gdVector2dMalloc(size_t size);
 +void gdVector2dTestSetAllocationFailureCountdown(int countdown);

  /* Returns nonzero if multiplying the two quantities will
 -	result in integer overflow. Also returns nonzero if
 -	either quantity is negative. By Phil Knirsch based on
 -	netpbm fixes by Alan Cox. */
 +        result in integer overflow. Also returns nonzero if
 +        either quantity is negative. By Phil Knirsch based on
 +        netpbm fixes by Alan Cox. */

  int overflow2(int a, int b);
  int overflowMul3(int a, int b, int c);
diff --cc ext/intl/converter/converter.cpp
index 1369b88742f,7d107c39ca1..8a11dd27109
--- a/ext/intl/converter/converter.cpp
+++ b/ext/intl/converter/converter.cpp
@@@ -641,9 -640,12 +641,12 @@@ static zend_string* php_converter_do_co
  	temp_len = 1 + ucnv_toUChars(src_cnv, NULL, 0, src, src_len, &error);
  	if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
  		THROW_UFAILURE(objval, error);
 -		return NULL;
 +		return nullptr;
  	}
- 	temp = reinterpret_cast<UChar *>(safe_emalloc(sizeof(UChar), temp_len, sizeof(UChar)));
 -	temp = safe_femalloc(sizeof(UChar), temp_len, sizeof(UChar), /* fallible */ true);
++	temp = reinterpret_cast<UChar *>(safe_femalloc(sizeof(UChar), temp_len, sizeof(UChar), /* fallible */ true));
+ 	if (!temp) {
+ 		return NULL;
+ 	}

  	/* Convert to intermediate UChar* array */
  	error = U_ZERO_ERROR;
@@@ -660,10 -662,14 +663,14 @@@
  	if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
  		THROW_UFAILURE(objval, error);
  		efree(temp);
 -		return NULL;
 +		return nullptr;
  	}

- 	ret = zend_string_alloc(ret_len, 0);
+ 	ret = zend_string_falloc(ret_len, /* persistent */ false, /* fallible */ true);
+ 	if (!ret) {
+ 		efree(temp);
+ 		return NULL;
+ 	}

  	/* Convert to final encoding */
  	error = U_ZERO_ERROR;
diff --cc ext/intl/grapheme/grapheme_string.cpp
index acb7c50cb9e,743939a9b66..08b41a5e6ab
--- a/ext/intl/grapheme/grapheme_string.cpp
+++ b/ext/intl/grapheme/grapheme_string.cpp
@@@ -923,9 -922,15 +926,15 @@@ U_CFUNC PHP_FUNCTION(grapheme_str_split

  	utext_close(ut);
  	ubrk_close(bi);
+ 	return;
+
+ oom:
+ 	utext_close(ut);
+ 	ubrk_close(bi);
+ 	RETURN_OOM();
  }

 -PHP_FUNCTION(grapheme_levenshtein)
 +U_CFUNC PHP_FUNCTION(grapheme_levenshtein)
  {
  	zend_string *string1, *string2;
  	zend_long cost_ins = 1;
@@@ -1072,8 -1079,15 +1087,15 @@@
  	}

  	zend_long *p1, *p2, *tmp;
- 	p1 = reinterpret_cast<zend_long *>(safe_emalloc((size_t) strlen_2 + 1, sizeof(zend_long), 0));
- 	p2 = reinterpret_cast<zend_long *>(safe_emalloc((size_t) strlen_2 + 1, sizeof(zend_long), 0));
 -	p1 = safe_femalloc((size_t) strlen_2 + 1, sizeof(zend_long), 0, /* fallible */ true);
++	p1 = reinterpret_cast<zend_long *>(safe_femalloc((size_t) strlen_2 + 1, sizeof(zend_long), 0, /* fallible */ true));
+ 	if (!p1) {
+ 		goto out_collator;
+ 	}
 -	p2 = safe_femalloc((size_t) strlen_2 + 1, sizeof(zend_long), 0, /* fallible */ true);
++	p2 = reinterpret_cast<zend_long *>(safe_femalloc((size_t) strlen_2 + 1, sizeof(zend_long), 0, /* fallible */ true));
+ 	if (!p2) {
+ 		efree(p1);
+ 		goto out_collator;
+ 	}

  	for (i2 = 0; i2 <= strlen_2; i2++) {
  		p1[i2] = i2 * cost_ins;
diff --cc ext/json/json_encoder.c
index b8ae31040c8,c33df074270..9d46ceab3cc
--- a/ext/json/json_encoder.c
+++ b/ext/json/json_encoder.c
@@@ -279,13 -292,25 +284,19 @@@ static zend_result php_json_encode_arra
  					php_json_pretty_print_indent(buf, options, encoder);

  					if (php_json_escape_string(buf, ZSTR_VAL(key), ZSTR_LEN(key),
- 								options & ~PHP_JSON_NUMERIC_CHECK, encoder) == FAILURE &&
- 							(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) &&
- 							buf->s) {
- 						ZSTR_LEN(buf->s) -= 4;
- 						smart_str_appendl(buf, "\"\"", 2);
+ 								options & ~PHP_JSON_NUMERIC_CHECK, encoder) == FAILURE) {
+ 						if (ZEND_HAS_OOM()) {
+ 							PHP_JSON_HASH_UNPROTECT_RECURSION(myht);
+ 							zend_release_properties(prop_ht);
+ 							return FAILURE;
+ 						}
+ 						if ((options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) && buf->s) {
+ 							ZEND_ASSERT(ZSTR_LEN(buf->s) >= 4);
+ 							ZSTR_LEN(buf->s) -= 4;
+ 							smart_str_appendl(buf, "\"\"", 2);
+ 						}
  					}
  				} else {
 -					if (need_comma) {
 -						smart_str_appendc(buf, ',');
 -					} else {
 -						need_comma = 1;
 -					}
 -
  					php_json_pretty_print_char(buf, options, '\n');
  					php_json_pretty_print_indent(buf, options, encoder);

diff --cc ext/mbstring/libmbfl/mbfl/mbfilter.c
index d2d68795fa0,56b2a4a0c40..249a0bbf633
--- a/ext/mbstring/libmbfl/mbfl/mbfilter.c
+++ b/ext/mbstring/libmbfl/mbfl/mbfilter.c
@@@ -112,88 -113,147 +112,94 @@@ mbfl_strcut
  	mbfl_string_init(result);
  	result->encoding = string->encoding;

 -	if ((encoding->flag & (MBFL_ENCTYPE_SBCS | MBFL_ENCTYPE_WCS2 | MBFL_ENCTYPE_WCS4)) || encoding->mblen_table != NULL) {
 -		const unsigned char *start = NULL;
 -		const unsigned char *end = NULL;
 -		unsigned char *w;
 -		size_t sz;
 -
 -		if (encoding->flag & MBFL_ENCTYPE_WCS2) {
 -			from &= -2;
 -
 -			if (length >= string->len - from) {
 -				length = string->len - from;
 -			}
 -
 -			start = string->val + from;
 -			end   = start + (length & -2);
 -		} else if (encoding->flag & MBFL_ENCTYPE_WCS4) {
 -			from &= -4;
 -
 -			if (length >= string->len - from) {
 -				length = string->len - from;
 -			}
 -
 -			start = string->val + from;
 -			end   = start + (length & -4);
 -		} else if ((encoding->flag & MBFL_ENCTYPE_SBCS)) {
 -			if (length >= string->len - from) {
 -				length = string->len - from;
 -			}
 -
 -			start = string->val + from;
 -			end = start + length;
 -		} else if (encoding->mblen_table != NULL) {
 -			const unsigned char *mbtab = encoding->mblen_table;
 -			const unsigned char *p, *q;
 -			int m;
 -
 -			/* search start position */
 -			for (m = 0, p = string->val, q = p + from;
 -					p < q; p += (m = mbtab[*p]));
 +	mbfl_convert_filter *encoder     = NULL;
 +	mbfl_convert_filter *decoder     = NULL;
 +	const unsigned char *p, *q, *r;
 +	struct {
 +		mbfl_convert_filter encoder;
 +		mbfl_convert_filter decoder;
 +		const unsigned char *p;
 +		size_t pos;
 +	} bk, _bk;
 +
 +	/* output code filter */
 +	if (!(decoder = mbfl_convert_filter_new(
 +			&mbfl_encoding_wchar,
 +			string->encoding,
 +			mbfl_memory_device_output, 0, &device))) {
 +		return NULL;
 +	}

 -			if (p > q) {
 -				p -= m;
 -			}
 +	/* wchar filter */
 +	if (!(encoder = mbfl_convert_filter_new(
 +			string->encoding,
 +			&mbfl_encoding_wchar,
 +			mbfl_filter_output_null,
 +			NULL, NULL))) {
 +		mbfl_convert_filter_delete(decoder);
 +		return NULL;
 +	}

- 	mbfl_memory_device_init(&device, length + 8, 0);
 -			start = p;
++	/* clamp init size to avoid over allocation */
++	size_t init_size = MIN(string->len, length) + 8;
++	mbfl_memory_device_init(&device, init_size, 0);

 -			/* search end position */
 -			if (length >= string->len - (start - string->val)) {
 -				end = string->val + string->len;
 -			} else {
 -				for (q = p + length; p < q; p += (m = mbtab[*p]));
 +	p = string->val;

 -				if (p > q) {
 -					p -= m;
 -				}
 -				end = p;
 -			}
 -		} else {
 -			/* never reached */
 -			return NULL;
 +	/* search start position */
 +	for (q = string->val + from; p < q; p++) {
- 		(*encoder->filter_function)(*p, encoder);
++		if ((*encoder->filter_function)(*p, encoder) < 0) {
++			goto err;
+ 		}
 +	}

 -		/* allocate memory and copy string */
 -		sz = end - start;
 -		w = ecalloc(sz + 8, sizeof(unsigned char));
 -
 -		memcpy(w, start, sz);
 -		w[sz] = '\0';
 -		w[sz + 1] = '\0';
 -		w[sz + 2] = '\0';
 -		w[sz + 3] = '\0';
 -
 -		result->val = w;
 -		result->len = sz;
 -	} else {
 -		mbfl_convert_filter *encoder     = NULL;
 -		mbfl_convert_filter *decoder     = NULL;
 -		const unsigned char *p, *q, *r;
 -		struct {
 -			mbfl_convert_filter encoder;
 -			mbfl_convert_filter decoder;
 -			const unsigned char *p;
 -			size_t pos;
 -		} bk, _bk;
 -
 -		/* output code filter */
 -		if (!(decoder = mbfl_convert_filter_new(
 -				&mbfl_encoding_wchar,
 -				string->encoding,
 -				mbfl_memory_device_output, 0, &device))) {
 -			return NULL;
 -		}
 +	/* switch the drain direction */
 +	encoder->output_function = (output_function_t)decoder->filter_function;
 +	encoder->flush_function = (flush_function_t)decoder->filter_flush;
 +	encoder->data = decoder;

 -		/* wchar filter */
 -		if (!(encoder = mbfl_convert_filter_new(
 -				string->encoding,
 -				&mbfl_encoding_wchar,
 -				mbfl_filter_output_null,
 -				NULL, NULL))) {
 -			mbfl_convert_filter_delete(decoder);
 -			return NULL;
 -		}
 +	q = string->val + string->len;

 -		/* clamp init size to avoid over allocation */
 -		size_t init_size = MIN(string->len, length) + 8;
 -		mbfl_memory_device_init(&device, init_size, 0);
 +	/* save the encoder, decoder state and the pointer */
 +	mbfl_convert_filter_copy(decoder, &_bk.decoder);
 +	mbfl_convert_filter_copy(encoder, &_bk.encoder);
 +	_bk.p = p;
 +	_bk.pos = device.pos;

 -		p = string->val;
 +	if (length > q - p) {
 +		length = q - p;
 +	}

 -		/* search start position */
 -		for (q = string->val + from; p < q; p++) {
 -			if ((*encoder->filter_function)(*p, encoder) < 0) {
 -				goto err;
 +	if (length >= 20) {
 +		/* output a little shorter than "length" */
 +		/* XXX: the constant "20" was determined purely on the heuristics. */
 +		for (r = p + length - 20; p < r; p++) {
- 			(*encoder->filter_function)(*p, encoder);
++			if (UNEXPECTED((*encoder->filter_function)(*p, encoder) < 0)) {
++				goto err_prev_bk;
+ 			}
  		}

 -		/* switch the drain direction */
 -		encoder->output_function = (output_function_t)decoder->filter_function;
 -		encoder->flush_function = (flush_function_t)decoder->filter_flush;
 -		encoder->data = decoder;
 -
 -		q = string->val + string->len;
 -
 -		/* save the encoder, decoder state and the pointer */
 -		mbfl_convert_filter_copy(decoder, &_bk.decoder);
 -		mbfl_convert_filter_copy(encoder, &_bk.encoder);
 -		_bk.p = p;
 -		_bk.pos = device.pos;
 -
 -		if (length > q - p) {
 -			length = q - p;
 -		}
 +		/* if the offset of the resulting string exceeds the length,
 +		 * then restore the state */
 +		if (device.pos > length) {
 +			p = _bk.p;
 +			device.pos = _bk.pos;
 +			if (decoder->filter_dtor)
 +				decoder->filter_dtor(decoder);
 +			if (encoder->filter_dtor)
 +				encoder->filter_dtor(encoder);
 +			mbfl_convert_filter_copy(&_bk.decoder, decoder);
 +			mbfl_convert_filter_copy(&_bk.encoder, encoder);
 +			bk = _bk;
 +		} else {
 +			/* save the encoder, decoder state and the pointer */
 +			mbfl_convert_filter_copy(decoder, &bk.decoder);
 +			mbfl_convert_filter_copy(encoder, &bk.encoder);
 +			bk.p = p;
 +			bk.pos = device.pos;

 -		if (length >= 20) {
 -			/* output a little shorter than "length" */
 -			/* XXX: the constant "20" was determined purely on the heuristics. */
 -			for (r = p + length - 20; p < r; p++) {
 -				if ((*encoder->filter_function)(*p, encoder) < 0) {
 -					goto err_prev_bk;
 -				}
 -			}
 +			/* flush the stream */
 +			(*encoder->filter_flush)(encoder);

  			/* if the offset of the resulting string exceeds the length,
  			 * then restore the state */
@@@ -226,20 -358,16 +232,22 @@@
  					encoder->filter_dtor(encoder);
  				mbfl_convert_filter_copy(&bk.decoder, decoder);
  				mbfl_convert_filter_copy(&bk.encoder, encoder);
 -				break;
  			}
 +		}
 +	} else {
 +		bk = _bk;
 +	}

 -			if (bk.decoder.filter_dtor)
 -				bk.decoder.filter_dtor(&bk.decoder);
 -			if (bk.encoder.filter_dtor)
 -				bk.encoder.filter_dtor(&bk.encoder);
 +	/* detect end position */
 +	while (p < q) {
- 		(*encoder->filter_function)(*p, encoder);
++		if ((*encoder->filter_function)(*p, encoder) < 0) {
++			goto err_bk;
++		}

 -			p = _bk.p;
 -			device.pos = _bk.pos;
 +		if (device.pos > length) {
 +			/* restore filter */
 +			p = bk.p;
 +			device.pos = bk.pos;
  			if (decoder->filter_dtor)
  				decoder->filter_dtor(decoder);
  			if (encoder->filter_dtor)
@@@ -282,30 -386,36 +290,53 @@@
  		if (bk.encoder.filter_dtor)
  			bk.encoder.filter_dtor(&bk.encoder);

 -		result = mbfl_memory_device_result(&device, result);
 +		p = _bk.p;
 +		device.pos = _bk.pos;
 +		if (decoder->filter_dtor)
 +			decoder->filter_dtor(decoder);
 +		if (encoder->filter_dtor)
 +			encoder->filter_dtor(encoder);
 +		mbfl_convert_filter_copy(&_bk.decoder, decoder);
 +		mbfl_convert_filter_copy(&_bk.encoder, encoder);

 -		mbfl_convert_filter_delete(encoder);
 -		mbfl_convert_filter_delete(decoder);
 +		bk = _bk;
 +	}
 +
 +	decoder->illegal_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE;
 +	(*encoder->filter_flush)(encoder);

 -		return result;
 +	if (bk.decoder.filter_dtor)
 +		bk.decoder.filter_dtor(&bk.decoder);
 +	if (bk.encoder.filter_dtor)
 +		bk.encoder.filter_dtor(&bk.encoder);

 -		/* Conversion failed, which for these filters means the output device
 -		 * could not be grown. Release the saved filter state which the normal
 -		 * exit path would have released, then everything else. */
 +	result = mbfl_memory_device_result(&device, result);
 +
 +	mbfl_convert_filter_delete(encoder);
 +	mbfl_convert_filter_delete(decoder);
 +
 +	return result;
++
++	/* Conversion failed, which for these filters means the output device
++	 * could not be grown. Release the saved filter state which the normal
++	 * exit path would have released, then everything else. */
+ err_bk:
 -		if (bk.decoder.filter_dtor)
 -			bk.decoder.filter_dtor(&bk.decoder);
 -		if (bk.encoder.filter_dtor)
 -			bk.encoder.filter_dtor(&bk.encoder);
 -		goto err;
++	if (bk.decoder.filter_dtor)
++		bk.decoder.filter_dtor(&bk.decoder);
++	if (bk.encoder.filter_dtor)
++		bk.encoder.filter_dtor(&bk.encoder);
++	goto err;
+
+ err_prev_bk:
 -		if (_bk.decoder.filter_dtor)
 -			_bk.decoder.filter_dtor(&_bk.decoder);
 -		if (_bk.encoder.filter_dtor)
 -			_bk.encoder.filter_dtor(&_bk.encoder);
++	if (_bk.decoder.filter_dtor)
++		_bk.decoder.filter_dtor(&_bk.decoder);
++	if (_bk.encoder.filter_dtor)
++		_bk.encoder.filter_dtor(&_bk.encoder);
+
+ err:
 -		mbfl_convert_filter_delete(encoder);
 -		mbfl_convert_filter_delete(decoder);
 -		mbfl_memory_device_clear(&device);
 -
 -		return NULL;
 -	}
++	mbfl_convert_filter_delete(encoder);
++	mbfl_convert_filter_delete(decoder);
++	mbfl_memory_device_clear(&device);
+
 -	return result;
++	return NULL;
  }
diff --cc ext/mbstring/mbstring.c
index 73436492f50,4cfe5422ad6..d8c3b4eb5d0
--- a/ext/mbstring/mbstring.c
+++ b/ext/mbstring/mbstring.c
@@@ -3838,16 -3840,10 +3871,19 @@@ static bool mb_recursive_convert_variab
  		zend_string *ret = php_mb_convert_encoding_ex(Z_STRVAL_P(var), Z_STRLEN_P(var), to_encoding, from_encoding);
  		zval_ptr_dtor(orig_var);
  		ZVAL_STR(orig_var, ret);
+ 		if (ZEND_HAS_OOM()) {
+ 			return true;
+ 		}
  	} else if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) {
 +		if (Z_TYPE_P(var) == IS_OBJECT) {
 +			php_error_docref(NULL, E_DEPRECATED,
 +				"Passing an object for argument #%" PRIu32 " $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead",
 +				arg_num
 +			);
 +			if (UNEXPECTED(EG(exception))) {
 +				return true;
 +			}
 +		}
  		HashTable *ht = HASH_OF(var);
  		HashTable *orig_ht = ht;

diff --cc ext/mbstring/tests/oom_mb_ereg_replace.phpt
index 00000000000,0041a4c1985..f1a14262ebb
mode 000000,100644..100644
--- a/ext/mbstring/tests/oom_mb_ereg_replace.phpt
+++ b/ext/mbstring/tests/oom_mb_ereg_replace.phpt
@@@ -1,0 -1,18 +1,20 @@@
+ --TEST--
+ mb_ereg_replace() doesn't reach hard limit
+ --EXTENSIONS--
+ mbstring
+ --SKIPIF--
+ <?php
+ if (!function_exists("mb_ereg_replace")) die("skip mbregex support unavailable");
+ ?>
+ --INI--
+ memory_limit=8M
+ --FILE--
+ <?php
+ // 2 MB == memory_limit / 4
+ mb_ereg_replace("a", "bbbbbbbbbb", str_repeat("a", 2 * 1024 * 1024));
+ echo "not reached\n";
+ ?>
+ --EXPECTF--
++Deprecated: Function mb_ereg_replace() is deprecated since 8.6, because the underlying library is no longer maintained in %s on line %d
++
+ Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
diff --cc ext/mbstring/tests/oom_mb_eregi_replace.phpt
index 00000000000,9d72892941d..6f0bb9c5df9
mode 000000,100644..100644
--- a/ext/mbstring/tests/oom_mb_eregi_replace.phpt
+++ b/ext/mbstring/tests/oom_mb_eregi_replace.phpt
@@@ -1,0 -1,18 +1,20 @@@
+ --TEST--
+ mb_eregi_replace() doesn't reach hard limit
+ --EXTENSIONS--
+ mbstring
+ --SKIPIF--
+ <?php
+ if (!function_exists("mb_eregi_replace")) die("skip mbregex support unavailable");
+ ?>
+ --INI--
+ memory_limit=8M
+ --FILE--
+ <?php
+ // 2 MB == memory_limit / 4
+ mb_eregi_replace("a", "bbbbbbbbbb", str_repeat("a", 2 * 1024 * 1024));
+ echo "not reached\n";
+ ?>
+ --EXPECTF--
++Deprecated: Function mb_eregi_replace() is deprecated since 8.6, because the underlying library is no longer maintained in %s on line %d
++
+ Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
diff --cc ext/mbstring/tests/oom_mb_split.phpt
index 00000000000,4d375a0a313..dcf61689cfe
mode 000000,100644..100644
--- a/ext/mbstring/tests/oom_mb_split.phpt
+++ b/ext/mbstring/tests/oom_mb_split.phpt
@@@ -1,0 -1,17 +1,19 @@@
+ --TEST--
+ mb_split() doesn't reach hard limit
+ --EXTENSIONS--
+ mbstring
+ --SKIPIF--
+ <?php
+ if (!function_exists("mb_split")) die("skip mbregex support unavailable");
+ ?>
+ --INI--
+ memory_limit=8M
+ --FILE--
+ <?php
+ mb_split("a", str_repeat("a", 2 * 1024 * 1024)); // 2 MB == memory_limit / 4
+ echo "not reached\n";
+ ?>
+ --EXPECTF--
++Deprecated: Function mb_split() is deprecated since 8.6, because the underlying library is no longer maintained in %s on line %d
++
+ Fatal error: Allowed memory size of 8388608 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
diff --cc ext/opcache/ZendAccelerator.h
index 79208893d12,256b087d081..5fd34441c40
--- a/ext/opcache/ZendAccelerator.h
+++ b/ext/opcache/ZendAccelerator.h
@@@ -335,18 -343,11 +341,21 @@@ zend_op_array *persistent_compile_file(

  zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str);

- uint32_t zend_accel_get_class_name_map_ptr(zend_string *type_name);
+ void zend_accel_get_class_name_map_ptr(zend_string *type_name);
+ void zend_accel_pending_ce_cache_begin(void);
+ void zend_accel_pending_ce_cache_commit(void);
+ void zend_accel_pending_ce_cache_discard(void);

 +const zend_op_array *zend_accel_pfa_cache_get(
 +		const uint32_t *declaring_lineno_ptr, const zend_function *called_function, bool cacheable_in_shm);
 +
 +/* Compiles ast into an op_array, and caches it. Takes ownership of ast. */
 +zend_op_array *zend_accel_compile_pfa(zend_ast *ast,
 +		zend_string *declaring_filename,
 +		const uint32_t *declaring_lineno_ptr,
 +		const zend_function *called_function,
 +		zend_string *pfa_func_name, bool cacheable_in_shm);
 +
  END_EXTERN_C()

  /* memory write protection */
diff --cc ext/pcre/php_pcre.c
index 4fde4ed5f9b,090cfd8da9a..fd239eb887f
--- a/ext/pcre/php_pcre.c
+++ b/ext/pcre/php_pcre.c
@@@ -1086,8 -1121,9 +1110,9 @@@ static zend_result populate_subpat_arra
  	/* Add MARK, if available */
  	if (mark) {
  		ZVAL_STRING(&val, (char *)mark);
 -		zend_hash_str_add_new(subpats_ht, ZEND_STRL("MARK"), &val);
 +		zend_hash_str_update(subpats_ht, ZEND_STRL("MARK"), &val);
  	}
+ 	return ZEND_HAS_OOM() ? FAILURE : SUCCESS;
  }

  static void php_do_pcre_match(INTERNAL_FUNCTION_PARAMETERS, bool global) /* {{{ */
diff --cc ext/session/php_session.h
index 2a1d782fd72,0507cfa41d0..e2b7a7e5a7d
--- a/ext/session/php_session.h
+++ b/ext/session/php_session.h
@@@ -179,11 -198,14 +179,13 @@@ typedef struct _php_ps_globals
  	bool rfc1867_enabled; /* session.upload_progress.enabled */
  	bool rfc1867_cleanup; /* session.upload_progress.cleanup */

 -	bool use_strict_mode; /* whether or not PHP accepts unknown session ids */
 -	bool lazy_write; /* omit session write when it is possible */
 -	bool in_save_handler; /* state if session is in save handler or not */
 -	bool set_handler;     /* state if session module i setting handler or not */
 +	bool mod_user_implemented;
 +	bool mod_user_is_open;
 +	bool mod_user_uses_object_methods_as_handlers;
 +	bool use_trans_sid; /* contains the INI value of whether to use trans-sid */
  	bool random_seeded;
 -	zend_string *session_vars; /* serialized original session data */
+
+ 	bool in_rfc1867_update;    /* php_session_rfc1867_update() is running */
  } php_ps_globals;

  typedef php_ps_globals zend_ps_globals;
diff --cc ext/session/session.c
index 701f15309e4,dd2c22e5d6d..cca448b5a41
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@@ -110,17 -111,16 +110,17 @@@ static int my_module_number = 0
  static inline void php_rinit_session_globals(void)
  {
  	/* Do NOT init PS(mod_user_names) here! */
- 	/* TODO: These could be moved to MINIT and removed. These should be initialized by php_rshutdown_session_globals() always when execution is finished. */
  	PS(id) = NULL;
  	PS(session_status) = php_session_none;
 -	PS(in_save_handler) = 0;
 -	PS(set_handler) = 0;
 +	PS(in_save_handler) = false;
 +	PS(set_handler) = false;
  	PS(mod_data) = NULL;
 -	PS(mod_user_is_open) = 0;
 -	PS(define_sid) = 1;
 +	PS(mod_user_is_open) = false;
 +	PS(mod_user_uses_object_methods_as_handlers) = false;
 +	PS(define_sid) = true;
  	PS(session_vars) = NULL;
  	PS(module_number) = my_module_number;
+ 	PS(in_rfc1867_update) = false;
  	ZVAL_UNDEF(&PS(http_session_vars));
  }

@@@ -1014,10 -995,10 +1035,10 @@@ PS_SERIALIZER_DECODE_FUNC(php_serialize
  	zval session_vars;
  	php_unserialize_data_t var_hash;
  	bool result;
 -	zend_string *var_name = ZSTR_INIT_LITERAL("_SESSION", 0);
 +	zend_string *var_name = ZSTR_INIT_LITERAL("_SESSION", false);

  	ZVAL_NULL(&session_vars);
- 	PHP_VAR_UNSERIALIZE_INIT(var_hash);
+ 	php_session_unserialize_init(&var_hash);
  	result = php_var_unserialize(
  		&session_vars, (const unsigned char **)&val, (const unsigned char *)endptr, &var_hash);
  	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
@@@ -1047,8 -1028,9 +1068,8 @@@ PS_SERIALIZER_ENCODE_FUNC(php_binary
  {
  	smart_str buf = {0};
  	php_serialize_data_t var_hash;
 -	PS_ENCODE_VARS;

- 	PHP_VAR_SERIALIZE_INIT(var_hash);
+ 	php_session_serialize_init(&var_hash);

  	PS_ENCODE_LOOP(
  			if (ZSTR_LEN(key) > PS_BIN_MAX) continue;
@@@ -1063,12 -1047,15 +1084,12 @@@

  PS_SERIALIZER_DECODE_FUNC(php_binary)
  {
 -	const char *p;
  	const char *endptr = val + vallen;
 -	zend_string *name;
  	php_unserialize_data_t var_hash;
 -	zval *current, rv;

- 	PHP_VAR_UNSERIALIZE_INIT(var_hash);
+ 	php_session_unserialize_init(&var_hash);

 -	for (p = val; p < endptr; ) {
 +	for (const char *p = val; p < endptr; ) {
  		size_t namelen = ((unsigned char)(*p)) & (~PS_BIN_UNDEF);

  		if (namelen > PS_BIN_MAX || (p + namelen) >= endptr) {
@@@ -1106,8 -1092,9 +1127,8 @@@ PS_SERIALIZER_ENCODE_FUNC(php
  	smart_str buf = {0};
  	php_serialize_data_t var_hash;
  	bool fail = false;
 -	PS_ENCODE_VARS;

- 	PHP_VAR_SERIALIZE_INIT(var_hash);
+ 	php_session_serialize_init(&var_hash);

  	PS_ENCODE_LOOP(
  		smart_str_append(&buf, key);
@@@ -2921,13 -2974,14 +2942,14 @@@ static PHP_GINIT_FUNCTION(ps
  	ps_globals->mod = NULL;
  	ps_globals->serializer = NULL;
  	ps_globals->mod_data = NULL;
+ 	ps_globals->in_rfc1867_update = false;
  	ps_globals->session_status = php_session_none;
  	ps_globals->default_mod = NULL;
 -	ps_globals->mod_user_implemented = 0;
 -	ps_globals->mod_user_class_name = NULL;
 -	ps_globals->mod_user_is_open = 0;
 +	ps_globals->mod_user_implemented = false;
 +	ps_globals->mod_user_is_open = false;
 +	ps_globals->mod_user_uses_object_methods_as_handlers = false;
  	ps_globals->session_vars = NULL;
 -	ps_globals->set_handler = 0;
 +	ps_globals->set_handler = false;
  	ps_globals->session_started_filename = NULL;
  	ps_globals->session_started_lineno = 0;
  	/* Unset user defined handlers */
@@@ -3162,19 -3197,24 +3188,24 @@@ static void php_session_rfc1867_update(
  		Z_TRY_ADDREF(progress->data);
  		zend_hash_update(Z_ARRVAL_P(sess_var), progress->key.s, &progress->data);
  	}
 -	php_session_flush(1);
 +	php_session_flush(true);
+ 	PS(in_rfc1867_update) = false;
  }

 -static void php_session_rfc1867_cleanup(php_session_rfc1867_progress *progress)
 +static void php_session_rfc1867_cleanup(const php_session_rfc1867_progress *progress)
  {
- 	php_session_initialize();
- 	PS(session_status) = php_session_active;
+ 	PS(in_rfc1867_update) = true;
+ 	if (php_session_initialize() == FAILURE || PS(session_status) != php_session_active) {
+ 		PS(in_rfc1867_update) = false;
+ 		return;
+ 	}
  	IF_SESSION_VARS() {
  		zval *sess_var = Z_REFVAL(PS(http_session_vars));
  		SEPARATE_ARRAY(sess_var);
  		zend_hash_del(Z_ARRVAL_P(sess_var), progress->key.s);
  	}
 -	php_session_flush(1);
 +	php_session_flush(true);
+ 	PS(in_rfc1867_update) = false;
  }

  static zend_result php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra)
@@@ -3191,9 -3235,13 +3226,13 @@@

  	progress = PS(rfc1867_progress);

 -	switch(event) {
 +	switch (event) {
  		case MULTIPART_EVENT_START: {
 -			multipart_event_start *data = (multipart_event_start *) event_data;
 +			const multipart_event_start *data = event_data;
+
+ 			/* This runs before RINIT, so we need to clear these early */
+ 			php_rinit_session_globals();
+
  			progress = ecalloc(1, sizeof(php_session_rfc1867_progress));
  			progress->content_length = data->content_length;
  			PS(rfc1867_progress) = progress;
diff --cc ext/simplexml/simplexml.c
index 75d859eea4a,9610b3a0bf1..ca121625775
--- a/ext/simplexml/simplexml.c
+++ b/ext/simplexml/simplexml.c
@@@ -1908,11 -1961,14 +1953,12 @@@ static zend_result sxe_object_cast(zend
  /* {{{ Returns the string content */
  PHP_METHOD(SimpleXMLElement, __toString)
  {
 -	if (zend_parse_parameters_none() == FAILURE) {
 -		RETURN_THROWS();
 -	}
 +	ZEND_PARSE_PARAMETERS_NONE();

- 	zend_result rv = sxe_object_cast_ex(Z_OBJ_P(ZEND_THIS), return_value, IS_STRING);
- 	ZEND_IGNORE_VALUE(rv);
- 	ZEND_ASSERT(rv == SUCCESS);
+ 	if (sxe_object_cast_ex(Z_OBJ_P(ZEND_THIS), return_value, IS_STRING) != SUCCESS) {
+ 		zval_ptr_dtor(return_value);
+ 		RETURN_EMPTY_STRING();
+ 	}
  }
  /* }}} */

diff --cc ext/soap/php_http.c
index e7325ec65b5,dbdafb464be..de6ea06c779
--- a/ext/soap/php_http.c
+++ b/ext/soap/php_http.c
@@@ -1569,13 -1571,16 +1577,16 @@@ static zend_string* get_http_body(php_s
  		}

  	} else if (header_length) {
 -		if (header_length < 0 || header_length >= ZSTR_MAX_LEN) {
 +		if (UNEXPECTED(header_length < 0 || header_length >= ZSTR_MAX_LEN)) {
  			return NULL;
  		}
- 		http_buf = zend_string_alloc(header_length, 0);
+ 		http_buf = zend_string_falloc(header_length, /* persistent */ false, /* fallible */ true);
+ 		if (UNEXPECTED(!http_buf)) {
+ 			return NULL;
+ 		}
  		while (http_buf_size < header_length) {
  			ssize_t len_read = php_stream_read(stream, http_buf->val + http_buf_size, header_length - http_buf_size);
 -			if (len_read <= 0) {
 +			if (UNEXPECTED(len_read <= 0)) {
  				break;
  			}
  			http_buf_size += len_read;
diff --cc ext/soap/tests/gh22585.phpt
index 9d007d012b4,9d007d012b4..38a33ed9abe
--- a/ext/soap/tests/gh22585.phpt
+++ b/ext/soap/tests/gh22585.phpt
@@@ -35,5 -35,5 +35,5 @@@ try
  }
  echo "Done" . PHP_EOL;
  ?>
----EXPECTREGEX--
--(?s)(Done|.*Allowed memory size of \d+ bytes exhausted.*)
++--EXPECTF--
++Fatal error: Allowed memory size of 67108864 bytes exhausted %S(tried to allocate %d bytes) in %s on line %d
diff --cc ext/standard/array.c
index f475eeebf05,84d3863318b..39422639418
--- a/ext/standard/array.c
+++ b/ext/standard/array.c
@@@ -7125,10 -6962,12 +7156,12 @@@ PHP_FUNCTION(array_map
  			}
  		}

- 		array_init_size(return_value, maxlen);
+ 		if (UNEXPECTED(!array_finit_size_packed(return_value, maxlen))) {
 -			efree(array_pos);
+ 			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. */
@@@ -7313,14 -7160,19 +7350,18 @@@ 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();
+ 	}

 -	ZVAL_UNDEF(&chunk);
 -
  	ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_key, str_key, entry) {
  		/* If new chunk, create and initialize it. */
 -		if (Z_TYPE(chunk) == IS_UNDEF) {
 +		if (current == 0) {
+ 			if (ZEND_HAS_OOM()) {
+ 				RETURN_OOM();
+ 			}
  			array_init_size(&chunk, (uint32_t)size);
 +			add_next_index_zval(return_value, &chunk);
  		}

  		/* Add entry to the chunk, preserving keys if necessary. */
diff --cc ext/standard/string.c
index b6b7a6e6487,e6302ed7097..0a05a1ae36f
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@@ -921,7 -918,10 +946,10 @@@ PHPAPI 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(&tmp, positions[i], (positions[i+1] - ZSTR_LEN(delim)) - positions[i]);
 +			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);
  		}
  		efree((void *)positions);
@@@ -5619,12 -5647,12 +5726,16 @@@ PHP_FUNCTION(str_repeat
  	if (ZSTR_LEN(input_str) == 0 || mult == 0)
  		RETURN_EMPTY_STRING();

 +	if (mult == 1) {
 +		RETURN_STR_COPY(input_str);
 +	}
 +
  	/* Initialize the result string */
- 	result = zend_string_safe_alloc(ZSTR_LEN(input_str), mult, 0, 0);
+ 	result = zend_string_safe_falloc(ZSTR_LEN(input_str), mult, 0, /*persistent */ false, /* fallible */ true);
+ 	if (UNEXPECTED(!result)) {
+ 		RETURN_OOM();
+ 	}
+
  	result_len = ZSTR_LEN(input_str) * mult;
  	ZSTR_COPY_CONCAT_PROPERTIES(result, input_str);

@@@ -6283,20 -6292,18 +6402,24 @@@ PHP_FUNCTION(str_split
  	n_reg_segments = ZSTR_LEN(str) / split_length;
  	p = ZSTR_VAL(str);

 -	while (n_reg_segments-- > 0) {
 -		/* Each segment costs a zval plus a zend_string, so stop once over the limit. */
 -		if (ZEND_HAS_OOM()) {
 -			RETURN_OOM();
 +	ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
 +		zval zv;
 +		while (n_reg_segments-- > 0) {
++			/* Each segment costs a zend_string, so stop once over the limit. */
++			if (ZEND_HAS_OOM()) {
++				RETURN_OOM();
++			}
 +			ZEND_ASSERT(split_length > 0);
 +			ZVAL_STRINGL_FAST(&zv, p, split_length);
 +			ZEND_HASH_FILL_ADD(&zv);
 +			p += split_length;
  		}
 -		add_next_index_stringl(return_value, p, split_length);
 -		p += split_length;
 -	}

 -	if (p != (ZSTR_VAL(str) + ZSTR_LEN(str))) {
 -		add_next_index_stringl(return_value, p, (ZSTR_VAL(str) + ZSTR_LEN(str) - p));
 -	}
 +		if (p != (ZSTR_VAL(str) + ZSTR_LEN(str))) {
 +			ZVAL_STRINGL_FAST(&zv, p, (ZSTR_VAL(str) + ZSTR_LEN(str) - p));
 +			ZEND_HASH_FILL_ADD(&zv);
 +		}
 +	} ZEND_HASH_FILL_END();
  }
  /* }}} */

diff --cc ext/standard/tests/strings/str_pad_variation1.phpt
index b0837073d83,1b075448f2f..37368837660
--- a/ext/standard/tests/strings/str_pad_variation1.phpt
+++ b/ext/standard/tests/strings/str_pad_variation1.phpt
@@@ -31,6 -31,6 +31,6 @@@ var_dump( str_pad($input, $php_int_max_
  ?>
  --EXPECTF--
  *** Testing str_pad() function: with large value for for 'pad_length' argument ***
 -str_pad(): Argument #2 ($length) must be of type int, float given
 +TypeError: str_pad(): Argument #2 ($length) must be of type int, float given

- Fatal error: Allowed memory size of %d bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
+ Fatal error: Allowed memory size of 134217728 bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
diff --cc ext/standard/var_unserializer.re
index 6d0fd606c9d,43968dd40c9..89f1c5a1a88
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@@ -265,15 -265,27 +275,15 @@@ PHPAPI void var_destroy(php_unserialize
  			if (Z_EXTRA_P(zv) == VAR_WAKEUP_FLAG) {
  				/* Perform delayed __wakeup calls */
  				if (!delayed_call_failed) {
 -					zval retval;
 -					zend_fcall_info fci;
 -					zend_fcall_info_cache fci_cache;
 -
  					ZEND_ASSERT(Z_TYPE_P(zv) == IS_OBJECT);

 -					fci.size = sizeof(fci);
 -					fci.object = Z_OBJ_P(zv);
 -					fci.retval = &retval;
 -					fci.param_count = 0;
 -					fci.params = NULL;
 -					fci.named_params = NULL;
 -					ZVAL_UNDEF(&fci.function_name);
 -
 -					fci_cache.function_handler = zend_hash_find_ptr(
 -						&fci.object->ce->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
 -					fci_cache.object = fci.object;
 -					fci_cache.called_scope = fci.object->ce;
 +					zend_function *fn = zend_hash_find_ptr(&Z_OBJCE_P(zv)->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
 +					zval retval;

  					BG(serialize_lock)++;
 -					if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval) || ZEND_HAS_OOM()) {
 +					zend_call_known_instance_method(fn, Z_OBJ_P(zv), &retval, 0, NULL);
 +					/* Exception thrown */
- 					if (Z_ISUNDEF(retval)) {
++					if (Z_ISUNDEF(retval) || ZEND_HAS_OOM()) {
  						delayed_call_failed = 1;
  						GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
  					}
@@@ -767,12 -809,19 +806,23 @@@ static inline int object_custom(UNSERIA
  		return 0;
  	}

- 	if (ce->unserialize == NULL) {
+ 	if (keep_payload) {
+ 		/* The class was not resolved (see php_var_unserialize_set_incomplete_classes_only()):
+ 		 * keep the payload verbatim, so that the object serializes back to the same bytes. */
+ 		zval payload;
+
+ 		ZEND_ASSERT(ce == PHP_IC_ENTRY);
+ 		if (UNEXPECTED(!ZVAL_FSTRINGL(&payload, (const char *) *p, datalen))) {
+ 			return 0;
+ 		}
+ 		object_init_ex(rval, ce);
+ 		zend_hash_str_update(Z_OBJPROP_P(rval), MAGIC_MEMBER_SERIALIZED, sizeof(MAGIC_MEMBER_SERIALIZED) - 1, &payload);
+ 	} else if (ce->unserialize == NULL) {
  		zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name));
 +		/* __PHP_Incomplete_Class has no internal state, an empty instance is safe. */
 +		if (ce != PHP_IC_ENTRY) {
 +			return 0;
 +		}
  		object_init_ex(rval, ce);
  	} else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) {
  		return 0;
diff --cc ext/uri/php_uri.c
index f50022aec81,076c9fef88a..5f9a71a51d3
--- a/ext/uri/php_uri.c
+++ b/ext/uri/php_uri.c
@@@ -731,10 -675,15 +731,15 @@@ PHP_METHOD(Uri_Rfc3986_Uri, withFragmen

  static void throw_cannot_recompose_uri_to_string(php_uri_object *object)
  {
+ 	if (ZEND_HAS_OOM()) {
+ 		zend_handle_delayed_oom();
+ 		return;
+ 	}
+
 -	zend_throw_exception_ex(php_uri_ce_error, 0, "Cannot recompose %s to a string", ZSTR_VAL(object->std.ce->name));
 +	zend_throw_exception_ex(php_uri_ce_error, 0, "Cannot recompose %pS to a string", object->std.ce->name);
  }

 -static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, php_uri_object *that_object, zend_object *comparison_mode)
 +static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, php_uri_object *that_object, zend_enum_Uri_UriComparisonMode comparison_mode)
  {
  	php_uri_object *this_object = Z_URI_OBJECT_P(ZEND_THIS);
  	ZEND_ASSERT(this_object->uri != NULL);
@@@ -899,7 -852,10 +904,10 @@@ static void uri_unserialize(INTERNAL_FU

  	uri_object->uri = uri_object->parser->parse(Z_STRVAL_P(uri_zv), Z_STRLEN_P(uri_zv), NULL, NULL, true);
  	if (uri_object->uri == NULL) {
+ 		if (ZEND_HAS_OOM()) {
+ 			RETURN_THROWS();
+ 		}
 -		zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name));
 +		zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %pS object", uri_object->std.ce->name);
  		RETURN_THROWS();
  	}

diff --cc ext/uri/php_uri_common.c
index 030f029ff65,5b2b708710f..34906ee89c6
--- a/ext/uri/php_uri_common.c
+++ b/ext/uri/php_uri_common.c
@@@ -68,7 -52,11 +68,11 @@@ void php_uri_property_read_helper(INTER
  	const php_uri_property_handler *property_handler = php_uri_parser_property_handler_by_name(uri_object->parser, property_name);

  	if (UNEXPECTED(property_handler->read(uri_object->uri, component_read_mode, return_value) == FAILURE)) {
+ 		if (ZEND_HAS_OOM()) {
+ 			zend_handle_delayed_oom();
+ 			RETURN_THROWS();
+ 		}
 -		zend_throw_exception_ex(php_uri_ce_error, 0, "The %s component cannot be retrieved", ZSTR_VAL(get_known_string_by_property_name(property_name)));
 +		zend_throw_exception_ex(php_uri_ce_error, 0, "The %pS component cannot be retrieved", get_known_string_by_property_name(property_name));
  		RETURN_THROWS();
  	}
  }
diff --cc ext/uri/uri_parser_rfc3986.c
index 48fcb236e8b,d56d053aae5..1a936a273ed
--- a/ext/uri/uri_parser_rfc3986.c
+++ b/ext/uri/uri_parser_rfc3986.c
@@@ -77,21 -87,27 +87,32 @@@ static inline bool has_text_range(cons
  	return range->first != NULL && range->afterLast != NULL;
  }

- ZEND_ATTRIBUTE_NONNULL static void copy_uri(UriUriA *new_uriparser_uri, const UriUriA *uriparser_uri)
+ /* Returns false when the copy could not be allocated. */
+ ZEND_ATTRIBUTE_NONNULL static bool copy_uri(UriUriA *new_uriparser_uri, const UriUriA *uriparser_uri)
  {
  	int result = uriCopyUriMmA(new_uriparser_uri, uriparser_uri, mm);
- 	ZEND_ASSERT(result == URI_SUCCESS);
+ 	ZEND_ASSERT(result == URI_SUCCESS || result == URI_ERROR_MALLOC);
+
+ 	return result == URI_SUCCESS;
  }

+ /* Returns NULL when the normalized form could not be allocated. */
  ZEND_ATTRIBUTE_NONNULL static UriUriA *get_normalized_uri(php_uri_parser_rfc3986_uris *uriparser_uris) {
  	if (!uriparser_uris->normalized_uri_initialized) {
 -		if (UNEXPECTED(!copy_uri(&uriparser_uris->normalized_uri, &uriparser_uris->uri))) {
 -			return NULL;
 -		}
 -		int result = uriNormalizeSyntaxExMmA(&uriparser_uris->normalized_uri, (unsigned int)-1, mm);
 -		ZEND_ASSERT(result == URI_SUCCESS || result == URI_ERROR_MALLOC);
 -		if (UNEXPECTED(result != URI_SUCCESS)) {
 -			uriFreeUriMembersMmA(&uriparser_uris->normalized_uri, mm);
 -			memset(&uriparser_uris->normalized_uri, 0, sizeof(uriparser_uris->normalized_uri));
 -			return NULL;
 +		int mask_result = uriNormalizeSyntaxMaskRequiredExA(&uriparser_uris->uri, &uriparser_uris->normalization_mask);
 +		ZEND_ASSERT(mask_result == URI_SUCCESS);
 +
 +		if (uriparser_uris->normalization_mask != URI_NORMALIZED) {
- 			copy_uri(&uriparser_uris->normalized_uri, &uriparser_uris->uri);
++			if (UNEXPECTED(!copy_uri(&uriparser_uris->normalized_uri, &uriparser_uris->uri))) {
++				return NULL;
++			}
 +			int result = uriNormalizeSyntaxExMmA(&uriparser_uris->normalized_uri, uriparser_uris->normalization_mask, mm);
- 			ZEND_ASSERT(result == URI_SUCCESS);
++			ZEND_ASSERT(result == URI_SUCCESS || result == URI_ERROR_MALLOC);
++			if (UNEXPECTED(result != URI_SUCCESS)) {
++				uriFreeUriMembersMmA(&uriparser_uris->normalized_uri, mm);
++				memset(&uriparser_uris->normalized_uri, 0, sizeof(uriparser_uris->normalized_uri));
++				return NULL;
++			}
  		}
  		uriparser_uris->normalized_uri_initialized = true;
  	}
@@@ -121,28 -133,12 +142,31 @@@ ZEND_ATTRIBUTE_NONNULL static UriUriA *
  	return &uriparser_uris->uri;
  }

 -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_scheme_read(void *uri, php_uri_component_read_mode read_mode, zval *retval)
 +ZEND_ATTRIBUTE_NONNULL void php_uri_parser_rfc3986_uri_type_read(php_uri_parser_rfc3986_uris *uri, zval *retval)
 +{
 +	const UriUriA *uriparser_uri = get_uri_for_reading(uri, PHP_URI_COMPONENT_READ_MODE_RAW);
 +
 +	zend_object *value;
 +
 +	if (has_text_range(&uriparser_uri->scheme)) {
 +		value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_type, ZEND_ENUM_Uri_Rfc3986_UriType_Uri);
 +	} else if (has_text_range(&uriparser_uri->hostText)) {
 +		value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_type, ZEND_ENUM_Uri_Rfc3986_UriType_NetworkPathReference);
 +	} else if (uriparser_uri->absolutePath) {
 +		value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_type, ZEND_ENUM_Uri_Rfc3986_UriType_AbsolutePathReference);
 +	} else {
 +		value = zend_enum_get_case_by_id(php_uri_ce_rfc3986_uri_type, ZEND_ENUM_Uri_Rfc3986_UriType_RelativePathReference);
 +	}
 +
 +	ZVAL_OBJ_COPY(retval, value);
 +}
 +
 +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_scheme_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval)
  {
  	const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode);
+ 	if (UNEXPECTED(uriparser_uri == NULL)) {
+ 		return FAILURE;
+ 	}

  	if (has_text_range(&uriparser_uri->scheme)) {
  		ZVAL_STRINGL(retval, uriparser_uri->scheme.first, get_text_range_length(&uriparser_uri->scheme));
@@@ -177,9 -177,12 +205,12 @@@ static zend_result php_uri_parser_rfc39
  	}
  }

 -ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_userinfo_read(void *uri, php_uri_component_read_mode read_mode, zval *retval)
 +ZEND_ATTRIBUTE_NONNULL zend_result php_uri_parser_rfc3986_userinfo_read(php_uri_parser_rfc3986_uris *uri, const php_uri_component_read_mode read_mode, zval *retval)
  {
  	const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode);
+ 	if (UNEXPECTED(uriparser_uri == NULL)) {
+ 		return FAILURE;
+ 	}

  	if (has_text_range(&uriparser_uri->userInfo)) {
  		ZVAL_STRINGL(retval, uriparser_uri->userInfo.first, get_text_range_length(&uriparser_uri->userInfo));
@@@ -217,9 -224,12 +252,12 @@@ zend_result php_uri_parser_rfc3986_user
  	}
  }

 -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_username_read(void *uri, php_uri_component_read_mode read_mode, zval *retval)
 +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_username_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval)
  {
  	const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode);
+ 	if (UNEXPECTED(uriparser_uri == NULL)) {
+ 		return FAILURE;
+ 	}

  	if (has_text_range(&uriparser_uri->userInfo)) {
  		size_t length = get_text_range_length(&uriparser_uri->userInfo);
@@@ -239,9 -249,12 +277,12 @@@
  	return SUCCESS;
  }

 -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_password_read(void *uri, php_uri_component_read_mode read_mode, zval *retval)
 +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_password_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval)
  {
  	const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode);
+ 	if (UNEXPECTED(uriparser_uri == NULL)) {
+ 		return FAILURE;
+ 	}

  	if (has_text_range(&uriparser_uri->userInfo)) {
  		const char *c = memchr(uriparser_uri->userInfo.first, ':', get_text_range_length(&uriparser_uri->userInfo));
@@@ -258,9 -271,12 +299,12 @@@
  	return SUCCESS;
  }

 -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_host_read(void *uri, php_uri_component_read_mode read_mode, zval *retval)
 +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_host_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval)
  {
  	const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode);
+ 	if (UNEXPECTED(uriparser_uri == NULL)) {
+ 		return FAILURE;
+ 	}

  	if (has_text_range(&uriparser_uri->hostText)) {
  		if (uriparser_uri->hostData.ip6 != NULL || uriparser_uri->hostData.ipFuture.first != NULL) {
@@@ -353,9 -350,12 +401,12 @@@ ZEND_ATTRIBUTE_NONNULL static zend_lon
  	return (zend_long)result;
  }

 -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_port_read(void *uri, php_uri_component_read_mode read_mode, zval *retval)
 +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_port_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval)
  {
  	const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode);
+ 	if (UNEXPECTED(uriparser_uri == NULL)) {
+ 		return FAILURE;
+ 	}

  	if (has_text_range(&uriparser_uri->portText) && get_text_range_length(&uriparser_uri->portText) > 0) {
  		ZVAL_LONG(retval, port_str_to_zend_long_checked(uriparser_uri->portText.first, get_text_range_length(&uriparser_uri->portText)));
@@@ -395,30 -399,18 +450,33 @@@ static zend_result php_uri_parser_rfc39
  	}
  }

 -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_path_read(void *uri, php_uri_component_read_mode read_mode, zval *retval)
 +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_path_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval)
  {
  	const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode);
+ 	if (UNEXPECTED(uriparser_uri == NULL)) {
+ 		return FAILURE;
+ 	}

  	if (uriparser_uri->pathHead != NULL) {
 -		smart_str str = {0};
 +		size_t total_len = 0;
 +		const bool need_leading_slash = uriparser_uri->absolutePath || uriHasHostA(uriparser_uri);
 +
 +		if (need_leading_slash) {
 +			total_len++;
 +		}

 -		if (uriparser_uri->absolutePath || uriHasHostA(uriparser_uri)) {
 -			smart_str_appendc(&str, '/');
 +		for (const UriPathSegmentA *p = uriparser_uri->pathHead; p; p = p->next) {
 +			total_len += get_text_range_length(&p->text);
 +			if (p->next) {
 +				total_len++;
 +			}
 +		}
 +
 +		zend_string *str = zend_string_alloc(total_len, false);
 +		char *out = ZSTR_VAL(str);
 +
 +		if (need_leading_slash) {
 +			*(out++) = '/';
  		}

  		for (const UriPathSegmentA *p = uriparser_uri->pathHead; p; p = p->next) {
@@@ -463,9 -458,12 +525,12 @@@ static zend_result php_uri_parser_rfc39
  	}
  }

 -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_query_read(void *uri, php_uri_component_read_mode read_mode, zval *retval)
 +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_query_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval)
  {
  	const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode);
+ 	if (UNEXPECTED(uriparser_uri == NULL)) {
+ 		return FAILURE;
+ 	}

  	if (has_text_range(&uriparser_uri->query)) {
  		ZVAL_STRINGL(retval, uriparser_uri->query.first, get_text_range_length(&uriparser_uri->query));
@@@ -500,9 -502,12 +569,12 @@@ static zend_result php_uri_parser_rfc39
  	}
  }

 -ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_fragment_read(void *uri, php_uri_component_read_mode read_mode, zval *retval)
 +ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_fragment_read(void *uri, const php_uri_component_read_mode read_mode, zval *retval)
  {
  	const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode);
+ 	if (UNEXPECTED(uriparser_uri == NULL)) {
+ 		return FAILURE;
+ 	}

  	if (has_text_range(&uriparser_uri->fragment)) {
  		ZVAL_STRINGL(retval, uriparser_uri->fragment.first, get_text_range_length(&uriparser_uri->fragment));
@@@ -545,37 -554,14 +621,37 @@@ static php_uri_parser_rfc3986_uris *uri
  	return uriparser_uris;
  }

 -php_uri_parser_rfc3986_uris *php_uri_parser_rfc3986_parse_ex(const char *uri_str, size_t uri_str_len, const php_uri_parser_rfc3986_uris *uriparser_base_urls, bool silent)
 +static zend_result php_uri_parser_rfc3986_add_base_url(
 +	UriUriA *tmp, const UriUriA *uri, const php_uri_parser_rfc3986_uris *uriparser_base_urls, const bool silent
 +) {
 +	const int result = uriAddBaseUriExMmA(tmp, uri, &uriparser_base_urls->uri, URI_RESOLVE_STRICTLY, mm);
 +	if (result != URI_SUCCESS) {
- 		if (!silent) {
++		if (!handle_pending_oom() && !silent) {
 +			switch (result) {
 +				case URI_ERROR_ADDBASE_REL_BASE:
 +					zend_throw_exception(php_uri_ce_invalid_uri_exception, "The specified base URI must be absolute", 0);
 +					break;
 +				default:
 +					/* This should be unreachable in practice. */
 +					zend_throw_exception(php_uri_ce_error, "Failed to resolve the specified URI against the base URI", 0);
 +					break;
 +			}
 +		}
 +
 +		return FAILURE;
 +	}
 +
 +	return SUCCESS;
 +}
 +
 +php_uri_parser_rfc3986_uris *php_uri_parser_rfc3986_parse_ex(const char *uri_str, const size_t uri_str_len, const php_uri_parser_rfc3986_uris *uriparser_base_urls, const bool silent)
  {
  	UriUriA uri = {0};

  	/* Parse the URI. */
 -	int result = uriParseSingleUriExMmA(&uri, uri_str, uri_str + uri_str_len, NULL, mm);
 +	const int result = uriParseSingleUriExMmA(&uri, uri_str, uri_str + uri_str_len, NULL, mm);
  	if (result != URI_SUCCESS) {
- 		if (!silent) {
+ 		if (!handle_pending_oom() && !silent) {
  			switch (result) {
  				case URI_ERROR_SYNTAX:
  					zend_throw_exception(php_uri_ce_invalid_uri_exception, "The specified URI is malformed", 0);
diff --cc ext/uri/uri_parser_whatwg.c
index 079bbb84e7b,32988d5929b..2a4457e3dc9
--- a/ext/uri/uri_parser_whatwg.c
+++ b/ext/uri/uri_parser_whatwg.c
@@@ -41,173 -42,202 +41,187 @@@ ZEND_ATTRIBUTE_NONNULL static zend_alwa
  	}
  }

- ZEND_ATTRIBUTE_NONNULL static zend_always_inline void zval_long_or_null_to_lexbor_str(const zval *value, lexbor_str_t *lexbor_str)
 -static zend_always_inline bool zval_long_or_null_to_lexbor_str(zval *value, lexbor_str_t *lexbor_str)
++static zend_always_inline bool zval_long_or_null_to_lexbor_str(const zval *value, lexbor_str_t *lexbor_str)
  {
  	if (Z_TYPE_P(value) == IS_LONG) {
 -		ZVAL_STR(value, zend_long_to_str(Z_LVAL_P(value)));
 -		const lxb_char_t *appended = lexbor_str_init_append(lexbor_str, lexbor_parser.mraw, (const lxb_char_t *) Z_STRVAL_P(value), Z_STRLEN_P(value));
 -		zval_ptr_dtor_str(value);
 +		char buf[MAX_LENGTH_OF_LONG + 1];
 +		const char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, Z_LVAL_P(value));
- 		lexbor_str_init_append(lexbor_str, lexbor_parser.mraw, (const lxb_char_t *) res, strlen(res));
++		const lxb_char_t *appended = lexbor_str_init_append(lexbor_str, lexbor_parser.mraw, (const lxb_char_t *) res, strlen(res));
+ 		if (UNEXPECTED(appended == NULL)) {
+ 			return false;
+ 		}
  	} else {
  		ZEND_ASSERT(Z_ISNULL_P(value));
  		lexbor_str->data = (lxb_char_t *) "";
  		lexbor_str->length = 0;
  	}
+
+ 	return true;
  }

 +ZEND_ATTRIBUTE_NONNULL static bool get_reason_from_error_type(const lxb_url_error_type_t error_type, const char **error_str)
 +{
 +	switch (error_type) {
 +		case LXB_URL_ERROR_TYPE_DOMAIN_TO_ASCII:
 +			*error_str = "DomainToAscii";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_DOMAIN_TO_UNICODE:
 +			*error_str = "DomainToUnicode";
 +			return false;
 +		case LXB_URL_ERROR_TYPE_DOMAIN_INVALID_CODE_POINT:
 +			*error_str = "DomainInvalidCodePoint";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_HOST_INVALID_CODE_POINT:
 +			*error_str = "HostInvalidCodePoint";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV4_EMPTY_PART:
 +			*error_str = "Ipv4EmptyPart";
 +			return false;
 +		case LXB_URL_ERROR_TYPE_IPV4_TOO_MANY_PARTS:
 +			*error_str = "Ipv4TooManyParts";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV4_NON_NUMERIC_PART:
 +			*error_str = "Ipv4NonNumericPart";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV4_NON_DECIMAL_PART:
 +			*error_str = "Ipv4NonDecimalPart";
 +			return false;
 +		case LXB_URL_ERROR_TYPE_IPV4_OUT_OF_RANGE_PART:
 +			*error_str = "Ipv4OutOfRangePart";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV6_UNCLOSED:
 +			*error_str = "Ipv6Unclosed";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV6_INVALID_COMPRESSION:
 +			*error_str = "Ipv6InvalidCompression";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV6_TOO_MANY_PIECES:
 +			*error_str = "Ipv6TooManyPieces";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV6_MULTIPLE_COMPRESSION:
 +			*error_str = "Ipv6MultipleCompression";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV6_INVALID_CODE_POINT:
 +			*error_str = "Ipv6InvalidCodePoint";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV6_TOO_FEW_PIECES:
 +			*error_str = "Ipv6TooFewPieces";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_MANY_PIECES:
 +			*error_str = "Ipv4InIpv6TooManyPieces";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_INVALID_CODE_POINT:
 +			*error_str = "Ipv4InIpv6InvalidCodePoint";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_OUT_OF_RANGE_PART:
 +			*error_str = "Ipv4InIpv6OutOfRangePart";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_FEW_PARTS:
 +			*error_str = "Ipv4InIpv6TooFewParts";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_INVALID_URL_UNIT:
 +			*error_str = "InvalidUrlUnit";
 +			return false;
 +		case LXB_URL_ERROR_TYPE_SPECIAL_SCHEME_MISSING_FOLLOWING_SOLIDUS:
 +			*error_str = "SpecialSchemeMissingFollowingSolidus";
 +			return false;
 +		case LXB_URL_ERROR_TYPE_MISSING_SCHEME_NON_RELATIVE_URL:
 +			*error_str = "MissingSchemeNonRelativeUrl";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_INVALID_REVERSE_SOLIDUS:
 +			*error_str = "InvalidReverseSoldius";
 +			return false;
 +		case LXB_URL_ERROR_TYPE_INVALID_CREDENTIALS:
 +			*error_str = "InvalidCredentials";
 +			return false;
 +		case LXB_URL_ERROR_TYPE_HOST_MISSING:
 +			*error_str = "HostMissing";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_PORT_OUT_OF_RANGE:
 +			*error_str = "PortOutOfRange";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_PORT_INVALID:
 +			*error_str = "PortInvalid";
 +			return true;
 +		case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER:
 +			*error_str = "FileInvalidWindowsDriveLetter";
 +			return false;
 +		case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST:
 +			*error_str = "FileInvalidWindowsDriveLetterHost";
 +			return false;
 +		default: ZEND_UNREACHABLE();
 +	}
 +}
 +
 +ZEND_ATTRIBUTE_NONNULL static bool append_validation_error(
 +	HashTable *errors, lxb_url_error_type_t error_type, const char *context, const char **reason
 +) {
 +	zval error;
 +	object_init_ex(&error, php_uri_ce_whatwg_url_validation_error);
 +	zend_update_property_string(php_uri_ce_whatwg_url_validation_error, Z_OBJ(error), ZEND_STRL("context"), context);
 +
 +	bool failure = get_reason_from_error_type(error_type, reason);
 +	zval type;
 +	ZVAL_OBJ(&type, zend_enum_get_case_cstr(php_uri_ce_whatwg_url_validation_error_type, *reason));
 +	zend_update_property_ex(php_uri_ce_whatwg_url_validation_error, Z_OBJ(error), ZSTR_KNOWN(ZEND_STR_TYPE), &type);
 +	zend_update_property_bool(php_uri_ce_whatwg_url_validation_error, Z_OBJ(error), ZEND_STRL("failure"), failure);
 +	zend_hash_next_index_insert(errors, &error);
 +
 +	return failure;
 +}
 +
  /**
   * Creates a Uri\WhatWg\UrlValidationError class by mapping error codes listed in
   * https://url.spec.whatwg.org/#writing to a Uri\WhatWg\UrlValidationErrorType enum.
   * The result is passed by reference to the errors parameter.
   */
 -static const char *fill_errors(zval *errors)
 +ZEND_ATTRIBUTE_NONNULL static const char *fill_errors_inner(HashTable *errors)
  {
 -	if (lexbor_parser.log == NULL || lexbor_plog_length(lexbor_parser.log) == 0) {
 -		ZVAL_EMPTY_ARRAY(errors);
 -		return NULL;
 -	}
 -
 -	array_init(errors);
  	const char *result = NULL;
 -
 -	lexbor_plog_entry_t *lxb_error;
 -	while ((lxb_error = lexbor_array_obj_pop(&lexbor_parser.log->list)) != NULL) {
 -		zval error;
 -		object_init_ex(&error, php_uri_ce_whatwg_url_validation_error);
 -		zend_update_property_string(php_uri_ce_whatwg_url_validation_error, Z_OBJ(error), ZEND_STRL("context"), (const char *) lxb_error->data);
 -
 -		const char *error_str;
 -		zval failure;
 -		switch (lxb_error->id) {
 -			case LXB_URL_ERROR_TYPE_DOMAIN_TO_ASCII:
 -				error_str = "DomainToAscii";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_DOMAIN_TO_UNICODE:
 -				error_str = "DomainToUnicode";
 -				ZVAL_FALSE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_DOMAIN_INVALID_CODE_POINT:
 -				error_str = "DomainInvalidCodePoint";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_HOST_INVALID_CODE_POINT:
 -				error_str = "HostInvalidCodePoint";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV4_EMPTY_PART:
 -				error_str = "Ipv4EmptyPart";
 -				ZVAL_FALSE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV4_TOO_MANY_PARTS:
 -				error_str = "Ipv4TooManyParts";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV4_NON_NUMERIC_PART:
 -				error_str = "Ipv4NonNumericPart";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV4_NON_DECIMAL_PART:
 -				error_str = "Ipv4NonDecimalPart";
 -				ZVAL_FALSE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV4_OUT_OF_RANGE_PART:
 -				error_str = "Ipv4OutOfRangePart";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV6_UNCLOSED:
 -				error_str = "Ipv6Unclosed";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV6_INVALID_COMPRESSION:
 -				error_str = "Ipv6InvalidCompression";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV6_TOO_MANY_PIECES:
 -				error_str = "Ipv6TooManyPieces";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV6_MULTIPLE_COMPRESSION:
 -				error_str = "Ipv6MultipleCompression";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV6_INVALID_CODE_POINT:
 -				error_str = "Ipv6InvalidCodePoint";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV6_TOO_FEW_PIECES:
 -				error_str = "Ipv6TooFewPieces";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_MANY_PIECES:
 -				error_str = "Ipv4InIpv6TooManyPieces";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_INVALID_CODE_POINT:
 -				error_str = "Ipv4InIpv6InvalidCodePoint";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_OUT_OF_RANGE_PART:
 -				error_str = "Ipv4InIpv6OutOfRangePart";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_IPV4_IN_IPV6_TOO_FEW_PARTS:
 -				error_str = "Ipv4InIpv6TooFewParts";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_INVALID_URL_UNIT:
 -				error_str = "InvalidUrlUnit";
 -				ZVAL_FALSE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_SPECIAL_SCHEME_MISSING_FOLLOWING_SOLIDUS:
 -				error_str = "SpecialSchemeMissingFollowingSolidus";
 -				ZVAL_FALSE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_MISSING_SCHEME_NON_RELATIVE_URL:
 -				error_str = "MissingSchemeNonRelativeUrl";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_INVALID_REVERSE_SOLIDUS:
 -				error_str = "InvalidReverseSoldius";
 -				ZVAL_FALSE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_INVALID_CREDENTIALS:
 -				error_str = "InvalidCredentials";
 -				ZVAL_FALSE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_HOST_MISSING:
 -				error_str = "HostMissing";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_PORT_OUT_OF_RANGE:
 -				error_str = "PortOutOfRange";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_PORT_INVALID:
 -				error_str = "PortInvalid";
 -				ZVAL_TRUE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER:
 -				error_str = "FileInvalidWindowsDriveLetter";
 -				ZVAL_FALSE(&failure);
 -				break;
 -			case LXB_URL_ERROR_TYPE_FILE_INVALID_WINDOWS_DRIVE_LETTER_HOST:
 -				error_str = "FileInvalidWindowsDriveLetterHost";
 -				ZVAL_FALSE(&failure);
 -				break;
 -			EMPTY_SWITCH_DEFAULT_CASE()
 -		}
 -
 -		zval error_type;
 -		ZVAL_OBJ(&error_type, zend_enum_get_case_cstr(php_uri_ce_whatwg_url_validation_error_type, error_str));
 -		zend_update_property_ex(php_uri_ce_whatwg_url_validation_error, Z_OBJ(error), ZSTR_KNOWN(ZEND_STR_TYPE), &error_type);
 -
 -		zend_update_property(php_uri_ce_whatwg_url_validation_error, Z_OBJ(error), ZEND_STRL("failure"), &failure);
 -
 -		if (Z_TYPE(failure) == IS_TRUE) {
 -			result = error_str;
 +	lexbor_plog_t *log = lexbor_parser.log;
 +	const size_t length = lexbor_plog_length(log);
 +
 +	for (size_t i = 0; i < length; i++) {
 +		const lexbor_plog_entry_t *lxb_error = lexbor_array_obj_get(&log->list, i);
 +		const char *reason;
 +		if (append_validation_error(errors, lxb_error->id, (const char *) lxb_error->data, &reason) && result == NULL) {
 +			result = reason;
  		}
+
 -		add_next_index_zval(errors, &error);
 -
+ 		if (ZEND_HAS_OOM()) {
+ 			break;
+ 		}
  	}
 +	lexbor_plog_clean(log);

  	return result;
  }

 -static void throw_invalid_url_exception_during_write(zval *errors, const char *component)
 +/**
 + * Creates a Uri\WhatWg\UrlValidationError class by mapping error codes listed in
 + * https://url.spec.whatwg.org/#writing to a Uri\WhatWg\UrlValidationErrorType enum.
 + * The result is passed by reference to the errors parameter.
 + */
 +ZEND_ATTRIBUTE_NONNULL static const char *fill_errors(zval *errors)
  {
 -	if (ZEND_HAS_OOM()) {
 -		zend_handle_delayed_oom();
 -		return;
 +	size_t log_len;
 +	if (lexbor_parser.log == NULL || (log_len = lexbor_plog_length(lexbor_parser.log)) == 0) {
 +		ZVAL_EMPTY_ARRAY(errors);
 +		return NULL;
  	}

 -	zval err;
 -	const char *reason = fill_errors(&err);
 +	array_init_size(errors, log_len);
 +
 +	return fill_errors_inner(Z_ARRVAL_P(errors));
 +}
 +
 +static void throw_invalid_url_exception_with_reason(zval *errors, const char *component, const char *reason, zval *err)
 +{
+ 	if (ZEND_HAS_OOM()) {
 -		zval_ptr_dtor(&err);
+ 		zend_handle_delayed_oom();
+ 		return;
+ 	}
+
  	zend_object *exception = zend_throw_exception_ex(
  		php_uri_ce_whatwg_invalid_url_exception,
  		0,
@@@ -659,9 -678,14 +701,14 @@@ static zend_string *php_uri_parser_what
  		case PHP_URI_RECOMPOSITION_MODE_NORMALIZED_ASCII:
  			lxb_url_serialize(lexbor_uri, serialize_to_smart_str_callback, &uri_str, exclude_fragment);
  			break;
 -		EMPTY_SWITCH_DEFAULT_CASE()
 +		default: ZEND_UNREACHABLE();
  	}

+ 	if (ZEND_HAS_OOM()) {
+ 		smart_str_free(&uri_str);
+ 		return NULL;
+ 	}
+
  	return smart_str_extract(&uri_str);
  }

diff --cc ext/xml/compat.c
index 10bfa19af7a,19577ce17a8..52723fb7e4b
--- a/ext/xml/compat.c
+++ b/ext/xml/compat.c
@@@ -101,14 -100,14 +101,23 @@@ start_element_handler_ns(void *user, co
  		for (i = 0; i < nb_attributes; i += 1) {

  			if (attributes[y+1] != NULL) {
 -				qualify_namespace(parser, attributes[y] , attributes[y + 2], &qualified_name_attr);
 +				qualified_name_attr = qualify_namespace(parser, attributes[y] , attributes[y + 2]);
  			} else {
 -				qualified_name_attr = xmlStrdup(attributes[y]);
 +				qualified_name_attr = BAD_CAST estrdup((const char *) attributes[y]);
  			}
  			attrs[z] = qualified_name_attr;
 -			attrs[z + 1] = xmlStrndup(attributes[y + 3] , (int) (attributes[y + 4] - attributes[y + 3]));
 +			attrs[z + 1] = BAD_CAST estrndup((const char *) attributes[y + 3], attributes[y + 4] - attributes[y + 3]);
  			z += 2;
  			y += 5;
++
++			if (ZEND_HAS_OOM()) {
++				for (i = 0; i < z; i++) {
++					efree(attrs[i]);
++				}
++				efree(attrs);
++				efree(qualified_name);
++				return;
++			}
  		}

  		attrs[z] = NULL;
diff --cc ext/xml/xml.c
index 6d7a54d2d7c,a20292833cc..16a95fcbee9
--- a/ext/xml/xml.c
+++ b/ext/xml/xml.c
@@@ -642,6 -666,14 +651,13 @@@ void xml_startElementHandler(void *user
  			attributes += 2;

  			zend_string_release_ex(att, 0);
+
+ 			if (ZEND_HAS_OOM()) {
+ 				zend_string_release_ex(tag_name, false);
 -				zval_ptr_dtor(&args[0]);
+ 				zval_ptr_dtor(&args[1]);
+ 				zval_ptr_dtor(&args[2]);
+ 				return;
+ 			}
  		}

  		zend_call_known_fcc(&parser->startElementHandler, /* retval */ NULL, /* param_count */ 3, args, /* named_params */ NULL);
@@@ -784,9 -829,13 +811,13 @@@ void xml_characterDataHandler(void *use
  		return;
  	}

+ 	if (UNEXPECTED(xml_handler_aborted())) {
+ 		return;
+ 	}
+
  	if (ZEND_FCC_INITIALIZED(parser->characterDataHandler)) {
  		zval args[2];
 -		ZVAL_COPY(&args[0], &parser->index);
 +		ZVAL_OBJ(&args[0], &parser->std);
  		xml_xmlchar_zval(s, len, parser->target_encoding, &args[1]);

  		zend_call_known_fcc(&parser->characterDataHandler, /* retval */ NULL, /* param_count */ 2, args, /* named_params */ NULL);
diff --cc ext/zend_test/test.c
index ba39696e319,400a2413a8a..4867f2f41c6
--- a/ext/zend_test/test.c
+++ b/ext/zend_test/test.c
@@@ -32,8 -36,9 +32,10 @@@
  #include "zend_weakrefs.h"
  #include "Zend/Optimizer/zend_optimizer.h"
  #include "Zend/zend_alloc.h"
+ #include "SAPI.h"
+ #include "rfc1867.h"
  #include "test_arginfo.h"
 +#include "tmp_methods_arginfo.h"
  #include "zend_call_stack.h"
  #include "zend_exceptions.h"
  #include "zend_system_id.h"
@@@ -1672,32 -1115,129 +1712,149 @@@ static ZEND_FUNCTION(zend_test_log_err_
  	php_log_err_with_severity(ZSTR_VAL(str), LOG_DEBUG);
  }

 +typedef struct _zend_test_object {
 +	zend_internal_function *tmp_method;
 +	zend_object std;
 +} zend_test_object;
 +
+ static php_stream *zend_test_post_stream = NULL;
+
+ /* Give the POST handler a fresh $_POST or $_FILES to fill in. A request parses
+  * its body before creating the auto globals, so the handler expects an array
+  * that nothing else holds a reference to yet. */
+ static void zend_test_reset_track_vars(int track_vars, const char *name, size_t name_len)
+ {
+ 	/* Create the auto global first, so that it is not created, and reset, on
+ 	 * first access after this. */
+ 	zend_is_auto_global_str(name, name_len);
+
+ 	zval *zv = &PG(http_globals)[track_vars];
+
+ 	zval_ptr_dtor_nogc(zv);
+ 	array_init(zv);
+ }
+
+ /* Point $_POST or $_FILES at the array the POST handler filled in. */
+ static void zend_test_publish_track_vars(int track_vars, const char *name, size_t name_len)
+ {
+ 	zval *zv = &PG(http_globals)[track_vars];
+
+ 	zend_hash_str_update(&EG(symbol_table), name, name_len, zv);
+ 	Z_ADDREF_P(zv);
+ }
+
+ static size_t zend_test_read_post(char *buffer, size_t count_bytes)
+ {
+ 	ssize_t read_bytes = php_stream_read(zend_test_post_stream, buffer, count_bytes);
+
+ 	return read_bytes > 0 ? (size_t) read_bytes : 0;
+ }
+
+ /* Run the POST handler registered for the content type over the contents of a
+  * stream, as if that stream were the body of the current request. */
+ static ZEND_FUNCTION(zend_test_handle_post_data)
+ {
+ 	zval *stream_zv;
+ 	char *content_type;
+ 	size_t content_type_len;
+ 	zend_long content_length;
+ 	php_stream *stream;
+
+ 	ZEND_PARSE_PARAMETERS_START(3, 3)
+ 		Z_PARAM_RESOURCE(stream_zv);
+ 		Z_PARAM_STRING(content_type, content_type_len);
+ 		Z_PARAM_LONG(content_length);
+ 	ZEND_PARSE_PARAMETERS_END();
+
+ 	php_stream_from_zval(stream, stream_zv);
+
+ 	zend_test_reset_track_vars(TRACK_VARS_POST, ZEND_STRL("_POST"));
+ 	zend_test_reset_track_vars(TRACK_VARS_FILES, ZEND_STRL("_FILES"));
+
+ 	/* Tear down what a previous call set up, as the request shutdown would. */
+ 	if (SG(rfc1867_uploaded_files)) {
+ 		destroy_uploaded_files_hash();
+ 	}
+
+ 	php_stream *old_stream = zend_test_post_stream;
+ 	size_t (*old_read_post)(char *buffer, size_t count_bytes) = sapi_module.read_post;
+ 	sapi_request_info old_request_info = SG(request_info);
+ 	int64_t old_read_post_bytes = SG(read_post_bytes);
+ 	unsigned char old_post_read = SG(post_read);
+
+ 	zend_test_post_stream = stream;
+ 	sapi_module.read_post = zend_test_read_post;
+ 	/* php_default_post_reader() insists on a request method. */
+ 	SG(request_info).request_method = "POST";
+ 	SG(request_info).content_type = content_type;
+ 	SG(request_info).content_length = content_length;
+ 	SG(request_info).content_type_dup = NULL;
+ 	SG(request_info).post_entry = NULL;
+ 	SG(request_info).request_body = NULL;
+ 	SG(read_post_bytes) = 0;
+ 	SG(post_read) = 0;
+
+ 	bool bailed_out = false;
+
+ 	zend_try {
+ 		/* Pick the post handler for the content type, read the body, then run
+ 		 * the handler over it. Anything else is swallowed by the default post
+ 		 * reader, as it would be during a request. */
+ 		sapi_read_post_data();
+ 		sapi_handle_post(&PG(http_globals)[TRACK_VARS_POST]);
+ 	} zend_catch {
+ 		bailed_out = true;
+ 	} zend_end_try();
+
+ 	zend_test_publish_track_vars(TRACK_VARS_POST, ZEND_STRL("_POST"));
+ 	zend_test_publish_track_vars(TRACK_VARS_FILES, ZEND_STRL("_FILES"));
+
+ 	if (SG(request_info).request_body) {
+ 		php_stream_close(SG(request_info).request_body);
+ 	}
+ 	if (SG(request_info).content_type_dup) {
+ 		efree(SG(request_info).content_type_dup);
+ 	}
+
+ 	zend_test_post_stream = old_stream;
+ 	sapi_module.read_post = old_read_post;
+ 	SG(request_info) = old_request_info;
+ 	SG(read_post_bytes) = old_read_post_bytes;
+ 	SG(post_read) = old_post_read;
+
+ 	if (bailed_out) {
+ 		zend_bailout();
+ 	}
+ }
+
+ static ZEND_FUNCTION(zend_new_singleton_array)
+ {
+ 	ZEND_PARSE_PARAMETERS_NONE();
+
+ 	array_init_singleton(return_value);
+ }
+
  static zend_object *zend_test_class_new(zend_class_entry *class_type)
  {
 -	zend_object *obj = zend_objects_new(class_type);
 -	object_properties_init(obj, class_type);
 -	obj->handlers = &zend_test_class_handlers;
 -	return obj;
 +	zend_test_object *intern = zend_object_alloc(sizeof(zend_test_object), class_type);
 +	zend_object_std_init(&intern->std, class_type);
 +	object_properties_init(&intern->std, class_type);
 +	return &intern->std;
 +}
 +
 +static void zend_test_class_free_obj(zend_object *object)
 +{
 +	zend_test_object *intern = ZEND_CONTAINER_OF(object, zend_test_object, std);
 +
 +	if (intern->tmp_method) {
 +		zend_internal_function *func = intern->tmp_method;
 +		intern->tmp_method = NULL;
 +		zend_string_release_ex(func->function_name, 0);
 +		zend_free_internal_arg_info(func, false);
 +		efree(func);
 +	}
 +
 +	zend_object_std_dtor(object);
  }

  static zend_function *zend_test_class_method_get(zend_object **object, zend_string *name, const zval *key)
diff --cc ext/zend_test/test.stub.php
index 1fbacdae109,754ac9a693a..db5ca629ade
--- a/ext/zend_test/test.stub.php
+++ b/ext/zend_test/test.stub.php
@@@ -300,71 -265,10 +300,75 @@@ namespace
      function zend_delref(mixed $variable): void {}

      function zend_test_erealloc_block_size(int $old_size, int $new_size): array {}
 -
 +
 +	function zend_bool(bool $param): bool {}
 +	function zend_bool_or_null(bool|null $param): bool|null {}
 +	function zend_bool_slow_zpp(bool $param): bool {}
 +	function zend_bool_or_null_slow_zpp(bool|null $param): bool|null {}
 +
 +	function zend_int(int $param): int {}
 +	function zend_int_or_null(int|null $param): int|null {}
 +	function zend_int_slow_zpp(int $param): int {}
 +	function zend_int_or_null_slow_zpp(int|null $param): int|null {}
 +
 +	function zend_float(float $param): float {}
 +	function zend_float_or_null(float|null $param): float|null {}
 +	function zend_float_slow_zpp(float $param): float {}
 +	function zend_float_or_null_slow_zpp(float|null $param): float|null {}
 +
 +	function zend_number(int|float $param): int|float {}
 +	function zend_number_or_null(int|float|null $param): int|float|null {}
 +	function zend_number_slow_zpp(int|float $param): int|float {}
 +	function zend_number_or_null_slow_zpp(int|float|null $param): int|float|null {}
 +
 +	function zend_object(object $param): object {}
 +	function zend_object_or_null(object|null $param): object|null {}
 +	function zend_object_slow_zpp(object $param): object {}
 +	function zend_object_or_null_slow_zpp(object|null $param): object|null {}
 +
 +	function zend_obj(object $param): object {}
 +	function zend_obj_or_null(object|null $param): object|null {}
 +
 +	function zend_obj_or_class_name(object|string $param): string {}
 +	function zend_obj_or_class_name_or_null(object|string|null $param): string|null {}
 +
 +	function zend_class_name(string $param): string {}
 +	function zend_class_name_or_null(string|null $param): string|null {}
 +	function zend_class_name_slow_zpp(string $param): string {}
 +	function zend_class_name_or_null_slow_zpp(string|null $param): string|null {}
 +
 +	function zend_object_sdtClass(stdClass $param): stdClass {}
 +	function zend_object_sdtClass_or_null(stdClass|null $param): stdClass|null {}
 +	function zend_object_sdtClass_slow_zpp(stdClass $param): stdClass {}
 +	function zend_object_sdtClass_or_null_slow_zpp(stdClass|null $param): stdClass|null {}
 +
 +	function zend_obj_sdtClass(stdClass $param): stdClass {}
 +	function zend_obj_sdtClass_or_null(stdClass|null $param): stdClass|null {}
 +
 +    /**
 +     * @param resource $param
 +     * @return resource
 +     */
 +	function zend_resource($param) {}
 +    /**
 +     * @param resource|null $param
 +     * @return resource|null
 +     */
 +	function zend_resource_or_null($param) {}
 +    /**
 +     * @param resource $param
 +     * @return resource
 +     */
 +	function zend_resource_slow_zpp($param) {}
 +    /**
 +     * @param resource|null $param
 +     * @return resource|null
 +     */
 +	function zend_resource_or_null_slow_zpp($param) {}
++
+     function zend_test_emalloc(int $size): void {}
+
+     function zend_test_callback(callable $callback): void {}

      function zend_string_or_object(object|string $param): object|string {}

diff --cc ext/zend_test/test_arginfo.h
index 40f06222783,820ac82fb01..87622c185cf
Binary files differ
diff --cc ext/zend_test/test_decl.h
index 96ebfbea6fc,00000000000..db7652512c8
mode 100644,000000..100644
Binary files differ
diff --cc ext/zend_test/test_legacy_arginfo.h
index 4ee3d3d083e,00000000000..a673b373142
mode 100644,000000..100644
Binary files differ
diff --cc ext/zend_test/tests/observer_bug81430_2.phpt
index 11a9f061b3d,23e66445e90..918794d6ea1
--- a/ext/zend_test/tests/observer_bug81430_2.phpt
+++ b/ext/zend_test/tests/observer_bug81430_2.phpt
@@@ -40,14 -35,14 +35,14 @@@ call_user_func([$r->getAttributes(A::cl
    <ReflectionAttribute::newInstance>
      <!-- init A::__construct() -->
      <A::__construct>
-       <!-- init array_map() -->
-       <array_map>
-         <!-- init str_repeat() -->
-         <str_repeat>
+       <!-- init var_dump() -->
+       <var_dump>
+         <!-- init class@anonymous::__debugInfo() -->
+         <class@anonymous::__debugInfo>
+         </class@anonymous::__debugInfo>

- Fatal error: Allowed memory size of %d bytes exhausted %s in %s on line %d
-         </str_repeat>
-       </array_map>
 -Fatal error: __debuginfo() must return an array in %s on line %d
++Fatal error: __debugInfo() must return an array in %s on line %d
+       </var_dump>
      </A::__construct>
    </ReflectionAttribute::newInstance>
  </file '%s'>
diff --cc ext/zend_test/tests/observer_bug81435.phpt
index da9bdd01db1,096afb8fb78..54f3f1fb82b
--- a/ext/zend_test/tests/observer_bug81435.phpt
+++ b/ext/zend_test/tests/observer_bug81435.phpt
@@@ -47,8 -42,8 +42,8 @@@ a()
    <d>
    </d>
    <!-- init bailout() -->
-   <!-- init array_map() -->
-   <!-- init str_repeat() -->
+   <!-- init var_dump() -->
+   <!-- init class@anonymous::__debugInfo() -->

- Fatal error: Allowed memory size of 20971520 bytes exhausted %s in %s on line %d
 -Fatal error: __debuginfo() must return an array in %s on line %d
++Fatal error: __debugInfo() must return an array in %s on line %d
  </a>
diff --cc ext/zend_test/tests/observer_error_01.phpt
index d20a23b00b2,4f8b97bf457..da9fcf9b757
--- a/ext/zend_test/tests/observer_error_01.phpt
+++ b/ext/zend_test/tests/observer_error_01.phpt
@@@ -28,10 -23,13 +23,13 @@@ echo 'You should not see this.'
  <file '%s'>
    <!-- init foo() -->
    <foo>
-     <!-- init str_repeat() -->
-     <str_repeat>
+     <!-- init var_dump() -->
+     <var_dump>
+       <!-- init class@anonymous::__debugInfo() -->
+       <class@anonymous::__debugInfo>
+       </class@anonymous::__debugInfo:''>

- Fatal error: Allowed memory size of 2097152 bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
-     </str_repeat:NULL>
 -Fatal error: __debuginfo() must return an array in %s on line %d
++Fatal error: __debugInfo() must return an array in %s on line %d
+     </var_dump:NULL>
    </foo:NULL>
  </file '%s%eobserver_error_%d.php'>
diff --cc ext/zend_test/tests/observer_fiber_functions_03.phpt
index 8e267ea65a0,a987242fafd..8b9d5fa20c1
--- a/ext/zend_test/tests/observer_fiber_functions_03.phpt
+++ b/ext/zend_test/tests/observer_fiber_functions_03.phpt
@@@ -76,11 -71,13 +71,13 @@@ int(2
  <!-- switching from fiber %s to %s -->
  <resume '%s'>
            </Fiber::suspend>
-           <!-- init str_repeat() -->
-           <str_repeat>
+           <var_dump>
+             <!-- init class@anonymous::__debugInfo() -->
+             <class@anonymous::__debugInfo>
+             </class@anonymous::__debugInfo>

- Fatal error: Allowed memory size of 104857600 bytes exhausted %s on line %d
-           </str_repeat>
 -Fatal error: __debuginfo() must return an array in %s on line %d
++Fatal error: __debugInfo() must return an array in %s on line %d
+           </var_dump>
          </{closure:%s:%d}>
  <!-- switching from fiber %s to %s -->
  <returned '%s'>
diff --cc main/main.c
index 3b82ae81f96,0db01692170..43c5fa087c5
--- a/main/main.c
+++ b/main/main.c
@@@ -1995,9 -2085,10 +2036,10 @@@ void php_request_shutdown(void *dummy
  		php_shutdown_stream_hashes();
  	} zend_end_try();

 -	/* 15. Free Willy (here be crashes) */
 +	/* 16. Free Willy (here be crashes) */
  	zend_arena_destroy(CG(arena));
  	zend_interned_strings_deactivate();
+ 	clear_last_error();
  	zend_try {
  		shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0);
  	} zend_end_try();