mirror of
https://github.com/php/php-src.git
synced 2025-08-17 22:48:57 +02:00

Excerpt from the release news: Version 10.37 26-May-2021 ------------------------- A few more bug fixes and tidies. The only change of real note is the removal of the actual POSIX names regcomp etc. from the POSIX wrapper library because these have caused issues for some applications (see 10.33 #2 below). Version 10.36 04-December-2020 ------------------------------ Again, mainly bug fixes and tidies. The only enhancements are the addition of GNU grep's -m (aka --max-count) option to pcre2grep, and also unifying the handling of substitution strings for both -O and callouts in pcre2grep, with the addition of $x{...} and $o{...} to allow for characters whose code points are greater than 255 in Unicode mode. NOTE: there is an outstanding issue with JIT support for MacOS on arm64 hardware. For details, please see Bugzilla issue #2618. Signed-off-by: Anatol Belski <ab@php.net>
229 lines
6.7 KiB
C
229 lines
6.7 KiB
C
/*
|
|
* Stack-less Just-In-Time compiler
|
|
*
|
|
* Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification, are
|
|
* permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
* conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
This file contains a simple W^X executable memory allocator for POSIX
|
|
like systems and Windows
|
|
|
|
In *NIX, MAP_ANON is required (that is considered a feature) so make
|
|
sure to set the right availability macros for your system or the code
|
|
will fail to build.
|
|
|
|
If your system doesn't support mapping of anonymous pages (ex: IRIX) it
|
|
is also likely that it doesn't need this allocator and should be using
|
|
the standard one instead.
|
|
|
|
It allocates a separate map for each code block and may waste a lot of
|
|
memory, because whatever was requested, will be rounded up to the page
|
|
size (minimum 4KB, but could be even bigger).
|
|
|
|
It changes the page permissions (RW <-> RX) as needed and therefore, if you
|
|
will be updating the code after it has been generated, need to make sure to
|
|
block any concurrent execution, or could result in a SIGBUS, that could
|
|
even manifest itself at a different address than the one that was being
|
|
modified.
|
|
|
|
Only use if you are unable to use the regular allocator because of security
|
|
restrictions and adding exceptions to your application or the system are
|
|
not possible.
|
|
*/
|
|
|
|
#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
|
|
sljit_update_wx_flags((from), (to), (enable_exec))
|
|
|
|
#ifndef _WIN32
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
|
|
#ifdef __NetBSD__
|
|
#if defined(PROT_MPROTECT)
|
|
#define check_se_protected(ptr, size) (0)
|
|
#define SLJIT_PROT_WX PROT_MPROTECT(PROT_EXEC)
|
|
#else /* !PROT_MPROTECT */
|
|
#ifdef _NETBSD_SOURCE
|
|
#include <sys/param.h>
|
|
#else /* !_NETBSD_SOURCE */
|
|
typedef unsigned int u_int;
|
|
#define devmajor_t sljit_s32
|
|
#endif /* _NETBSD_SOURCE */
|
|
#include <sys/sysctl.h>
|
|
#include <unistd.h>
|
|
|
|
#define check_se_protected(ptr, size) netbsd_se_protected()
|
|
|
|
static SLJIT_INLINE int netbsd_se_protected(void)
|
|
{
|
|
int mib[3];
|
|
int paxflags;
|
|
size_t len = sizeof(paxflags);
|
|
|
|
mib[0] = CTL_PROC;
|
|
mib[1] = getpid();
|
|
mib[2] = PROC_PID_PAXFLAGS;
|
|
|
|
if (SLJIT_UNLIKELY(sysctl(mib, 3, &paxflags, &len, NULL, 0) < 0))
|
|
return -1;
|
|
|
|
return (paxflags & CTL_PROC_PAXFLAGS_MPROTECT) ? -1 : 0;
|
|
}
|
|
#endif /* PROT_MPROTECT */
|
|
#else /* POSIX */
|
|
#define check_se_protected(ptr, size) generic_se_protected(ptr, size)
|
|
|
|
static SLJIT_INLINE int generic_se_protected(void *ptr, sljit_uw size)
|
|
{
|
|
if (SLJIT_LIKELY(!mprotect(ptr, size, PROT_EXEC)))
|
|
return mprotect(ptr, size, PROT_READ | PROT_WRITE);
|
|
|
|
return -1;
|
|
}
|
|
#endif /* NetBSD */
|
|
|
|
#if defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED
|
|
#define SLJIT_SE_LOCK()
|
|
#define SLJIT_SE_UNLOCK()
|
|
#else /* !SLJIT_SINGLE_THREADED */
|
|
#include <pthread.h>
|
|
#define SLJIT_SE_LOCK() pthread_mutex_lock(&se_lock)
|
|
#define SLJIT_SE_UNLOCK() pthread_mutex_unlock(&se_lock)
|
|
#endif /* SLJIT_SINGLE_THREADED */
|
|
|
|
#ifndef SLJIT_PROT_WX
|
|
#define SLJIT_PROT_WX 0
|
|
#endif /* !SLJIT_PROT_WX */
|
|
|
|
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
|
{
|
|
#if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
|
|
static pthread_mutex_t se_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
#endif
|
|
static int se_protected = !SLJIT_PROT_WX;
|
|
int prot = PROT_READ | PROT_WRITE | SLJIT_PROT_WX;
|
|
sljit_uw* ptr;
|
|
|
|
if (SLJIT_UNLIKELY(se_protected < 0))
|
|
return NULL;
|
|
|
|
#ifdef PROT_MAX
|
|
prot |= PROT_MAX(PROT_READ | PROT_WRITE | PROT_EXEC);
|
|
#endif
|
|
|
|
size += sizeof(sljit_uw);
|
|
ptr = (sljit_uw*)mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
|
|
if (ptr == MAP_FAILED)
|
|
return NULL;
|
|
|
|
if (SLJIT_UNLIKELY(se_protected > 0)) {
|
|
SLJIT_SE_LOCK();
|
|
se_protected = check_se_protected(ptr, size);
|
|
SLJIT_SE_UNLOCK();
|
|
if (SLJIT_UNLIKELY(se_protected < 0)) {
|
|
munmap((void *)ptr, size);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
*ptr++ = size;
|
|
return ptr;
|
|
}
|
|
|
|
#undef SLJIT_PROT_WX
|
|
#undef SLJIT_SE_UNLOCK
|
|
#undef SLJIT_SE_LOCK
|
|
|
|
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
|
|
{
|
|
sljit_uw *start_ptr = ((sljit_uw*)ptr) - 1;
|
|
munmap((void*)start_ptr, *start_ptr);
|
|
}
|
|
|
|
static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec)
|
|
{
|
|
sljit_uw page_mask = (sljit_uw)get_page_alignment();
|
|
sljit_uw start = (sljit_uw)from;
|
|
sljit_uw end = (sljit_uw)to;
|
|
int prot = PROT_READ | (enable_exec ? PROT_EXEC : PROT_WRITE);
|
|
|
|
SLJIT_ASSERT(start < end);
|
|
|
|
start &= ~page_mask;
|
|
end = (end + page_mask) & ~page_mask;
|
|
|
|
mprotect((void*)start, end - start, prot);
|
|
}
|
|
|
|
#else /* windows */
|
|
|
|
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
|
|
{
|
|
sljit_uw *ptr;
|
|
|
|
size += sizeof(sljit_uw);
|
|
ptr = (sljit_uw*)VirtualAlloc(NULL, size,
|
|
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
|
|
if (!ptr)
|
|
return NULL;
|
|
|
|
*ptr++ = size;
|
|
|
|
return ptr;
|
|
}
|
|
|
|
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
|
|
{
|
|
sljit_uw start = (sljit_uw)ptr - sizeof(sljit_uw);
|
|
#if defined(SLJIT_DEBUG) && SLJIT_DEBUG
|
|
sljit_uw page_mask = (sljit_uw)get_page_alignment();
|
|
|
|
SLJIT_ASSERT(!(start & page_mask));
|
|
#endif
|
|
VirtualFree((void*)start, 0, MEM_RELEASE);
|
|
}
|
|
|
|
static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec)
|
|
{
|
|
DWORD oldprot;
|
|
sljit_uw page_mask = (sljit_uw)get_page_alignment();
|
|
sljit_uw start = (sljit_uw)from;
|
|
sljit_uw end = (sljit_uw)to;
|
|
DWORD prot = enable_exec ? PAGE_EXECUTE : PAGE_READWRITE;
|
|
|
|
SLJIT_ASSERT(start < end);
|
|
|
|
start &= ~page_mask;
|
|
end = (end + page_mask) & ~page_mask;
|
|
|
|
VirtualProtect((void*)start, end - start, prot, &oldprot);
|
|
}
|
|
|
|
#endif /* !windows */
|
|
|
|
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
|
|
{
|
|
/* This allocator does not keep unused memory for future allocations. */
|
|
}
|