summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--js/src/jsnativestack.cpp68
1 files changed, 65 insertions, 3 deletions
diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp
index 05928ea3d..166a5a4f7 100644
--- a/js/src/jsnativestack.cpp
+++ b/js/src/jsnativestack.cpp
@@ -21,6 +21,18 @@
# include <unistd.h>
# endif
+# if defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__)
+# include <dlfcn.h>
+# include <sys/syscall.h>
+# include <sys/types.h>
+# include <unistd.h>
+static pid_t
+gettid()
+{
+ return syscall(__NR_gettid);
+}
+# endif
+
#else
# error "Unsupported platform"
@@ -88,6 +100,52 @@ js::GetNativeStackBaseImpl()
context.uc_stack.ss_size;
}
+#elif defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__)
+void*
+js::GetNativeStackBaseImpl()
+{
+ // On the main thread, get stack base from glibc's __libc_stack_end rather than pthread APIs
+ // to avoid filesystem calls /proc/self/maps. Non-main threads spawned with pthreads can read
+ // this information directly from their pthread struct, but when using the pthreads API, the
+ // main thread must go parse /proc/self/maps to figure the mapped stack address space ranges.
+ // We want to avoid reading from /proc/ so that the application can run in restricted
+ // environments where /proc may not be mounted (e.g. chroot).
+ if (gettid() == getpid()) {
+ void** pLibcStackEnd = (void**)dlsym(RTLD_DEFAULT, "__libc_stack_end");
+
+ // If __libc_stack_end is not found, architecture specific frame pointer hopping will need
+ // to be implemented.
+ MOZ_RELEASE_ASSERT(pLibcStackEnd, "__libc_stack_end unavailable, unable to setup stack range for JS.");
+ void* stackBase = *pLibcStackEnd;
+ MOZ_RELEASE_ASSERT(stackBase, "Invalid stack base, unable to setup stack range for JS.");
+
+ // We don't need to fix stackBase, as it already roughly points to beginning of the stack.
+ return stackBase;
+ }
+
+ // Non-main threads have the required info stored in memory, so no filesystem calls are made.
+ pthread_t thread = pthread_self();
+ pthread_attr_t sattr;
+ pthread_attr_init(&sattr);
+ pthread_getattr_np(thread, &sattr);
+
+ // stackBase will be the *lowest* address on all architectures.
+ void* stackBase = nullptr;
+ size_t stackSize = 0;
+ int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
+ if (rc) {
+ MOZ_CRASH("Call to pthread_attr_getstack failed, unable to setup stack range for JS.");
+ }
+ MOZ_RELEASE_ASSERT(stackBase, "Invalid stack base, unable to setup stack range for JS.");
+ pthread_attr_destroy(&sattr);
+
+# if JS_STACK_GROWTH_DIRECTION > 0
+ return stackBase;
+# else
+ return static_cast<char*>(stackBase) + stackSize;
+# endif
+}
+
#else /* XP_UNIX */
void*
@@ -156,11 +214,15 @@ js::GetNativeStackBaseImpl()
// the truth.
rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
# else
+ // Use the default pthread_attr_getstack() call. Note that this function
+ // differs between libc implementations and could imply /proc access etc.
+ // which may not work in restricted environments.
rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
# endif
- if (rc)
- MOZ_CRASH();
- MOZ_ASSERT(stackBase);
+ if (rc) {
+ MOZ_CRASH("Call to pthread_attr_getstack failed, unable to setup stack range for JS.");
+ }
+ MOZ_RELEASE_ASSERT(stackBase, "Invalid stack base, unable to setup stack range for JS.");
pthread_attr_destroy(&sattr);
# if JS_STACK_GROWTH_DIRECTION > 0