From a34e543e924d6ad5deb514a05376c3d29d70fe81 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Sat, 7 May 2022 23:15:52 +0100 Subject: [PATCH 01/10] Remove custom alloca Use do_alloca in place of alloca Add support for Windows --- Zend/Optimizer/dce.c | 17 +- Zend/zend_portability.h | 14 +- configure.ac | 2 +- ext/standard/crypt_sha256.c | 24 +- ext/standard/crypt_sha512.c | 24 +- main/alloca.c | 486 ------------------------------------ 6 files changed, 60 insertions(+), 507 deletions(-) delete mode 100644 main/alloca.c diff --git a/Zend/Optimizer/dce.c b/Zend/Optimizer/dce.c index 347d71300e324..5f92c3384aaac 100644 --- a/Zend/Optimizer/dce.c +++ b/Zend/Optimizer/dce.c @@ -530,6 +530,7 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_d /* DCE of CV operations that changes arguments may affect vararg functions. */ bool has_varargs = (ssa->cfg.flags & ZEND_FUNC_VARARG) != 0; + ALLOCA_FLAG(use_heap); context ctx; ctx.ssa = ssa; @@ -538,18 +539,18 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_d /* We have no dedicated phi vector, so we use the whole ssa var vector instead */ ctx.instr_worklist_len = zend_bitset_len(op_array->last); - ctx.instr_worklist = alloca(sizeof(zend_ulong) * ctx.instr_worklist_len); + ctx.instr_worklist = do_alloca(sizeof(zend_ulong) * ctx.instr_worklist_len, use_heap); memset(ctx.instr_worklist, 0, sizeof(zend_ulong) * ctx.instr_worklist_len); ctx.phi_worklist_len = zend_bitset_len(ssa->vars_count); - ctx.phi_worklist = alloca(sizeof(zend_ulong) * ctx.phi_worklist_len); + ctx.phi_worklist = do_alloca(sizeof(zend_ulong) * ctx.phi_worklist_len, use_heap); memset(ctx.phi_worklist, 0, sizeof(zend_ulong) * ctx.phi_worklist_len); - ctx.phi_worklist_no_val = alloca(sizeof(zend_ulong) * ctx.phi_worklist_len); + ctx.phi_worklist_no_val = do_alloca(sizeof(zend_ulong) * ctx.phi_worklist_len, use_heap); memset(ctx.phi_worklist_no_val, 0, sizeof(zend_ulong) * ctx.phi_worklist_len); /* Optimistically assume all instructions and phis to be dead */ - ctx.instr_dead = alloca(sizeof(zend_ulong) * ctx.instr_worklist_len); + ctx.instr_dead = do_alloca(sizeof(zend_ulong) * ctx.instr_worklist_len, use_heap); memset(ctx.instr_dead, 0, sizeof(zend_ulong) * ctx.instr_worklist_len); - ctx.phi_dead = alloca(sizeof(zend_ulong) * ctx.phi_worklist_len); + ctx.phi_dead = do_alloca(sizeof(zend_ulong) * ctx.phi_worklist_len, use_heap); memset(ctx.phi_dead, 0xff, sizeof(zend_ulong) * ctx.phi_worklist_len); /* Mark non-CV phis as live. Even if the result is unused, we generally cannot remove one @@ -664,5 +665,11 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_d } } FOREACH_PHI_END(); + free_alloca(ctx.instr_worklist, use_heap); + free_alloca(ctx.phi_worklist, use_heap); + free_alloca(ctx.phi_worklist_no_val, use_heap); + free_alloca(ctx.instr_dead, use_heap); + free_alloca(ctx.phi_dead, use_heap); + return removed_ops; } diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index 6ad9f1b1db2f9..f75d9e1f87d35 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -350,13 +350,25 @@ char *alloca(); # define ALLOCA_FLAG(name) \ bool name; # define SET_ALLOCA_FLAG(name) \ - name = 1 + name = true # define do_alloca_ex(size, limit, use_heap) \ ((use_heap = (UNEXPECTED((size) > (limit)))) ? emalloc(size) : alloca(size)) # define do_alloca(size, use_heap) \ do_alloca_ex(size, ZEND_ALLOCA_MAX_SIZE, use_heap) # define free_alloca(p, use_heap) \ do { if (UNEXPECTED(use_heap)) efree(p); } while (0) +#elif defined(PHP_WIN32) +# define ZEND_ALLOCA_MAX_SIZE (32 * 1024) +# define ALLOCA_FLAG(name) \ + bool name; +# define SET_ALLOCA_FLAG(name) \ + name = true +# define do_alloca_ex(size, limit, use_heap) \ + ((use_heap = (UNEXPECTED((size) > (limit)))) ? emalloc(size) : _malloca(size)) +# define do_alloca(size, use_heap) \ + do_alloca_ex(size, ZEND_ALLOCA_MAX_SIZE, use_heap) +# define free_alloca(p, use_heap) \ + do { if (UNEXPECTED(use_heap)) { efree(p); } else { _freea(p); } } while (0) #else # define ALLOCA_FLAG(name) # define SET_ALLOCA_FLAG(name) diff --git a/configure.ac b/configure.ac index 63513b7d800ea..5a24b52800047 100644 --- a/configure.ac +++ b/configure.ac @@ -1610,7 +1610,7 @@ PHP_INSTALL_HEADERS([Zend/Optimizer], [ \ PHP_ADD_SOURCES(TSRM, TSRM.c, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_ADD_SOURCES(main, main.c snprintf.c spprintf.c \ - fopen_wrappers.c alloca.c php_scandir.c \ + fopen_wrappers.c php_scandir.c \ php_ini_builder.c \ php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ strlcat.c explicit_bzero.c reentrancy.c php_variables.c php_ticks.c \ diff --git a/ext/standard/crypt_sha256.c b/ext/standard/crypt_sha256.c index 4ba4f6c3dd831..1ba56dfe0c66b 100644 --- a/ext/standard/crypt_sha256.c +++ b/ext/standard/crypt_sha256.c @@ -10,7 +10,6 @@ #ifdef PHP_WIN32 # define __alignof__ __alignof -# define alloca _alloca #else # ifndef HAVE_ALIGNOF # include @@ -370,16 +369,19 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX); key_len = strlen(key); + ALLOCA_FLAG(use_heap); + char *tmp_key = NULL; + char *tmp_salt = NULL; if ((key - (char *) 0) % __alignof__ (uint32_t) != 0) { - char *tmp = (char *) alloca(key_len + __alignof__(uint32_t)); - key = copied_key = memcpy(tmp + __alignof__(uint32_t) - (tmp - (char *) 0) % __alignof__(uint32_t), key, key_len); + tmp_key = (char *) do_alloca(key_len + __alignof__(uint32_t), use_heap); + key = copied_key = memcpy(tmp_key + __alignof__(uint32_t) - (tmp_key - (char *) 0) % __alignof__(uint32_t), key, key_len); } if ((salt - (char *) 0) % __alignof__(uint32_t) != 0) { - char *tmp = (char *) alloca(salt_len + 1 + __alignof__(uint32_t)); + tmp_salt = (char *) do_alloca(salt_len + 1 + __alignof__(uint32_t), use_heap); salt = copied_salt = - memcpy(tmp + __alignof__(uint32_t) - (tmp - (char *) 0) % __alignof__ (uint32_t), salt, salt_len); + memcpy(tmp_salt + __alignof__(uint32_t) - (tmp_salt - (char *) 0) % __alignof__ (uint32_t), salt, salt_len); copied_salt[salt_len] = 0; } @@ -443,7 +445,7 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b sha256_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence P. */ - cp = p_bytes = alloca(key_len); + cp = p_bytes = do_alloca(key_len, use_heap); for (cnt = key_len; cnt >= 32; cnt -= 32) { cp = __php_mempcpy((void *)cp, (const void *)temp_result, 32); } @@ -461,7 +463,7 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b sha256_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence S. */ - cp = s_bytes = alloca(salt_len); + cp = s_bytes = do_alloca(salt_len, use_heap); for (cnt = salt_len; cnt >= 32; cnt -= 32) { cp = __php_mempcpy(cp, temp_result, 32); } @@ -571,6 +573,14 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b if (copied_salt != NULL) { ZEND_SECURE_ZERO(copied_salt, salt_len); } + if (tmp_key != NULL) { + free_alloca(tmp_key, use_heap); + } + if (tmp_salt != NULL) { + free_alloca(tmp_salt, use_heap); + } + free_alloca(p_bytes, use_heap); + free_alloca(s_bytes, use_heap); return buffer; } diff --git a/ext/standard/crypt_sha512.c b/ext/standard/crypt_sha512.c index a7696d63f7e84..09bdec107ef10 100644 --- a/ext/standard/crypt_sha512.c +++ b/ext/standard/crypt_sha512.c @@ -9,7 +9,6 @@ #include #ifdef PHP_WIN32 # define __alignof__ __alignof -# define alloca _alloca #else # ifndef HAVE_ALIGNOF # include @@ -404,16 +403,19 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX); key_len = strlen(key); + ALLOCA_FLAG(use_heap); + char *tmp_key = NULL; + char *tmp_salt = NULL; if ((key - (char *) 0) % __alignof__ (uint64_t) != 0) { - char *tmp = (char *) alloca (key_len + __alignof__ (uint64_t)); + tmp_key = (char *) do_alloca(key_len + __alignof__ (uint64_t), use_heap); key = copied_key = - memcpy(tmp + __alignof__(uint64_t) - (tmp - (char *) 0) % __alignof__(uint64_t), key, key_len); + memcpy(tmp_key + __alignof__(uint64_t) - (tmp_key - (char *) 0) % __alignof__(uint64_t), key, key_len); } if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0) { - char *tmp = (char *) alloca(salt_len + 1 + __alignof__(uint64_t)); - salt = copied_salt = memcpy(tmp + __alignof__(uint64_t) - (tmp - (char *) 0) % __alignof__(uint64_t), salt, salt_len); + tmp_salt = (char *) do_alloca(salt_len + 1 + __alignof__(uint64_t), use_heap); + salt = copied_salt = memcpy(tmp_salt + __alignof__(uint64_t) - (tmp_salt - (char *) 0) % __alignof__(uint64_t), salt, salt_len); copied_salt[salt_len] = 0; } @@ -477,7 +479,7 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) sha512_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence P. */ - cp = p_bytes = alloca(key_len); + cp = p_bytes = do_alloca(key_len, use_heap); for (cnt = key_len; cnt >= 64; cnt -= 64) { cp = __php_mempcpy((void *) cp, (const void *)temp_result, 64); } @@ -496,7 +498,7 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) sha512_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence S. */ - cp = s_bytes = alloca(salt_len); + cp = s_bytes = do_alloca(salt_len, use_heap); for (cnt = salt_len; cnt >= 64; cnt -= 64) { cp = __php_mempcpy(cp, temp_result, 64); } @@ -618,6 +620,14 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) if (copied_salt != NULL) { ZEND_SECURE_ZERO(copied_salt, salt_len); } + if (tmp_key != NULL) { + free_alloca(tmp_key, use_heap); + } + if (tmp_salt != NULL) { + free_alloca(tmp_salt, use_heap); + } + free_alloca(p_bytes, use_heap); + free_alloca(s_bytes, use_heap); return buffer; } diff --git a/main/alloca.c b/main/alloca.c deleted file mode 100644 index 9c8d458189abe..0000000000000 --- a/main/alloca.c +++ /dev/null @@ -1,486 +0,0 @@ -/* alloca.c -- allocate automatically reclaimed memory - (Mostly) portable public-domain implementation -- D A Gwyn - - This implementation of the PWB library alloca function, - which is used to allocate space off the run-time stack so - that it is automatically reclaimed upon procedure exit, - was inspired by discussions with J. Q. Johnson of Cornell. - J.Otto Tennant contributed the Cray support. - - There are some preprocessor constants that can - be defined when compiling for your specific system, for - improved efficiency; however, the defaults should be okay. - - The general concept of this implementation is to keep - track of all alloca-allocated blocks, and reclaim any - that are found to be deeper in the stack than the current - invocation. This heuristic does not reclaim storage as - soon as it becomes invalid, but it will do so eventually. - - As a special case, alloca(0) reclaims storage without - allocating any. It is a good idea to use alloca(0) in - your main control loop, etc. to force garbage collection. */ - -#include - -#if !HAVE_ALLOCA - -#include -#include - -#ifdef emacs -#include "blockinput.h" -#endif - -/* If compiling with GCC 2, this file's not needed. */ -#if !defined (__GNUC__) || __GNUC__ < 2 - -/* If someone has defined alloca as a macro, - there must be some other way alloca is supposed to work. */ -#ifndef alloca - -#ifdef emacs -#ifdef static -/* actually, only want this if static is defined as "" - -- this is for usg, in which emacs must undefine static - in order to make unexec workable - */ -#ifndef STACK_DIRECTION -you -lose --- must know STACK_DIRECTION at compile-time -#endif /* STACK_DIRECTION undefined */ -#endif /* static */ -#endif /* emacs */ - -/* If your stack is a linked list of frames, you have to - provide an "address metric" ADDRESS_FUNCTION macro. */ - -#if defined (CRAY) && defined (CRAY_STACKSEG_END) -long i00afunc (); -#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg)) -#else -#define ADDRESS_FUNCTION(arg) &(arg) -#endif - -#if __STDC__ -typedef void *pointer; -#else -typedef char *pointer; -#endif - -#ifndef NULL -#define NULL 0 -#endif - -/* Define STACK_DIRECTION if you know the direction of stack - growth for your system; otherwise it will be automatically - deduced at run-time. - - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ - -#ifndef STACK_DIRECTION -#define STACK_DIRECTION 0 /* Direction unknown. */ -#endif - -#if STACK_DIRECTION != 0 - -#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */ - -#else /* STACK_DIRECTION == 0; need run-time code. */ - -static int stack_dir; /* 1 or -1 once known. */ -#define STACK_DIR stack_dir - -static void -find_stack_direction () -{ - static char *addr = NULL; /* Address of first `dummy', once known. */ - auto char dummy; /* To get stack address. */ - - if (addr == NULL) - { /* Initial entry. */ - addr = ADDRESS_FUNCTION (dummy); - - find_stack_direction (); /* Recurse once. */ - } - else - { - /* Second entry. */ - if (ADDRESS_FUNCTION (dummy) > addr) - stack_dir = 1; /* Stack grew upward. */ - else - stack_dir = -1; /* Stack grew downward. */ - } -} - -#endif /* STACK_DIRECTION == 0 */ - -/* An "alloca header" is used to: - (a) chain together all alloca'd blocks; - (b) keep track of stack depth. - - It is very important that sizeof(header) agree with malloc - alignment chunk size. The following default should work okay. */ - -#ifndef ALIGN_SIZE -#define ALIGN_SIZE sizeof(double) -#endif - -typedef union hdr -{ - char align[ALIGN_SIZE]; /* To force sizeof(header). */ - struct - { - union hdr *next; /* For chaining headers. */ - char *deep; /* For stack depth measure. */ - } h; -} header; - -static header *last_alloca_header = NULL; /* -> last alloca header. */ - -/* Return a pointer to at least SIZE bytes of storage, - which will be automatically reclaimed upon exit from - the procedure that called alloca. Originally, this space - was supposed to be taken from the current stack frame of the - caller, but that method cannot be made to work for some - implementations of C, for example under Gould's UTX/32. */ - -pointer -alloca (size) - size_t size; -{ - auto char probe; /* Probes stack depth: */ - register char *depth = ADDRESS_FUNCTION (probe); - -#if STACK_DIRECTION == 0 - if (STACK_DIR == 0) /* Unknown growth direction. */ - find_stack_direction (); -#endif - - /* Reclaim garbage, defined as all alloca'd storage that - was allocated from deeper in the stack than currently. */ - - { - register header *hp; /* Traverses linked list. */ - -#ifdef emacs - BLOCK_INPUT; -#endif - - for (hp = last_alloca_header; hp != NULL;) - if ((STACK_DIR > 0 && hp->h.deep > depth) - || (STACK_DIR < 0 && hp->h.deep < depth)) - { - register header *np = hp->h.next; - - free ((pointer) hp); /* Collect garbage. */ - - hp = np; /* -> next header. */ - } - else - break; /* Rest are not deeper. */ - - last_alloca_header = hp; /* -> last valid storage. */ - -#ifdef emacs - UNBLOCK_INPUT; -#endif - } - - if (size == 0) - return NULL; /* No allocation required. */ - - /* Allocate combined header + user data storage. */ - - { - register pointer new = malloc (sizeof (header) + size); - /* Address of header. */ - - if (new == 0) - abort(); - - ((header *) new)->h.next = last_alloca_header; - ((header *) new)->h.deep = depth; - - last_alloca_header = (header *) new; - - /* User storage begins just after header. */ - - return (pointer) ((char *) new + sizeof (header)); - } -} - -#if defined (CRAY) && defined (CRAY_STACKSEG_END) - -#ifdef DEBUG_I00AFUNC -#include -#endif - -#ifndef CRAY_STACK -#define CRAY_STACK -#ifndef CRAY2 -/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */ -struct stack_control_header - { - long shgrow:32; /* Number of times stack has grown. */ - long shaseg:32; /* Size of increments to stack. */ - long shhwm:32; /* High water mark of stack. */ - long shsize:32; /* Current size of stack (all segments). */ - }; - -/* The stack segment linkage control information occurs at - the high-address end of a stack segment. (The stack - grows from low addresses to high addresses.) The initial - part of the stack segment linkage control information is - 0200 (octal) words. This provides for register storage - for the routine which overflows the stack. */ - -struct stack_segment_linkage - { - long ss[0200]; /* 0200 overflow words. */ - long sssize:32; /* Number of words in this segment. */ - long ssbase:32; /* Offset to stack base. */ - long:32; - long sspseg:32; /* Offset to linkage control of previous - segment of stack. */ - long:32; - long sstcpt:32; /* Pointer to task common address block. */ - long sscsnm; /* Private control structure number for - microtasking. */ - long ssusr1; /* Reserved for user. */ - long ssusr2; /* Reserved for user. */ - long sstpid; /* Process ID for pid based multi-tasking. */ - long ssgvup; /* Pointer to multitasking thread give up. */ - long sscray[7]; /* Reserved for Cray Research. */ - long ssa0; - long ssa1; - long ssa2; - long ssa3; - long ssa4; - long ssa5; - long ssa6; - long ssa7; - long sss0; - long sss1; - long sss2; - long sss3; - long sss4; - long sss5; - long sss6; - long sss7; - }; - -#else /* CRAY2 */ -/* The following structure defines the vector of words - returned by the STKSTAT library routine. */ -struct stk_stat - { - long now; /* Current total stack size. */ - long maxc; /* Amount of contiguous space which would - be required to satisfy the maximum - stack demand to date. */ - long high_water; /* Stack high-water mark. */ - long overflows; /* Number of stack overflow ($STKOFEN) calls. */ - long hits; /* Number of internal buffer hits. */ - long extends; /* Number of block extensions. */ - long stko_mallocs; /* Block allocations by $STKOFEN. */ - long underflows; /* Number of stack underflow calls ($STKRETN). */ - long stko_free; /* Number of deallocations by $STKRETN. */ - long stkm_free; /* Number of deallocations by $STKMRET. */ - long segments; /* Current number of stack segments. */ - long maxs; /* Maximum number of stack segments so far. */ - long pad_size; /* Stack pad size. */ - long current_address; /* Current stack segment address. */ - long current_size; /* Current stack segment size. This - number is actually corrupted by STKSTAT to - include the fifteen word trailer area. */ - long initial_address; /* Address of initial segment. */ - long initial_size; /* Size of initial segment. */ - }; - -/* The following structure describes the data structure which trails - any stack segment. I think that the description in 'asdef' is - out of date. I only describe the parts that I am sure about. */ - -struct stk_trailer - { - long this_address; /* Address of this block. */ - long this_size; /* Size of this block (does not include - this trailer). */ - long unknown2; - long unknown3; - long link; /* Address of trailer block of previous - segment. */ - long unknown5; - long unknown6; - long unknown7; - long unknown8; - long unknown9; - long unknown10; - long unknown11; - long unknown12; - long unknown13; - long unknown14; - }; - -#endif /* CRAY2 */ -#endif /* not CRAY_STACK */ - -#ifdef CRAY2 -/* Determine a "stack measure" for an arbitrary ADDRESS. - I doubt that "lint" will like this much. */ - -static long -i00afunc (long *address) -{ - struct stk_stat status; - struct stk_trailer *trailer; - long *block, size; - long result = 0; - - /* We want to iterate through all of the segments. The first - step is to get the stack status structure. We could do this - more quickly and more directly, perhaps, by referencing the - $LM00 common block, but I know that this works. */ - - STKSTAT (&status); - - /* Set up the iteration. */ - - trailer = (struct stk_trailer *) (status.current_address - + status.current_size - - 15); - - /* There must be at least one stack segment. Therefore it is - a fatal error if "trailer" is null. */ - - if (trailer == 0) - abort (); - - /* Discard segments that do not contain our argument address. */ - - while (trailer != 0) - { - block = (long *) trailer->this_address; - size = trailer->this_size; - if (block == 0 || size == 0) - abort (); - trailer = (struct stk_trailer *) trailer->link; - if ((block <= address) && (address < (block + size))) - break; - } - - /* Set the result to the offset in this segment and add the sizes - of all predecessor segments. */ - - result = address - block; - - if (trailer == 0) - { - return result; - } - - do - { - if (trailer->this_size <= 0) - abort (); - result += trailer->this_size; - trailer = (struct stk_trailer *) trailer->link; - } - while (trailer != 0); - - /* We are done. Note that if you present a bogus address (one - not in any segment), you will get a different number back, formed - from subtracting the address of the first block. This is probably - not what you want. */ - - return (result); -} - -#else /* not CRAY2 */ -/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP. - Determine the number of the cell within the stack, - given the address of the cell. The purpose of this - routine is to linearize, in some sense, stack addresses - for alloca. */ - -static long -i00afunc (long address) -{ - long stkl = 0; - - long size, pseg, this_segment, stack; - long result = 0; - - struct stack_segment_linkage *ssptr; - - /* Register B67 contains the address of the end of the - current stack segment. If you (as a subprogram) store - your registers on the stack and find that you are past - the contents of B67, you have overflowed the segment. - - B67 also points to the stack segment linkage control - area, which is what we are really interested in. */ - - stkl = CRAY_STACKSEG_END (); - ssptr = (struct stack_segment_linkage *) stkl; - - /* If one subtracts 'size' from the end of the segment, - one has the address of the first word of the segment. - - If this is not the first segment, 'pseg' will be - nonzero. */ - - pseg = ssptr->sspseg; - size = ssptr->sssize; - - this_segment = stkl - size; - - /* It is possible that calling this routine itself caused - a stack overflow. Discard stack segments which do not - contain the target address. */ - - while (!(this_segment <= address && address <= stkl)) - { -#ifdef DEBUG_I00AFUNC - fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl); -#endif - if (pseg == 0) - break; - stkl = stkl - pseg; - ssptr = (struct stack_segment_linkage *) stkl; - size = ssptr->sssize; - pseg = ssptr->sspseg; - this_segment = stkl - size; - } - - result = address - this_segment; - - /* If you subtract pseg from the current end of the stack, - you get the address of the previous stack segment's end. - This seems a little convoluted to me, but I'll bet you save - a cycle somewhere. */ - - while (pseg != 0) - { -#ifdef DEBUG_I00AFUNC - fprintf (stderr, "%011o %011o\n", pseg, size); -#endif - stkl = stkl - pseg; - ssptr = (struct stack_segment_linkage *) stkl; - size = ssptr->sssize; - pseg = ssptr->sspseg; - result += size; - } - return (result); -} - -#endif /* not CRAY2 */ -#endif /* CRAY */ - -#endif /* no alloca */ -#endif /* not GCC version 2 */ -#endif /* HAVE_ALLOCA */ From 1af023e8d40241c8ad89e65b65bd535c2454d913 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Sun, 8 May 2022 11:40:08 +0100 Subject: [PATCH 02/10] Drop new windows specific code --- Zend/zend_portability.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index f75d9e1f87d35..c924d89da2cd5 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -357,18 +357,6 @@ char *alloca(); do_alloca_ex(size, ZEND_ALLOCA_MAX_SIZE, use_heap) # define free_alloca(p, use_heap) \ do { if (UNEXPECTED(use_heap)) efree(p); } while (0) -#elif defined(PHP_WIN32) -# define ZEND_ALLOCA_MAX_SIZE (32 * 1024) -# define ALLOCA_FLAG(name) \ - bool name; -# define SET_ALLOCA_FLAG(name) \ - name = true -# define do_alloca_ex(size, limit, use_heap) \ - ((use_heap = (UNEXPECTED((size) > (limit)))) ? emalloc(size) : _malloca(size)) -# define do_alloca(size, use_heap) \ - do_alloca_ex(size, ZEND_ALLOCA_MAX_SIZE, use_heap) -# define free_alloca(p, use_heap) \ - do { if (UNEXPECTED(use_heap)) { efree(p); } else { _freea(p); } } while (0) #else # define ALLOCA_FLAG(name) # define SET_ALLOCA_FLAG(name) From a4fa962f584ddb494733b3b6dcde50f64da4c7bd Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Sun, 8 May 2022 12:08:25 +0100 Subject: [PATCH 03/10] Use different alloca flags for crypt_sha --- ext/standard/crypt_sha256.c | 19 ++++++++++--------- ext/standard/crypt_sha512.c | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/ext/standard/crypt_sha256.c b/ext/standard/crypt_sha256.c index 1ba56dfe0c66b..0be82180476e9 100644 --- a/ext/standard/crypt_sha256.c +++ b/ext/standard/crypt_sha256.c @@ -369,17 +369,18 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX); key_len = strlen(key); - ALLOCA_FLAG(use_heap); char *tmp_key = NULL; + ALLOCA_FLAG(use_heap_key); char *tmp_salt = NULL; + ALLOCA_FLAG(use_heap_salt); if ((key - (char *) 0) % __alignof__ (uint32_t) != 0) { - tmp_key = (char *) do_alloca(key_len + __alignof__(uint32_t), use_heap); + tmp_key = (char *) do_alloca(key_len + __alignof__(uint32_t), use_heap_key); key = copied_key = memcpy(tmp_key + __alignof__(uint32_t) - (tmp_key - (char *) 0) % __alignof__(uint32_t), key, key_len); } if ((salt - (char *) 0) % __alignof__(uint32_t) != 0) { - tmp_salt = (char *) do_alloca(salt_len + 1 + __alignof__(uint32_t), use_heap); + tmp_salt = (char *) do_alloca(salt_len + 1 + __alignof__(uint32_t), use_heap_salt); salt = copied_salt = memcpy(tmp_salt + __alignof__(uint32_t) - (tmp_salt - (char *) 0) % __alignof__ (uint32_t), salt, salt_len); copied_salt[salt_len] = 0; @@ -445,7 +446,7 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b sha256_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence P. */ - cp = p_bytes = do_alloca(key_len, use_heap); + cp = p_bytes = do_alloca(key_len, use_heap_key); for (cnt = key_len; cnt >= 32; cnt -= 32) { cp = __php_mempcpy((void *)cp, (const void *)temp_result, 32); } @@ -463,7 +464,7 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b sha256_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence S. */ - cp = s_bytes = do_alloca(salt_len, use_heap); + cp = s_bytes = do_alloca(salt_len, use_heap_salt); for (cnt = salt_len; cnt >= 32; cnt -= 32) { cp = __php_mempcpy(cp, temp_result, 32); } @@ -574,13 +575,13 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b ZEND_SECURE_ZERO(copied_salt, salt_len); } if (tmp_key != NULL) { - free_alloca(tmp_key, use_heap); + free_alloca(tmp_key, use_heap_key); } if (tmp_salt != NULL) { - free_alloca(tmp_salt, use_heap); + free_alloca(tmp_salt, use_heap_salt); } - free_alloca(p_bytes, use_heap); - free_alloca(s_bytes, use_heap); + free_alloca(p_bytes, use_heap_key); + free_alloca(s_bytes, use_heap_salt); return buffer; } diff --git a/ext/standard/crypt_sha512.c b/ext/standard/crypt_sha512.c index 09bdec107ef10..0d18e872d474e 100644 --- a/ext/standard/crypt_sha512.c +++ b/ext/standard/crypt_sha512.c @@ -403,18 +403,19 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX); key_len = strlen(key); - ALLOCA_FLAG(use_heap); char *tmp_key = NULL; + ALLOCA_FLAG(use_heap_key); char *tmp_salt = NULL; + ALLOCA_FLAG(use_heap_salt); if ((key - (char *) 0) % __alignof__ (uint64_t) != 0) { - tmp_key = (char *) do_alloca(key_len + __alignof__ (uint64_t), use_heap); + tmp_key = (char *) do_alloca(key_len + __alignof__ (uint64_t), use_heap_key); key = copied_key = memcpy(tmp_key + __alignof__(uint64_t) - (tmp_key - (char *) 0) % __alignof__(uint64_t), key, key_len); } if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0) { - tmp_salt = (char *) do_alloca(salt_len + 1 + __alignof__(uint64_t), use_heap); + tmp_salt = (char *) do_alloca(salt_len + 1 + __alignof__(uint64_t), use_heap_salt); salt = copied_salt = memcpy(tmp_salt + __alignof__(uint64_t) - (tmp_salt - (char *) 0) % __alignof__(uint64_t), salt, salt_len); copied_salt[salt_len] = 0; } @@ -479,7 +480,7 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) sha512_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence P. */ - cp = p_bytes = do_alloca(key_len, use_heap); + cp = p_bytes = do_alloca(key_len, use_heap_key); for (cnt = key_len; cnt >= 64; cnt -= 64) { cp = __php_mempcpy((void *) cp, (const void *)temp_result, 64); } @@ -498,7 +499,7 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) sha512_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence S. */ - cp = s_bytes = do_alloca(salt_len, use_heap); + cp = s_bytes = do_alloca(salt_len, use_heap_salt); for (cnt = salt_len; cnt >= 64; cnt -= 64) { cp = __php_mempcpy(cp, temp_result, 64); } @@ -621,13 +622,13 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) ZEND_SECURE_ZERO(copied_salt, salt_len); } if (tmp_key != NULL) { - free_alloca(tmp_key, use_heap); + free_alloca(tmp_key, use_heap_key); } if (tmp_salt != NULL) { - free_alloca(tmp_salt, use_heap); + free_alloca(tmp_salt, use_heap_salt); } - free_alloca(p_bytes, use_heap); - free_alloca(s_bytes, use_heap); + free_alloca(p_bytes, use_heap_key); + free_alloca(s_bytes, use_heap_salt); return buffer; } From a1ef3e42edabd738d9a68f6a5b7abd906e6824b6 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Sun, 8 May 2022 12:19:23 +0100 Subject: [PATCH 04/10] Use arena in DCE --- Zend/Optimizer/dce.c | 20 ++++++++------------ Zend/Optimizer/dfa_pass.c | 2 +- Zend/Optimizer/zend_optimizer_internal.h | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Zend/Optimizer/dce.c b/Zend/Optimizer/dce.c index 5f92c3384aaac..b6c4be6707fb9 100644 --- a/Zend/Optimizer/dce.c +++ b/Zend/Optimizer/dce.c @@ -523,34 +523,34 @@ static inline bool may_throw_dce_exception(const zend_op *opline) { return opline->opcode == ZEND_ADD_ARRAY_ELEMENT && opline->op2_type == IS_UNUSED; } -int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_dtor_effects) { +int dce_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *optimizer_ctx, zend_ssa *ssa, bool reorder_dtor_effects) { int i; zend_ssa_phi *phi; int removed_ops = 0; /* DCE of CV operations that changes arguments may affect vararg functions. */ bool has_varargs = (ssa->cfg.flags & ZEND_FUNC_VARARG) != 0; - ALLOCA_FLAG(use_heap); context ctx; ctx.ssa = ssa; ctx.op_array = op_array; ctx.reorder_dtor_effects = reorder_dtor_effects; + void *checkpoint = zend_arena_checkpoint(optimizer_ctx->arena); /* We have no dedicated phi vector, so we use the whole ssa var vector instead */ ctx.instr_worklist_len = zend_bitset_len(op_array->last); - ctx.instr_worklist = do_alloca(sizeof(zend_ulong) * ctx.instr_worklist_len, use_heap); + ctx.instr_worklist = zend_arena_calloc(&optimizer_ctx->arena, ctx.instr_worklist_len, sizeof(zend_ulong)); memset(ctx.instr_worklist, 0, sizeof(zend_ulong) * ctx.instr_worklist_len); ctx.phi_worklist_len = zend_bitset_len(ssa->vars_count); - ctx.phi_worklist = do_alloca(sizeof(zend_ulong) * ctx.phi_worklist_len, use_heap); + ctx.phi_worklist = zend_arena_calloc(&optimizer_ctx->arena, ctx.phi_worklist_len, sizeof(zend_ulong)); memset(ctx.phi_worklist, 0, sizeof(zend_ulong) * ctx.phi_worklist_len); - ctx.phi_worklist_no_val = do_alloca(sizeof(zend_ulong) * ctx.phi_worklist_len, use_heap); + ctx.phi_worklist_no_val = zend_arena_calloc(&optimizer_ctx->arena, ctx.phi_worklist_len, sizeof(zend_ulong)); memset(ctx.phi_worklist_no_val, 0, sizeof(zend_ulong) * ctx.phi_worklist_len); /* Optimistically assume all instructions and phis to be dead */ - ctx.instr_dead = do_alloca(sizeof(zend_ulong) * ctx.instr_worklist_len, use_heap); + ctx.instr_dead = zend_arena_calloc(&optimizer_ctx->arena, ctx.instr_worklist_len, sizeof(zend_ulong)); memset(ctx.instr_dead, 0, sizeof(zend_ulong) * ctx.instr_worklist_len); - ctx.phi_dead = do_alloca(sizeof(zend_ulong) * ctx.phi_worklist_len, use_heap); + ctx.phi_dead = zend_arena_calloc(&optimizer_ctx->arena, ctx.phi_worklist_len, sizeof(zend_ulong)); memset(ctx.phi_dead, 0xff, sizeof(zend_ulong) * ctx.phi_worklist_len); /* Mark non-CV phis as live. Even if the result is unused, we generally cannot remove one @@ -665,11 +665,7 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_d } } FOREACH_PHI_END(); - free_alloca(ctx.instr_worklist, use_heap); - free_alloca(ctx.phi_worklist, use_heap); - free_alloca(ctx.phi_worklist_no_val, use_heap); - free_alloca(ctx.instr_dead, use_heap); - free_alloca(ctx.phi_dead, use_heap); + zend_arena_release(&optimizer_ctx->arena, checkpoint); return removed_ops; } diff --git a/Zend/Optimizer/dfa_pass.c b/Zend/Optimizer/dfa_pass.c index 66c001746d799..a103527613137 100644 --- a/Zend/Optimizer/dfa_pass.c +++ b/Zend/Optimizer/dfa_pass.c @@ -1076,7 +1076,7 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx } if (ZEND_OPTIMIZER_PASS_14 & ctx->optimization_level) { - if (dce_optimize_op_array(op_array, ssa, 0)) { + if (dce_optimize_op_array(op_array, ctx, ssa, 0)) { remove_nops = 1; } if (zend_dfa_optimize_jmps(op_array, ssa)) { diff --git a/Zend/Optimizer/zend_optimizer_internal.h b/Zend/Optimizer/zend_optimizer_internal.h index 9e295bad73dcb..92410c18bf86b 100644 --- a/Zend/Optimizer/zend_optimizer_internal.h +++ b/Zend/Optimizer/zend_optimizer_internal.h @@ -121,7 +121,7 @@ uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args); void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, zend_op *opline); void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_t *shiftlist); int sccp_optimize_op_array(zend_optimizer_ctx *ctx, zend_op_array *op_array, zend_ssa *ssa, zend_call_info **call_map); -int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_dtor_effects); +int dce_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *optimizer_ctx, zend_ssa *ssa, bool reorder_dtor_effects); zend_result zend_ssa_escape_analysis(const zend_script *script, zend_op_array *op_array, zend_ssa *ssa); typedef void (*zend_op_array_func_t)(zend_op_array *, void *context); From e460cd392d9c1e83a10fc27ae95ab3c3b46c9cd7 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Sun, 8 May 2022 12:29:36 +0100 Subject: [PATCH 05/10] Drop memset --- Zend/Optimizer/dce.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Zend/Optimizer/dce.c b/Zend/Optimizer/dce.c index b6c4be6707fb9..95c7fd09fd6d6 100644 --- a/Zend/Optimizer/dce.c +++ b/Zend/Optimizer/dce.c @@ -540,18 +540,13 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *optimizer /* We have no dedicated phi vector, so we use the whole ssa var vector instead */ ctx.instr_worklist_len = zend_bitset_len(op_array->last); ctx.instr_worklist = zend_arena_calloc(&optimizer_ctx->arena, ctx.instr_worklist_len, sizeof(zend_ulong)); - memset(ctx.instr_worklist, 0, sizeof(zend_ulong) * ctx.instr_worklist_len); ctx.phi_worklist_len = zend_bitset_len(ssa->vars_count); ctx.phi_worklist = zend_arena_calloc(&optimizer_ctx->arena, ctx.phi_worklist_len, sizeof(zend_ulong)); - memset(ctx.phi_worklist, 0, sizeof(zend_ulong) * ctx.phi_worklist_len); ctx.phi_worklist_no_val = zend_arena_calloc(&optimizer_ctx->arena, ctx.phi_worklist_len, sizeof(zend_ulong)); - memset(ctx.phi_worklist_no_val, 0, sizeof(zend_ulong) * ctx.phi_worklist_len); /* Optimistically assume all instructions and phis to be dead */ ctx.instr_dead = zend_arena_calloc(&optimizer_ctx->arena, ctx.instr_worklist_len, sizeof(zend_ulong)); - memset(ctx.instr_dead, 0, sizeof(zend_ulong) * ctx.instr_worklist_len); ctx.phi_dead = zend_arena_calloc(&optimizer_ctx->arena, ctx.phi_worklist_len, sizeof(zend_ulong)); - memset(ctx.phi_dead, 0xff, sizeof(zend_ulong) * ctx.phi_worklist_len); /* Mark non-CV phis as live. Even if the result is unused, we generally cannot remove one * of the producing instructions, as it combines producing the result with control flow. From 6edd2549af216a640473c80f534b96de92079ebb Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Sun, 8 May 2022 22:24:11 +0100 Subject: [PATCH 06/10] Reinstate memset to -1 --- Zend/Optimizer/dce.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Zend/Optimizer/dce.c b/Zend/Optimizer/dce.c index 95c7fd09fd6d6..4aca34c943ca7 100644 --- a/Zend/Optimizer/dce.c +++ b/Zend/Optimizer/dce.c @@ -546,7 +546,8 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *optimizer /* Optimistically assume all instructions and phis to be dead */ ctx.instr_dead = zend_arena_calloc(&optimizer_ctx->arena, ctx.instr_worklist_len, sizeof(zend_ulong)); - ctx.phi_dead = zend_arena_calloc(&optimizer_ctx->arena, ctx.phi_worklist_len, sizeof(zend_ulong)); + ctx.phi_dead = zend_arena_alloc(&optimizer_ctx->arena, ctx.phi_worklist_len * sizeof(zend_ulong)); + memset(ctx.phi_dead, 0xff, sizeof(zend_ulong) * ctx.phi_worklist_len); /* Mark non-CV phis as live. Even if the result is unused, we generally cannot remove one * of the producing instructions, as it combines producing the result with control flow. From 88c668b3c3eed04e7d9dfb9cea8227cc4aac19c0 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Sun, 8 May 2022 22:27:06 +0100 Subject: [PATCH 07/10] Use seperate use heap variables from s and p byte sequences --- ext/standard/crypt_sha256.c | 10 ++++++---- ext/standard/crypt_sha512.c | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ext/standard/crypt_sha256.c b/ext/standard/crypt_sha256.c index 0be82180476e9..d8e61bc8baf11 100644 --- a/ext/standard/crypt_sha256.c +++ b/ext/standard/crypt_sha256.c @@ -446,7 +446,8 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b sha256_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence P. */ - cp = p_bytes = do_alloca(key_len, use_heap_key); + ALLOCA_FLAG(use_heap_p_bytes); + cp = p_bytes = do_alloca(key_len, use_heap_p_bytes); for (cnt = key_len; cnt >= 32; cnt -= 32) { cp = __php_mempcpy((void *)cp, (const void *)temp_result, 32); } @@ -464,7 +465,8 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b sha256_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence S. */ - cp = s_bytes = do_alloca(salt_len, use_heap_salt); + ALLOCA_FLAG(use_heap_s_bytes); + cp = s_bytes = do_alloca(salt_len, use_heap_s_bytes); for (cnt = salt_len; cnt >= 32; cnt -= 32) { cp = __php_mempcpy(cp, temp_result, 32); } @@ -580,8 +582,8 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b if (tmp_salt != NULL) { free_alloca(tmp_salt, use_heap_salt); } - free_alloca(p_bytes, use_heap_key); - free_alloca(s_bytes, use_heap_salt); + free_alloca(p_bytes, use_heap_p_bytes); + free_alloca(s_bytes, use_heap_s_bytes); return buffer; } diff --git a/ext/standard/crypt_sha512.c b/ext/standard/crypt_sha512.c index 0d18e872d474e..6d5472597ba0e 100644 --- a/ext/standard/crypt_sha512.c +++ b/ext/standard/crypt_sha512.c @@ -480,7 +480,8 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) sha512_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence P. */ - cp = p_bytes = do_alloca(key_len, use_heap_key); + ALLOCA_FLAG(use_heap_p_bytes); + cp = p_bytes = do_alloca(key_len, use_heap_p_bytes); for (cnt = key_len; cnt >= 64; cnt -= 64) { cp = __php_mempcpy((void *) cp, (const void *)temp_result, 64); } @@ -499,7 +500,8 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) sha512_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence S. */ - cp = s_bytes = do_alloca(salt_len, use_heap_salt); + ALLOCA_FLAG(use_heap_s_bytes); + cp = s_bytes = do_alloca(salt_len, use_heap_s_bytes); for (cnt = salt_len; cnt >= 64; cnt -= 64) { cp = __php_mempcpy(cp, temp_result, 64); } @@ -627,8 +629,8 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) if (tmp_salt != NULL) { free_alloca(tmp_salt, use_heap_salt); } - free_alloca(p_bytes, use_heap_key); - free_alloca(s_bytes, use_heap_salt); + free_alloca(p_bytes, use_heap_p_bytes); + free_alloca(s_bytes, use_heap_s_bytes); return buffer; } From ead0565b38c4e56242506715e0f0f1c06d957830 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Wed, 11 May 2022 19:42:20 +0100 Subject: [PATCH 08/10] Use ZEND_MM in debug mode instead of alloca --- Zend/zend_portability.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index c924d89da2cd5..1ed795a769340 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -345,7 +345,7 @@ char *alloca(); # define XtOffsetOf(s_type, field) offsetof(s_type, field) #endif -#if (defined(HAVE_ALLOCA) || (defined (__GNUC__) && __GNUC__ >= 2)) && !(defined(ZTS) && defined(HPUX)) && !defined(DARWIN) +#if !ZEND_DEBUG && (defined(HAVE_ALLOCA) || (defined (__GNUC__) && __GNUC__ >= 2)) && !(defined(ZTS) && defined(HPUX)) && !defined(DARWIN) # define ZEND_ALLOCA_MAX_SIZE (32 * 1024) # define ALLOCA_FLAG(name) \ bool name; From 2d773203febd936af4b6fc1e8d09526dbc6a86f4 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Wed, 11 May 2022 19:51:49 +0100 Subject: [PATCH 09/10] Group alloca handling together --- Zend/zend_portability.h | 45 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index 1ed795a769340..d36d4a663ab8b 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -63,10 +63,6 @@ #include -#if HAVE_ALLOCA_H && !defined(_ALLOCA_H) -# include -#endif - #if defined(ZEND_WIN32) && !defined(__clang__) #include #endif @@ -181,6 +177,9 @@ # define ZEND_EXTENSIONS_SUPPORT 0 #endif +#if defined(HAVE_ALLOCA_H) && !defined(_ALLOCA_H) +# include +#endif /* AIX requires this to be the first thing in the file. */ #ifndef __GNUC__ # ifndef HAVE_ALLOCA_H @@ -194,6 +193,25 @@ char *alloca(); # endif #endif +#if !ZEND_DEBUG && (defined(HAVE_ALLOCA) || (defined (__GNUC__) && __GNUC__ >= 2)) && !(defined(ZTS) && defined(HPUX)) && !defined(DARWIN) +# define ZEND_ALLOCA_MAX_SIZE (32 * 1024) +# define ALLOCA_FLAG(name) \ + bool name; +# define SET_ALLOCA_FLAG(name) \ + name = true +# define do_alloca_ex(size, limit, use_heap) \ + ((use_heap = (UNEXPECTED((size) > (limit)))) ? emalloc(size) : alloca(size)) +# define do_alloca(size, use_heap) \ + do_alloca_ex(size, ZEND_ALLOCA_MAX_SIZE, use_heap) +# define free_alloca(p, use_heap) \ + do { if (UNEXPECTED(use_heap)) efree(p); } while (0) +#else +# define ALLOCA_FLAG(name) +# define SET_ALLOCA_FLAG(name) +# define do_alloca(p, use_heap) emalloc(p) +# define free_alloca(p, use_heap) efree(p) +#endif + #if ZEND_GCC_VERSION >= 2096 || __has_attribute(__malloc__) # define ZEND_ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) #else @@ -345,25 +363,6 @@ char *alloca(); # define XtOffsetOf(s_type, field) offsetof(s_type, field) #endif -#if !ZEND_DEBUG && (defined(HAVE_ALLOCA) || (defined (__GNUC__) && __GNUC__ >= 2)) && !(defined(ZTS) && defined(HPUX)) && !defined(DARWIN) -# define ZEND_ALLOCA_MAX_SIZE (32 * 1024) -# define ALLOCA_FLAG(name) \ - bool name; -# define SET_ALLOCA_FLAG(name) \ - name = true -# define do_alloca_ex(size, limit, use_heap) \ - ((use_heap = (UNEXPECTED((size) > (limit)))) ? emalloc(size) : alloca(size)) -# define do_alloca(size, use_heap) \ - do_alloca_ex(size, ZEND_ALLOCA_MAX_SIZE, use_heap) -# define free_alloca(p, use_heap) \ - do { if (UNEXPECTED(use_heap)) efree(p); } while (0) -#else -# define ALLOCA_FLAG(name) -# define SET_ALLOCA_FLAG(name) -# define do_alloca(p, use_heap) emalloc(p) -# define free_alloca(p, use_heap) efree(p) -#endif - #ifdef HAVE_SIGSETJMP # define SETJMP(a) sigsetjmp(a, 0) # define LONGJMP(a,b) siglongjmp(a, b) From d8419062a9e514f414771c8132f649d87229f82e Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Wed, 11 May 2022 20:14:53 +0100 Subject: [PATCH 10/10] Set ALLOCA flag in crypt_sha files --- ext/standard/crypt_sha256.c | 3 +++ ext/standard/crypt_sha512.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ext/standard/crypt_sha256.c b/ext/standard/crypt_sha256.c index d8e61bc8baf11..5083ee4fc92f0 100644 --- a/ext/standard/crypt_sha256.c +++ b/ext/standard/crypt_sha256.c @@ -374,6 +374,9 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b char *tmp_salt = NULL; ALLOCA_FLAG(use_heap_salt); + SET_ALLOCA_FLAG(use_heap_key); + SET_ALLOCA_FLAG(use_heap_salt); + if ((key - (char *) 0) % __alignof__ (uint32_t) != 0) { tmp_key = (char *) do_alloca(key_len + __alignof__(uint32_t), use_heap_key); key = copied_key = memcpy(tmp_key + __alignof__(uint32_t) - (tmp_key - (char *) 0) % __alignof__(uint32_t), key, key_len); diff --git a/ext/standard/crypt_sha512.c b/ext/standard/crypt_sha512.c index 6d5472597ba0e..caeeff750f6ce 100644 --- a/ext/standard/crypt_sha512.c +++ b/ext/standard/crypt_sha512.c @@ -408,6 +408,9 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) char *tmp_salt = NULL; ALLOCA_FLAG(use_heap_salt); + SET_ALLOCA_FLAG(use_heap_key); + SET_ALLOCA_FLAG(use_heap_salt); + if ((key - (char *) 0) % __alignof__ (uint64_t) != 0) { tmp_key = (char *) do_alloca(key_len + __alignof__ (uint64_t), use_heap_key); key = copied_key =