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