1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <limits.h>
6 #include <zircon/syscalls.h>
7 #include <pthread.h>
8 #include <runtime/tls.h>
9 #include <stdint.h>
10 #include <threads.h>
11 #include <unistd.h>
12 #include <unittest/unittest.h>
13 
14 // We request one-page stacks, so collisions are easy to catch.
page_of(const void * ptr)15 static uintptr_t page_of(const void* ptr) {
16     return (uintptr_t)ptr & -PAGE_SIZE;
17 }
18 
do_stack_tests(bool is_main_thread)19 static bool do_stack_tests(bool is_main_thread) {
20     BEGIN_TEST;
21 
22     const void* safe_stack = __builtin_frame_address(0);
23 
24     // The compiler sees this pointer escape, so it should know
25     // that this belongs on the unsafe stack.
26     char unsafe_stack[64];
27     (void)zx_system_get_version(unsafe_stack, sizeof(unsafe_stack));
28 
29     // Likewise, the tls_buf is used.
30     static thread_local char tls_buf[64];
31     (void)zx_system_get_version(tls_buf, sizeof(tls_buf));
32 
33     const void* tp = zxr_tp_get();
34 
35     EXPECT_NONNULL(environ, "environ unset");
36     EXPECT_NONNULL(safe_stack, "CFA is null");
37     EXPECT_NONNULL(unsafe_stack, "local's taken address is null");
38     EXPECT_NONNULL(tls_buf, "thread_local's taken address is null");
39     EXPECT_NONNULL(tp, "thread pointer is null");
40 
41     if (__has_feature(safe_stack) || !is_main_thread) {
42         EXPECT_NE(page_of(safe_stack), page_of(environ),
43                   "safe stack collides with environ");
44     }
45 
46     // The environ array sits on the main thread's unsafe stack.  But we can't
47     // verify that it does since it might not be on the same page.
48     if (!is_main_thread) {
49         EXPECT_NE(page_of(unsafe_stack), page_of(environ),
50                   "unsafe stack collides with environ");
51     }
52 
53     EXPECT_NE(page_of(tls_buf), page_of(environ),
54               "TLS collides with environ");
55 
56     EXPECT_NE(page_of(tls_buf), page_of(safe_stack),
57               "TLS collides with safe stack");
58 
59     EXPECT_NE(page_of(tls_buf), page_of(unsafe_stack),
60               "TLS collides with unsafe stack");
61 
62     EXPECT_NE(page_of(tp), page_of(environ),
63               "thread pointer collides with environ");
64 
65     EXPECT_NE(page_of(tp), page_of(safe_stack),
66               "thread pointer collides with safe stack");
67 
68     EXPECT_NE(page_of(tp), page_of(unsafe_stack),
69               "thread pointer collides with unsafe stack");
70 
71 #ifdef __clang__
72 # if __has_feature(safe_stack)
73     const void* unsafe_start = __builtin___get_unsafe_stack_start();
74     const void* unsafe_ptr = __builtin___get_unsafe_stack_ptr();
75 
76     if (!is_main_thread) {
77         EXPECT_EQ(page_of(unsafe_start), page_of(unsafe_ptr),
78                   "reported unsafe start and ptr not nearby");
79     }
80 
81     EXPECT_EQ(page_of(unsafe_stack), page_of(unsafe_ptr),
82               "unsafe stack and reported ptr not nearby");
83 
84     EXPECT_NE(page_of(unsafe_stack), page_of(safe_stack),
85               "unsafe stack collides with safe stack");
86 # endif
87 #endif
88 
89     END_TEST;
90 }
91 
92 // This instance of the test is lossy, because it's possible
93 // one of our single stacks spans multiple pages.  We can't
94 // get the main thread's stack down to a single page because
95 // the unittest machinery needs more than that.
main_thread_stack_tests(void)96 static bool main_thread_stack_tests(void) {
97     return do_stack_tests(true);
98 }
99 
thread_stack_tests(void * arg)100 static void* thread_stack_tests(void* arg) {
101     return (void*)(uintptr_t)do_stack_tests(false);
102 }
103 
104 // Spawn a thread with a one-page stack.
other_thread_stack_tests(void)105 static bool other_thread_stack_tests(void) {
106     BEGIN_TEST;
107 
108     EXPECT_LE(PTHREAD_STACK_MIN, PAGE_SIZE, "");
109 
110     pthread_attr_t attr;
111     ASSERT_EQ(0, pthread_attr_init(&attr), "");
112     ASSERT_EQ(0, pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN), "");
113     pthread_t thread;
114     ASSERT_EQ(0, pthread_create(&thread, &attr, &thread_stack_tests, 0), "");
115     void* result;
116     ASSERT_EQ(0, pthread_join(thread, &result), "");
117     bool other_thread_ok = (uintptr_t)result;
118     EXPECT_TRUE(other_thread_ok, "");
119 
120     END_TEST;
121 }
122 
123 BEGIN_TEST_CASE(stack_tests)
RUN_TEST(main_thread_stack_tests)124 RUN_TEST(main_thread_stack_tests)
125 RUN_TEST(other_thread_stack_tests)
126 END_TEST_CASE(stack_tests)
127 
128 #ifndef BUILD_COMBINED_TESTS
129 int main(int argc, char** argv) {
130     return unittest_run_all_tests(argc, argv) ? 0 : -1;
131 }
132 #endif
133