php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
zend_call_stack.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Arnaud Le Blanc <arnaud.lb@gmail.com> |
16 +----------------------------------------------------------------------+
17*/
18
19/* Inspired from Chromium's stack_util.cc */
20
21#include "zend.h"
22#include "zend_globals.h"
23#include "zend_portability.h"
24#include "zend_call_stack.h"
25#include <stdint.h>
26#ifdef ZEND_WIN32
27# include <processthreadsapi.h>
28# include <memoryapi.h>
29#else /* ZEND_WIN32 */
30# include <sys/resource.h>
31# ifdef HAVE_UNISTD_H
32# include <unistd.h>
33# endif
34# ifdef HAVE_SYS_TYPES_H
35# include <sys/types.h>
36# endif
37#endif /* ZEND_WIN32 */
38#if (defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)) || \
39 defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || \
40 defined(__NetBSD__) || defined(__DragonFly__) || defined(__sun)
41# include <pthread.h>
42#endif
43#if defined(__FreeBSD__) || defined(__DragonFly__)
44# include <pthread_np.h>
45# include <sys/mman.h>
46# include <sys/sysctl.h>
47# include <sys/user.h>
48#endif
49#ifdef __OpenBSD__
50typedef int boolean_t;
51# include <tib.h>
52# include <pthread_np.h>
53# include <sys/sysctl.h>
54# include <sys/user.h>
55#endif
56#ifdef __NetBSD__
57# include <sys/sysctl.h>
58# include <sys/syscall.h>
59#endif
60#ifdef __HAIKU__
61# include <kernel/OS.h>
62#endif
63#ifdef __linux__
64#include <sys/syscall.h>
65#endif
66#ifdef __sun
67# include <sys/lwp.h>
68# ifdef HAVE_LIBPROC_H
69# define _STRUCTURED_PROC 1
70# include <sys/procfs.h>
71# include <libproc.h>
72# endif
73#include <thread.h>
74#endif
75
76#ifdef HAVE_VALGRIND
77# include <valgrind/valgrind.h>
78#endif
79
80#ifdef ZEND_CHECK_STACK_LIMIT
81
82/* Called once per process or thread */
83ZEND_API void zend_call_stack_init(void) {
84 if (!zend_call_stack_get(&EG(call_stack))) {
85 EG(call_stack) = (zend_call_stack){0};
86 }
87
88 switch (EG(max_allowed_stack_size)) {
89 case ZEND_MAX_ALLOWED_STACK_SIZE_DETECT: {
90 void *base = EG(call_stack).base;
91 size_t size = EG(call_stack).max_size;
92 if (UNEXPECTED(base == (void*)0)) {
93 base = zend_call_stack_position();
94 size = zend_call_stack_default_size();
95 /* base is not the actual stack base */
96 size -= 32 * 1024;
97 }
98 EG(stack_base) = base;
99 EG(stack_limit) = zend_call_stack_limit(base, size, EG(reserved_stack_size));
100 break;
101 }
102 case ZEND_MAX_ALLOWED_STACK_SIZE_UNCHECKED: {
103 EG(stack_base) = (void*)0;
104 EG(stack_limit) = (void*)0;
105 break;
106 }
107 default: {
108 ZEND_ASSERT(EG(max_allowed_stack_size) > 0);
109 void *base = EG(call_stack).base;
110 if (UNEXPECTED(base == (void*)0)) {
111 base = zend_call_stack_position();
112 }
113 EG(stack_base) = base;
114 EG(stack_limit) = zend_call_stack_limit(base, EG(max_allowed_stack_size), EG(reserved_stack_size));
115 break;
116 }
117 }
118}
119
120#ifdef __linux__
121static bool zend_call_stack_is_main_thread(void) {
122# ifdef HAVE_GETTID
123 return getpid() == gettid();
124# else
125 return getpid() == syscall(SYS_gettid);
126# endif
127}
128
129# if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
130static bool zend_call_stack_get_linux_pthread(zend_call_stack *stack)
131{
132 pthread_attr_t attr;
133 int error;
134 void *addr;
135 size_t max_size;
136
137 /* pthread_getattr_np() will return bogus values for the main thread with
138 * musl or with some old glibc versions */
139 ZEND_ASSERT(!zend_call_stack_is_main_thread());
140
141 error = pthread_getattr_np(pthread_self(), &attr);
142 if (UNEXPECTED(error)) {
143 return false;
144 }
145
146 error = pthread_attr_getstack(&attr, &addr, &max_size);
147 if (UNEXPECTED(error)) {
148 pthread_attr_destroy(&attr);
149 return false;
150 }
151
152# if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 8))
153 {
154 size_t guard_size;
155 /* In glibc prior to 2.8, addr and size include the guard pages */
156 error = pthread_attr_getguardsize(&attr, &guard_size);
157 if (UNEXPECTED(error)) {
158 pthread_attr_destroy(&attr);
159 return false;
160 }
161
162 addr = (int8_t*)addr + guard_size;
163 max_size -= guard_size;
164 }
165# endif /* glibc < 2.8 */
166
167 stack->base = (int8_t*)addr + max_size;
168 stack->max_size = max_size;
169
170 pthread_attr_destroy(&attr);
171
172 return true;
173}
174# else /* defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK) */
175static bool zend_call_stack_get_linux_pthread(zend_call_stack *stack)
176{
177 return false;
178}
179# endif /* defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK) */
180
181static bool zend_call_stack_get_linux_proc_maps(zend_call_stack *stack)
182{
183 FILE *f;
184 char buffer[4096];
185 uintptr_t addr_on_stack = (uintptr_t) zend_call_stack_position();
186 uintptr_t start, end, prev_end = 0;
187 size_t max_size;
188 bool found = false;
189 struct rlimit rlim;
190 int error;
191
192 /* This method is relevant only for the main thread */
193 ZEND_ASSERT(zend_call_stack_is_main_thread());
194
195 /* Scan the process memory mappings to find the one containing the stack.
196 *
197 * The end of the stack mapping is the base of the stack. The start is
198 * adjusted by the kernel as the stack grows. The maximum stack size is
199 * determined by RLIMIT_STACK and the previous mapping.
200 *
201 *
202 * ^ Higher addresses ^
203 * : :
204 * : :
205 * Mapping end --> |-------------------| <-- Stack base (stack start)
206 * | | ^
207 * | Stack Mapping | | Stack size
208 * | | v
209 * Mapping start --> |-------------------| <-- Current stack end
210 * (adjusted : :
211 * downwards as the . .
212 * stack grows) : :
213 * |-------------------|
214 * | Some Mapping | The previous mapping may prevent
215 * |-------------------| stack growth
216 * : :
217 * : :
218 * v Lower addresses v
219 */
220
221 f = fopen("/proc/self/maps", "r");
222 if (!f) {
223 return false;
224 }
225
226 while (fgets(buffer, sizeof(buffer), f) && sscanf(buffer, "%" SCNxPTR "-%" SCNxPTR, &start, &end) == 2) {
227 if (start <= addr_on_stack && end >= addr_on_stack) {
228 found = true;
229 break;
230 }
231 prev_end = end;
232 }
233
234 fclose(f);
235
236 if (!found) {
237 return false;
238 }
239
240 error = getrlimit(RLIMIT_STACK, &rlim);
241 if (error || rlim.rlim_cur == RLIM_INFINITY) {
242 return false;
243 }
244
245 max_size = rlim.rlim_cur;
246
247#ifdef HAVE_VALGRIND
248 /* Under Valgrind, the last page is not useable */
249 if (RUNNING_ON_VALGRIND) {
250 max_size -= zend_get_page_size();
251 }
252#endif
253
254 /* Previous mapping may prevent the stack from growing */
255 if (end - max_size < prev_end) {
256 max_size = prev_end - end;
257 }
258
259 stack->base = (void*)end;
260 stack->max_size = max_size;
261
262 return true;
263}
264
265static bool zend_call_stack_get_linux(zend_call_stack *stack)
266{
267 if (zend_call_stack_is_main_thread()) {
268 return zend_call_stack_get_linux_proc_maps(stack);
269 }
270
271 return zend_call_stack_get_linux_pthread(stack);
272}
273#else /* __linux__ */
274static bool zend_call_stack_get_linux(zend_call_stack *stack)
275{
276 return false;
277}
278#endif /* __linux__ */
279
280#if defined(__FreeBSD__) || defined(__DragonFly__)
281static bool zend_call_stack_is_main_thread(void)
282{
283 int is_main = pthread_main_np();
284 return is_main == -1 || is_main == 1;
285}
286
287# if defined(HAVE_PTHREAD_ATTR_GET_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
288static bool zend_call_stack_get_freebsd_pthread(zend_call_stack *stack)
289{
290 pthread_attr_t attr;
291 int error;
292 void *addr;
293 size_t max_size;
294
295 /* pthread will return bogus values for the main thread */
296 ZEND_ASSERT(!zend_call_stack_is_main_thread());
297
298 pthread_attr_init(&attr);
299
300 error = pthread_attr_get_np(pthread_self(), &attr);
301 if (error) {
302 goto fail;
303 }
304
305 error = pthread_attr_getstack(&attr, &addr, &max_size);
306 if (error) {
307 goto fail;
308 }
309
310 stack->base = (int8_t*)addr + max_size;
311 stack->max_size = max_size;
312
313 pthread_attr_destroy(&attr);
314 return true;
315
316fail:
317 pthread_attr_destroy(&attr);
318 return false;
319}
320# else /* defined(HAVE_PTHREAD_ATTR_GET_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK) */
321static bool zend_call_stack_get_freebsd_pthread(zend_call_stack *stack)
322{
323 return false;
324}
325# endif /* defined(HAVE_PTHREAD_ATTR_GET_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK) */
326
327static bool zend_call_stack_get_freebsd_sysctl(zend_call_stack *stack)
328{
329 void *stack_base;
330 int mib[2] = {CTL_KERN, KERN_USRSTACK};
331 size_t len = sizeof(stack_base);
332 struct rlimit rlim;
333 size_t numguards = 0;
334
335 /* This method is relevant only for the main thread */
336 ZEND_ASSERT(zend_call_stack_is_main_thread());
337
338 if (sysctl(mib, sizeof(mib)/sizeof(*mib), &stack_base, &len, NULL, 0) != 0) {
339 return false;
340 }
341
342 if (getrlimit(RLIMIT_STACK, &rlim) != 0) {
343 return false;
344 }
345
346 if (rlim.rlim_cur == RLIM_INFINITY) {
347 return false;
348 }
349
350 len = sizeof(numguards);
351 /* For most of the cases, we do not necessarily need to do so as, by default, it is `1` page, but is user writable */
352 if (sysctlbyname("security.bsd.stack_guard_page", &numguards, &len, NULL, 0) != 0) {
353 return false;
354 }
355
356 size_t guard_size = numguards * getpagesize();
357
358 stack->base = stack_base;
359 stack->max_size = rlim.rlim_cur - guard_size;
360
361 return true;
362}
363
364static bool zend_call_stack_get_freebsd(zend_call_stack *stack)
365{
366 if (zend_call_stack_is_main_thread()) {
367 return zend_call_stack_get_freebsd_sysctl(stack);
368 }
369
370 return zend_call_stack_get_freebsd_pthread(stack);
371}
372#else
373static bool zend_call_stack_get_freebsd(zend_call_stack *stack)
374{
375 return false;
376}
377#endif /* __FreeBSD__ */
378
379#ifdef ZEND_WIN32
380static bool zend_call_stack_get_win32(zend_call_stack *stack)
381{
382 ULONG_PTR low_limit, high_limit;
383 ULONG size;
384 MEMORY_BASIC_INFORMATION guard_region = {0}, uncommitted_region = {0};
385 size_t result_size, page_size;
386
387 /* The stack consists of three regions: committed, guard, and uncommitted.
388 * Memory is committed when the guard region is accessed. If only one page
389 * is left in the uncommitted region, a stack overflow error is raised
390 * instead.
391 *
392 * The total useable stack size is the size of the committed and uncommitted
393 * regions less one page.
394 *
395 * http://blogs.msdn.com/b/satyem/archive/2012/08/13/thread-s-stack-memory-management.aspx
396 * https://learn.microsoft.com/en-us/windows/win32/procthread/thread-stack-size
397 *
398 * ^ Higher addresses ^
399 * : :
400 * : :
401 * high_limit --> |--------------------|
402 * ^ | |
403 * | | Committed region |
404 * | | |
405 * | |------------------- | <-- guard_region.BaseAddress
406 * reserved | | | + guard_region.RegionSize
407 * size | | Guard region |
408 * | | |
409 * | |--------------------| <-- guard_region.BaseAddress,
410 * | | | uncommitted_region.BaseAddress
411 * | | Uncommitted region | + uncommitted_region.RegionSize
412 * v | |
413 * low_limit --> |------------------- | <-- uncommitted_region.BaseAddress
414 * : :
415 * : :
416 * v Lower addresses v
417 */
418
419 GetCurrentThreadStackLimits(&low_limit, &high_limit);
420
421 result_size = VirtualQuery((void*)low_limit,
422 &uncommitted_region, sizeof(uncommitted_region));
423 ZEND_ASSERT(result_size >= sizeof(uncommitted_region));
424
425 result_size = VirtualQuery((int8_t*)uncommitted_region.BaseAddress + uncommitted_region.RegionSize,
426 &guard_region, sizeof(guard_region));
427 ZEND_ASSERT(result_size >= sizeof(uncommitted_region));
428
429 stack->base = (void*)high_limit;
430 stack->max_size = (uintptr_t)high_limit - (uintptr_t)low_limit;
431
432 ZEND_ASSERT(stack->max_size > guard_region.RegionSize);
433 stack->max_size -= guard_region.RegionSize;
434
435 /* The uncommitted region does not shrink below 1 page */
436 page_size = zend_get_page_size();
437 ZEND_ASSERT(stack->max_size > page_size);
438 stack->max_size -= page_size;
439
440 return true;
441}
442#else /* ZEND_WIN32 */
443static bool zend_call_stack_get_win32(zend_call_stack *stack)
444{
445 return false;
446}
447#endif /* ZEND_WIN32 */
448
449#if defined(__APPLE__) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
450static bool zend_call_stack_get_macos(zend_call_stack *stack)
451{
452 void *base = pthread_get_stackaddr_np(pthread_self());
453 size_t max_size;
454
455#if !defined(__aarch64__)
456 if (pthread_main_np())
457 {
458 /* pthread_get_stacksize_np() returns a too low value for the main
459 * thread in OSX 10.9, 10.10:
460 * https://mail.openjdk.org/pipermail/hotspot-dev/2013-October/011353.html
461 * https://github.com/rust-lang/rust/issues/43347
462 */
463
464 /* Stack size is 8MiB by default for main threads
465 * https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html */
466 max_size = 8 * 1024 * 1024;
467 }
468 else
469#endif
470 {
471 max_size = pthread_get_stacksize_np(pthread_self());
472 }
473
474 stack->base = base;
475 stack->max_size = max_size;
476
477 return true;
478}
479#else /* defined(__APPLE__) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) */
480static bool zend_call_stack_get_macos(zend_call_stack *stack)
481{
482 return false;
483}
484#endif /* defined(__APPLE__) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) */
485
486#if defined(__OpenBSD__)
487#if defined(HAVE_PTHREAD_STACKSEG_NP)
488static bool zend_call_stack_get_openbsd_pthread(zend_call_stack *stack)
489{
490 stack_t ss;
491
492 if (pthread_stackseg_np(pthread_self(), &ss) != 0) {
493 return false;
494 }
495
496 stack->base = (char *)ss.ss_sp - ss.ss_size;
497 stack->max_size = ss.ss_size - sysconf(_SC_PAGE_SIZE);
498
499 return true;
500}
501#else
502static bool zend_call_stack_get_openbsd_pthread(zend_call_stack *stack)
503{
504 return false;
505}
506#endif /* defined(HAVE_PTHREAD_STACKSEG_NP) */
507
508static bool zend_call_stack_get_openbsd_vm(zend_call_stack *stack)
509{
510 struct _ps_strings ps;
511 struct rlimit rlim;
512 int mib[2] = {CTL_VM, VM_PSSTRINGS };
513 size_t len = sizeof(ps), pagesize;
514
515 if (sysctl(mib, 2, &ps, &len, NULL, 0) != 0) {
516 return false;
517 }
518
519 if (getrlimit(RLIMIT_STACK, &rlim) != 0) {
520 return false;
521 }
522
523 if (rlim.rlim_cur == RLIM_INFINITY) {
524 return false;
525 }
526
527 pagesize = sysconf(_SC_PAGE_SIZE);
528
529 stack->base = (void *)((uintptr_t)ps.val + (pagesize - 1) & ~(pagesize - 1));
530 stack->max_size = rlim.rlim_cur - pagesize;
531
532 return true;
533}
534
535static bool zend_call_stack_get_openbsd(zend_call_stack *stack)
536{
537 // TIB_THREAD_INITIAL_STACK is private and here we avoid using pthread's api (ie pthread_main_np)
538 if (!TIB_GET()->tib_thread || (TIB_GET()->tib_thread_flags & 0x002) != 0) {
539 return zend_call_stack_get_openbsd_vm(stack);
540 }
541
542 return zend_call_stack_get_openbsd_pthread(stack);
543}
544
545#else
546static bool zend_call_stack_get_openbsd(zend_call_stack *stack)
547{
548 return false;
549}
550#endif /* defined(__OpenBSD__) */
551#if defined(__HAIKU__)
552static bool zend_call_stack_get_haiku(zend_call_stack *stack)
553{
554 thread_id id;
555 thread_info ti;
556 size_t guard_size;
557
558 // unlikely, main thread ought to be always available but we never know
559 if ((id = find_thread(NULL)) == B_NAME_NOT_FOUND || get_thread_info(id, &ti) != B_OK) {
560 return false;
561 }
562
563 // USER_STACK_GUARD_SIZE
564 guard_size = sysconf(_SC_PAGESIZE) * 4;
565
566 stack->base = ti.stack_end;
567 stack->max_size = ((size_t)ti.stack_end - (size_t)ti.stack_base) - guard_size;
568
569 return true;
570}
571#else
572static bool zend_call_stack_get_haiku(zend_call_stack *stack)
573{
574 return false;
575}
576#endif /* defined(__HAIKU__) */
577
578#if defined(__NetBSD__)
579# ifdef HAVE_PTHREAD_GETATTR_NP
580static bool zend_call_stack_get_netbsd_pthread(zend_call_stack *stack)
581{
582 pthread_attr_t attr;
583 int error;
584 void *addr;
585 size_t max_size, guard_size;
586
587 error = pthread_getattr_np(pthread_self(), &attr);
588 if (error) {
589 return false;
590 }
591
592 error = pthread_attr_getstack(&attr, &addr, &max_size);
593 if (error) {
594 return false;
595 }
596
597 error = pthread_attr_getguardsize(&attr, &guard_size);
598 if (error) {
599 return false;
600 }
601
602 addr = (char *)addr + guard_size;
603 max_size -= guard_size;
604
605 stack->base = (char *)addr + max_size;
606 stack->max_size = max_size;
607
608 return true;
609}
610# else
611static bool zend_call_stack_get_netbsd_pthread(zend_call_stack *stack)
612{
613 return false;
614}
615# endif /* HAVE_PTHREAD_GETATTR_NP */
616static bool zend_call_stack_get_netbsd_vm(zend_call_stack *stack, void **ptr)
617{
622 char *start, *end;
623 struct kinfo_vmentry *entry;
624 size_t len, max_size;
625 uintptr_t addr_on_stack = (uintptr_t) zend_call_stack_position();
626 int mib[5] = { CTL_VM, VM_PROC, VM_PROC_MAP, getpid(), sizeof(struct kinfo_vmentry) };
627 bool found = false;
628 struct rlimit rlim;
629
630 if (sysctl(mib, 5, NULL, &len, NULL, 0) != 0) {
631 return false;
632 }
633
634 // kinfo_getvmmap uses the same formula, only we do not want to rely on libkvm
635 len = len * 4 / 3 ;
636 *ptr = malloc(len);
637
638 if (sysctl(mib, 5, *ptr, &len, NULL, 0) != 0) {
639 return false;
640 }
641
642 start = (char *)*ptr;
643 end = start + len;
644
645 while (start < end) {
646 entry = (struct kinfo_vmentry *)start;
647 if (entry->kve_start <= addr_on_stack && entry->kve_end >= addr_on_stack) {
648 found = true;
649 break;
650 }
651
652 start += sizeof(struct kinfo_vmentry);
653 }
654
655 if (!found) {
656 return false;
657 }
658
659 if (getrlimit(RLIMIT_STACK, &rlim) || rlim.rlim_cur == RLIM_INFINITY) {
660 return false;
661 }
662
663 max_size = rlim.rlim_cur;
664
665 stack->base = (void *)entry->kve_end;
666 stack->max_size = max_size;
667
668 return true;
669}
670
671
672static bool zend_call_stack_get_netbsd(zend_call_stack *stack)
673{
674 if (syscall(SYS__lwp_self) == 1) {
675 void *ptr = NULL;
676 bool r = zend_call_stack_get_netbsd_vm(stack, &ptr);
677 free(ptr);
678 return r;
679 }
680
681 return zend_call_stack_get_netbsd_pthread(stack);
682}
683#else
684static bool zend_call_stack_get_netbsd(zend_call_stack *stack)
685{
686 return false;
687}
688#endif /* defined(__NetBSD__) */
689
690#if defined(__sun)
691static bool zend_call_stack_get_solaris_pthread(zend_call_stack *stack)
692{
693 stack_t s;
694 if (thr_stksegment(&s) < 0) {
695 return false;
696 }
697
698 stack->max_size = s.ss_size;
699 stack->base = s.ss_sp;
700 return true;
701}
702
703#ifdef HAVE_LIBPROC_H
704static bool zend_call_stack_get_solaris_proc_maps(zend_call_stack *stack)
705{
706 uintptr_t addr_on_stack = (uintptr_t) zend_call_stack_position();
707 bool found = false, r = false;
708 struct ps_prochandle *proc;
709 prmap_t *map, *orig;
710 struct rlimit rlim;
711 char path[PATH_MAX];
712 size_t size;
713 ssize_t len = -1;
714 pid_t pid;
715 int error, fd;
716
717 pid = getpid();
718 proc = Pgrab(pid, PGRAB_RDONLY, &error);
719 if (!proc) {
720 return false;
721 }
722
723 size = (1 << 20);
724 snprintf(path, sizeof(path), "/proc/%d/map", (int)pid);
725
726 if ((fd = open(path, O_RDONLY)) == -1) {
727 Prelease(proc, 0);
728 return false;
729 }
730
731 orig = malloc(size);
732 if (!orig) {
733 Prelease(proc, 0);
734 close(fd);
735 return false;
736 }
737
738 while (size > 0 && (len = pread(fd, orig, size, 0)) == size) {
739 prmap_t *tmp;
740 size <<= 1;
741 tmp = realloc(orig, size);
742 if (!tmp) {
743 goto end;
744 }
745 orig = tmp;
746 }
747
748 for (map = orig; len > 0; ++map) {
749 if ((uintptr_t)map->pr_vaddr <= addr_on_stack && (uintptr_t)map->pr_vaddr + map->pr_size >= addr_on_stack) {
750 found = true;
751 break;
752 }
753 len -= sizeof(*map);
754 }
755
756 if (!found) {
757 goto end;
758 }
759
760 error = getrlimit(RLIMIT_STACK, &rlim);
761 if (error || rlim.rlim_cur == RLIM_INFINITY) {
762 goto end;
763 }
764
765 stack->base = (void *)map->pr_vaddr + map->pr_size;
766 stack->max_size = rlim.rlim_cur;
767 r = true;
768
769end:
770 free(orig);
771 Prelease(proc, 0);
772 close(fd);
773 return r;
774}
775#endif
776
777static bool zend_call_stack_get_solaris(zend_call_stack *stack)
778{
779#ifdef HAVE_LIBPROC_H
780 if (_lwp_self() == 1) {
781 return zend_call_stack_get_solaris_proc_maps(stack);
782 }
783#endif
784 return zend_call_stack_get_solaris_pthread(stack);
785}
786#else
787static bool zend_call_stack_get_solaris(zend_call_stack *stack)
788{
789 return false;
790}
791#endif /* defined(__sun) */
792
794ZEND_API bool zend_call_stack_get(zend_call_stack *stack)
795{
796 if (zend_call_stack_get_linux(stack)) {
797 return true;
798 }
799
800 if (zend_call_stack_get_freebsd(stack)) {
801 return true;
802 }
803
804 if (zend_call_stack_get_win32(stack)) {
805 return true;
806 }
807
808 if (zend_call_stack_get_macos(stack)) {
809 return true;
810 }
811
812 if (zend_call_stack_get_openbsd(stack)) {
813 return true;
814 }
815
816 if (zend_call_stack_get_netbsd(stack)) {
817 return true;
818 }
819
820 if (zend_call_stack_get_haiku(stack)) {
821 return true;
822 }
823
824 if (zend_call_stack_get_solaris(stack)) {
825 return true;
826 }
827
828 return false;
829}
830
831#endif /* ZEND_CHECK_STACK_LIMIT */
size_t len
Definition apprentice.c:174
sscanf(string $string, string $format, mixed &... $vars)
fclose($stream)
fopen(string $filename, string $mode, bool $use_include_path=false, $context=null)
fgets($stream, ?int $length=null)
char s[4]
Definition cdf.c:77
error($message)
Definition ext_skel.php:22
new_type size
Definition ffi.c:4365
void * ptr
Definition ffi.c:3814
new_type attr
Definition ffi.c:4364
buf start
Definition ffi.c:4687
#define NULL
Definition gdcache.h:45
unsigned const char * end
Definition php_ffi.h:51
int fd
Definition phpdbg.h:282
bool fail
Definition session.c:1065
sljit_gpr base
Definition file.h:177
#define close(a)
ZEND_API size_t zend_get_page_size(void)
Definition zend.c:1269
#define ZEND_API
#define snprintf
#define EG(v)
#define ZEND_ASSERT(c)
#define UNEXPECTED(condition)