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();