1 // Copyright 2016 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 <float.h>
6 #include <limits.h>
7 #include <sched.h>
8 #include <stdint.h>
9 #include <threads.h>
10 
11 #include <unittest/unittest.h>
12 
13 static thread_local bool u1 = true;
14 static thread_local uint8_t u8 = UINT8_MAX;
15 static thread_local uint16_t u16 = UINT16_MAX;
16 static thread_local uint32_t u32 = UINT32_MAX;
17 static thread_local uint64_t u64 = UINT64_MAX;
18 static thread_local uintptr_t uptr = UINTPTR_MAX;
19 static thread_local int8_t i8 = INT8_MAX;
20 static thread_local int16_t i16 = INT16_MAX;
21 static thread_local int32_t i32 = INT32_MAX;
22 static thread_local int64_t i64 = INT64_MAX;
23 static thread_local intptr_t iptr = INTPTR_MAX;
24 static thread_local float f32 = FLT_MAX;
25 static thread_local double f64 = DBL_MAX;
26 static thread_local void* ptr = &ptr;
27 static thread_local struct {
28     uint64_t bits0 : 9;
29     uint64_t bits1 : 9;
30     uint64_t bits2 : 9;
31     uint64_t bits3 : 9;
32     uint64_t bits4 : 9;
33     uint64_t bits5 : 9;
34     uint64_t bits6 : 9;
35     double f64;
36     uint64_t bits7 : 9;
37     uint64_t bits8 : 9;
38     uint64_t bits9 : 9;
39     uint64_t bits10 : 9;
40     uint64_t bits11 : 9;
41     uint64_t bits12 : 9;
42     uint64_t bits13 : 9;
43 } bits = {
44     0x1ffu,
45     0x1ffu,
46     0x1ffu,
47     0x1ffu,
48     0x1ffu,
49     0x1ffu,
50     0x1ffu,
51     DBL_MAX,
52     0x1ffu,
53     0x1ffu,
54     0x1ffu,
55     0x1ffu,
56     0x1ffu,
57     0x1ffu,
58     0x1ffu,
59 };
60 #define BYTES_4 0xffu, 0xffu, 0xffu, 0xffu,
61 #define BYTES_16 BYTES_4 BYTES_4 BYTES_4 BYTES_4
62 #define BYTES_64 BYTES_16 BYTES_16 BYTES_16 BYTES_16
63 #define BYTES_256 BYTES_64 BYTES_64 BYTES_64 BYTES_64
64 #define BYTES_1024 BYTES_256 BYTES_256 BYTES_256 BYTES_256
65 static thread_local uint8_t array[1024] = { BYTES_1024 };
66 static thread_local struct Ctor {
CtorCtor67     Ctor() : x_(UINT64_MAX) {}
68     uint64_t x_;
69 } ctor;
70 static thread_local uint8_t big_array[1 << 20];
71 
72 __attribute__((aligned(0x1000))) thread_local int aligned_var = 123;
73 
CheckInitializers()74 bool CheckInitializers() {
75     BEGIN_TEST;
76 
77     ASSERT_EQ(u1, true, "unexpected initialized value");
78     ASSERT_EQ(u8, UINT8_MAX, "unexpected initialized value");
79     ASSERT_EQ(u16, UINT16_MAX, "unexpected initialized value");
80     ASSERT_EQ(u32, UINT32_MAX, "unexpected initialized value");
81     ASSERT_EQ(u64, UINT64_MAX, "unexpected initialized value");
82     ASSERT_EQ(uptr, UINTPTR_MAX, "unexpected initialized value");
83     ASSERT_EQ(i8, INT8_MAX, "unexpected initialized value");
84     ASSERT_EQ(i16, INT16_MAX, "unexpected initialized value");
85     ASSERT_EQ(i32, INT32_MAX, "unexpected initialized value");
86     ASSERT_EQ(i64, INT64_MAX, "unexpected initialized value");
87     ASSERT_EQ(iptr, INTPTR_MAX, "unexpected initialized value");
88     ASSERT_EQ(f32, FLT_MAX, "unexpected initialized value");
89     ASSERT_EQ(f64, DBL_MAX, "unexpected initialized value");
90     ASSERT_EQ(ptr, &ptr, "unexpected initialized value");
91 
92     ASSERT_EQ(bits.bits0, 0x1ffu, "unexpected initialized value");
93     ASSERT_EQ(bits.bits1, 0x1ffu, "unexpected initialized value");
94     ASSERT_EQ(bits.bits2, 0x1ffu, "unexpected initialized value");
95     ASSERT_EQ(bits.bits3, 0x1ffu, "unexpected initialized value");
96     ASSERT_EQ(bits.bits4, 0x1ffu, "unexpected initialized value");
97     ASSERT_EQ(bits.bits5, 0x1ffu, "unexpected initialized value");
98     ASSERT_EQ(bits.bits6, 0x1ffu, "unexpected initialized value");
99     ASSERT_EQ(bits.f64, DBL_MAX, "unexpected initialized value");
100     ASSERT_EQ(bits.bits7, 0x1ffu, "unexpected initialized value");
101     ASSERT_EQ(bits.bits8, 0x1ffu, "unexpected initialized value");
102     ASSERT_EQ(bits.bits9, 0x1ffu, "unexpected initialized value");
103     ASSERT_EQ(bits.bits10, 0x1ffu, "unexpected initialized value");
104     ASSERT_EQ(bits.bits11, 0x1ffu, "unexpected initialized value");
105     ASSERT_EQ(bits.bits12, 0x1ffu, "unexpected initialized value");
106     ASSERT_EQ(bits.bits13, 0x1ffu, "unexpected initialized value");
107 
108     for (auto& byte : array)
109         ASSERT_EQ(byte, UINT8_MAX, "unexpected initialized value");
110 
111     ASSERT_EQ(ctor.x_, UINT64_MAX, "unexpected initialized value");
112 
113     uint8_t sum = 0u;
114     for (auto& byte : big_array)
115         sum |= byte;
116     ASSERT_EQ(sum, 0u, "unexpected initialized value");
117 
118     // TODO(ZX-1646): Make this work on ARM64.
119     EXPECT_EQ((uintptr_t)&aligned_var % 0x1000, 0);
120     EXPECT_EQ(aligned_var, 123);
121 
122     END_TEST;
123 }
124 
TestArraySpam(uintptr_t idx)125 bool TestArraySpam(uintptr_t idx) {
126     BEGIN_TEST;
127 
128     for (uintptr_t iteration = 0; iteration < 100; ++iteration) {
129         auto starting_value = static_cast<uint8_t>(idx + iteration);
130         auto value = starting_value;
131         for (auto& byte : array) {
132             byte = value;
133             ++value;
134         }
135         sched_yield();
136         value = starting_value;
137         for (auto& byte : array) {
138             ASSERT_EQ(byte, value, "unexpected value read back!");
139             ++value;
140         }
141     }
142 
143     END_TEST;
144 }
145 
TestThread(void * arg)146 int TestThread(void* arg) {
147     auto idx = reinterpret_cast<uintptr_t>(arg);
148 
149     CheckInitializers();
150     TestArraySpam(idx);
151     return 0;
152 }
153 
ExecutableTlsTest()154 bool ExecutableTlsTest() {
155     BEGIN_TEST;
156 
157     constexpr uintptr_t thread_count = 64u;
158     thrd_t threads[thread_count];
159     for (uintptr_t idx = 0u; idx < thread_count; ++idx) {
160         auto arg = reinterpret_cast<void*>(idx);
161         int ret = thrd_create_with_name(&threads[idx], &TestThread, arg, "elf tls test");
162         ASSERT_EQ(ret, thrd_success, "unable to create test thread");
163     }
164     for (uintptr_t idx = 0u; idx < thread_count; ++idx) {
165         int ret = thrd_join(threads[idx], nullptr);
166         ASSERT_EQ(ret, thrd_success, "unable to join test thread");
167     }
168 
169     TestThread(nullptr);
170 
171     END_TEST;
172 }
173 
174 BEGIN_TEST_CASE(elf_tls_tests)
RUN_TEST(ExecutableTlsTest)175 RUN_TEST(ExecutableTlsTest)
176 END_TEST_CASE(elf_tls_tests)
177 
178 #ifndef BUILD_COMBINED_TESTS
179 int main(int argc, char** argv) {
180     return unittest_run_all_tests(argc, argv) ? 0 : -1;
181 }
182 #endif
183