Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Zend/Zend.m4
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ AC_CHECK_FUNCS(m4_normalize([
pthread_attr_getstack
pthread_get_stackaddr_np
pthread_getattr_np
pthread_getthrds_np
pthread_stackseg_np
strnlen
]))
Expand Down
13 changes: 12 additions & 1 deletion Zend/tests/stack_limit/stack_limit_010.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,24 @@ $expectedMaxSize = match(php_uname('s')) {
'SunOS' => preg_match('/(omnios|illumos|smartos|oi-|openindiana|joyent)/i', php_uname('v'))
? 10 * 1024 * 1024
: 8 * 1024 * 1024,
'OS400' => 0xFFFF_000, // defaults to maximum possible size
'Windows NT' => 67108864 - 4*4096, // Set by sapi/cli/config.w32
};

printf("Expected max_size: 0x%x\n", $expectedMaxSize);
printf("Actual max_size: %s\n", $stack['max_size']);

var_dump($stack['max_size'] === sprintf('0x%x', $expectedMaxSize));
// AIX/PASE returns a more exact number which is variable depending on i.e.
// OS version or other factors, due to stuff at the top of the stack. Let's
// just round to page size to try.
if (PHP_OS_FAMILY == "AIX") {
$pageSize = 4096;
$maxSize = hexdec($stack['max_size']);
$maxSize = ($maxSize + $pageSize - 1) & ~($pageSize - 1);
var_dump(sprintf('0x%x', $maxSize) === sprintf('0x%x', $expectedMaxSize));
} else {
var_dump($stack['max_size'] === sprintf('0x%x', $expectedMaxSize));
}

?>
--EXPECTF--
Expand Down
80 changes: 79 additions & 1 deletion Zend/zend_call_stack.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
#endif /* ZEND_WIN32 */
#if (defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)) || \
defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || \
defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun)
defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun) || \
defined(_AIX)
# include <pthread.h>
#endif
#if defined(__FreeBSD__) || defined(__DragonFly__)
Expand Down Expand Up @@ -788,6 +789,79 @@ static bool zend_call_stack_get_solaris(zend_call_stack *stack)
}
#endif /* defined(__sun) */

#if defined(_AIX)
static bool zend_call_stack_get_aix_pthread(zend_call_stack *stack)
{
#ifdef HAVE_PTHREAD_GETTHRDS_NP
pthread_t pt = pthread_self();
struct __pthrdsinfo thread_info = {0};
/*
* We don't need the register buffer since we only call the function
* on our own thread, and since the register buffer is only used for
* suspended threads...
*/
int regsz = 0;

if (pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_ALL, &thread_info,
sizeof(thread_info), NULL, &regsz)) {
return false;
}

/*
* These can be null in rare situations, allegedly with user-provided
* stacks with pthread (according to OpenJDK)
*/
if (!(thread_info.__pi_stackend && thread_info.__pi_stackaddr)) {
return false;
}

/*
* The top of the stack (stackend) is not page aligned, there's some
* internal stuff above it. Thankfully, we don't need page alignment.
*
* The size is a little weird. The stacksize field for child threads
* is smaller than subtracting the bottom (stackaddr) from the top;
* it's about 0x888 to 0x1888 above stackaddr. I'm assuming it rounds
* the bottom of the stack to page alignment? The main thread size is
* the same as end - addr, but it is variable between systems; also
* assuming there's stuff at the top of the stack that gets taken off,
* regardless of maximum declared size.
*
* A somewhat crude diagram is available here:
* https://www.ibm.com/docs/en/aix/7.2.0?topic=tuning-thread-environment-variables
*
* pthread->pt_stk.st_limit is __pi_stackend,
* above that is internal pthread junk close to the end of page
* pthread->pt_stk.st_base is __pi_stackaddr,
* below that is the red zone
*/
Comment thread
NattyNarwhal marked this conversation as resolved.
stack->base = thread_info.__pi_stackend;
Comment thread
NattyNarwhal marked this conversation as resolved.
stack->max_size = thread_info.__pi_stackend - thread_info.__pi_stackaddr;
return true;
#else
/* pthread likely not linked in; default NTS build behaviour */
return false;
#endif
}

static bool zend_call_stack_get_aix(zend_call_stack *stack)
{
/*
* While we could use /proc on AIX (and the implementation basically
* like the Solaris one, as the procfs is similar), it doesn't work on
* PASE. The pthread API works even on the main thread, so we should
* use it when we have pthread linked (always with ZTS, maybe not with
* NTS builds).
*/
return zend_call_stack_get_aix_pthread(stack);
}
#else
static bool zend_call_stack_get_aix(zend_call_stack *stack)
{
return false;
}
#endif /* defined(_AIX) */

/** Get the stack information for the calling thread */
ZEND_API bool zend_call_stack_get(zend_call_stack *stack)
{
Expand Down Expand Up @@ -823,6 +897,10 @@ ZEND_API bool zend_call_stack_get(zend_call_stack *stack)
return true;
}

if (zend_call_stack_get_aix(stack)) {
return true;
}

return false;
}

Expand Down
26 changes: 26 additions & 0 deletions Zend/zend_call_stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,32 @@ static inline size_t zend_call_stack_default_size(void)
#ifdef __sun
return 8 * 4096;
#endif
#ifdef _AIX
/*
* default pthread stack limit is 96 KB on 32-bit, 192 KB on 64-bit
* https://www.ibm.com/docs/en/aix/7.1.0?topic=programming-threads-library-options
*/
#ifdef HAVE_PTHREAD_GETTHRDS_NP /* if we have pthread linked (not in libc) */
if (pthread_self() != 1) {
#ifdef __64BIT__
return 192 * 1024;
#else
return 96 * 1024;
#endif
}
#endif
/*
* default AIX ulimit -s value is allegedly 32 MB, default values per:
* https://www.ibm.com/docs/en/aix/7.1.0?topic=u-ulimit-command
* N.B.: the the file uses 512b blocks, but the command uses kilobytes
* https://www.ibm.com/support/pages/ibm-aix-security-ulimit-and-ulimit-d-output-differs-value-etcsecuritylimits
*
* note PASE uses an unlimited stack size by default, which is capped
* at the PowerPC segment size (256 MB)
*/
return 32 * 1024 * 1024;
#endif


return 2 * 1024 * 1024;
}
Expand Down
Loading