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. 15static uintptr_t page_of(const void* ptr) { 16 return (uintptr_t)ptr & -PAGE_SIZE; 17} 18 19static bool do_stack_tests(bool one_page_stack) { 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 EXPECT_NE(page_of(safe_stack), page_of(environ), 42 "safe stack collides with environ"); 43 44 EXPECT_NE(page_of(unsafe_stack), page_of(environ), 45 "unsafe stack collides with environ"); 46 47 EXPECT_NE(page_of(tls_buf), page_of(environ), 48 "TLS collides with environ"); 49 50 EXPECT_NE(page_of(tls_buf), page_of(safe_stack), 51 "TLS collides with safe stack"); 52 53 EXPECT_NE(page_of(tls_buf), page_of(unsafe_stack), 54 "TLS collides with unsafe stack"); 55 56 EXPECT_NE(page_of(tp), page_of(environ), 57 "thread pointer collides with environ"); 58 59 EXPECT_NE(page_of(tp), page_of(safe_stack), 60 "thread pointer collides with safe stack"); 61 62 EXPECT_NE(page_of(tp), page_of(unsafe_stack), 63 "thread pointer collides with unsafe stack"); 64 65#ifdef __clang__ 66# if __has_feature(safe_stack) 67 const void* unsafe_start = __builtin___get_unsafe_stack_start(); 68 const void* unsafe_ptr = __builtin___get_unsafe_stack_ptr(); 69 70 if (one_page_stack) { 71 EXPECT_EQ(page_of(unsafe_start), page_of(unsafe_ptr), 72 "reported unsafe start and ptr not nearby"); 73 } 74 75 EXPECT_EQ(page_of(unsafe_stack), page_of(unsafe_ptr), 76 "unsafe stack and reported ptr not nearby"); 77 78 EXPECT_NE(page_of(unsafe_stack), page_of(safe_stack), 79 "unsafe stack collides with safe stack"); 80# endif 81#endif 82 83 END_TEST; 84} 85 86// This instance of the test is lossy, because it's possible 87// one of our single stacks spans multiple pages. We can't 88// get the main thread's stack down to a single page because 89// the unittest machinery needs more than that. 90static bool main_thread_stack_tests(void) { 91 return do_stack_tests(false); 92} 93 94static void* thread_stack_tests(void* arg) { 95 return (void*)(uintptr_t)do_stack_tests(true); 96} 97 98// Spawn a thread with a one-page stack. 99static bool other_thread_stack_tests(void) { 100 BEGIN_TEST; 101 102 EXPECT_LE(PTHREAD_STACK_MIN, PAGE_SIZE, ""); 103 104 pthread_attr_t attr; 105 ASSERT_EQ(0, pthread_attr_init(&attr), ""); 106 ASSERT_EQ(0, pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN), ""); 107 pthread_t thread; 108 ASSERT_EQ(0, pthread_create(&thread, &attr, &thread_stack_tests, 0), ""); 109 void* result; 110 ASSERT_EQ(0, pthread_join(thread, &result), ""); 111 bool other_thread_ok = (uintptr_t)result; 112 EXPECT_TRUE(other_thread_ok, ""); 113 114 END_TEST; 115} 116 117BEGIN_TEST_CASE(stack_tests) 118RUN_TEST(main_thread_stack_tests) 119RUN_TEST(other_thread_stack_tests) 120END_TEST_CASE(stack_tests) 121 122#ifndef BUILD_COMBINED_TESTS 123int main(int argc, char** argv) { 124 return unittest_run_all_tests(argc, argv) ? 0 : -1; 125} 126#endif 127