• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 
19 #include <setjmp.h>
20 #include <stdlib.h>
21 #include <sys/auxv.h>
22 #include <sys/syscall.h>
23 #include <unistd.h>
24 
25 #include <android-base/silent_death_test.h>
26 #include <android-base/test_utils.h>
27 
28 #include "SignalUtils.h"
29 
30 using setjmp_DeathTest = SilentDeathTest;
31 
TEST(setjmp,setjmp_smoke)32 TEST(setjmp, setjmp_smoke) {
33   int value;
34   jmp_buf jb;
35   if ((value = setjmp(jb)) == 0) {
36     longjmp(jb, 123);
37     FAIL(); // Unreachable.
38   } else {
39     ASSERT_EQ(123, value);
40   }
41 }
42 
TEST(setjmp,_setjmp_smoke)43 TEST(setjmp, _setjmp_smoke) {
44   int value;
45   jmp_buf jb;
46   if ((value = _setjmp(jb)) == 0) {
47     _longjmp(jb, 456);
48     FAIL(); // Unreachable.
49   } else {
50     ASSERT_EQ(456, value);
51   }
52 }
53 
TEST(setjmp,sigsetjmp_0_smoke)54 TEST(setjmp, sigsetjmp_0_smoke) {
55   int value;
56   sigjmp_buf jb;
57   if ((value = sigsetjmp(jb, 0)) == 0) {
58     siglongjmp(jb, 789);
59     FAIL(); // Unreachable.
60   } else {
61     ASSERT_EQ(789, value);
62   }
63 }
64 
TEST(setjmp,sigsetjmp_1_smoke)65 TEST(setjmp, sigsetjmp_1_smoke) {
66   int value;
67   sigjmp_buf jb;
68   if ((value = sigsetjmp(jb, 0)) == 0) {
69     siglongjmp(jb, 0xabc);
70     FAIL(); // Unreachable.
71   } else {
72     ASSERT_EQ(0xabc, value);
73   }
74 }
75 
76 // Two distinct signal sets.
77 struct SigSets {
SigSetsSigSets78   SigSets() : one(MakeSigSet(0)), two(MakeSigSet(1)) {
79   }
80 
MakeSigSetSigSets81   static sigset64_t MakeSigSet(int offset) {
82     sigset64_t ss;
83     sigemptyset64(&ss);
84     sigaddset64(&ss, SIGUSR1 + offset);
85 #if defined(__BIONIC__)
86     // TIMER_SIGNAL.
87     sigaddset64(&ss, __SIGRTMIN);
88 #endif
89     sigaddset64(&ss, SIGRTMIN + offset);
90     return ss;
91   }
92 
93   sigset64_t one;
94   sigset64_t two;
95 };
96 
AssertSigmaskEquals(const sigset64_t & expected)97 void AssertSigmaskEquals(const sigset64_t& expected) {
98   sigset64_t actual;
99   sigprocmask64(SIG_SETMASK, nullptr, &actual);
100   size_t end = sizeof(expected) * 8;
101   for (size_t i = 1; i <= end; ++i) {
102     EXPECT_EQ(sigismember64(&expected, i), sigismember64(&actual, i)) << i;
103   }
104 }
105 
TEST(setjmp,_setjmp_signal_mask)106 TEST(setjmp, _setjmp_signal_mask) {
107   SignalMaskRestorer smr;
108 
109   // _setjmp/_longjmp do not save/restore the signal mask.
110   SigSets ss;
111   sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
112   jmp_buf jb;
113   if (_setjmp(jb) == 0) {
114     sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
115     _longjmp(jb, 1);
116     FAIL(); // Unreachable.
117   } else {
118     AssertSigmaskEquals(ss.two);
119   }
120 }
121 
TEST(setjmp,setjmp_signal_mask)122 TEST(setjmp, setjmp_signal_mask) {
123   SignalMaskRestorer smr;
124 
125   // setjmp/longjmp do save/restore the signal mask on bionic, but not on glibc.
126   // This is a BSD versus System V historical accident. POSIX leaves the
127   // behavior unspecified, so any code that cares needs to use sigsetjmp.
128   SigSets ss;
129   sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
130   jmp_buf jb;
131   if (setjmp(jb) == 0) {
132     sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
133     longjmp(jb, 1);
134     FAIL(); // Unreachable.
135   } else {
136 #if defined(__BIONIC__)
137     // bionic behaves like BSD and does save/restore the signal mask.
138     AssertSigmaskEquals(ss.one);
139 #else
140     // glibc behaves like System V and doesn't save/restore the signal mask.
141     AssertSigmaskEquals(ss.two);
142 #endif
143   }
144 }
145 
TEST(setjmp,sigsetjmp_0_signal_mask)146 TEST(setjmp, sigsetjmp_0_signal_mask) {
147   SignalMaskRestorer smr;
148 
149   // sigsetjmp(0)/siglongjmp do not save/restore the signal mask.
150   SigSets ss;
151   sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
152   sigjmp_buf sjb;
153   if (sigsetjmp(sjb, 0) == 0) {
154     sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
155     siglongjmp(sjb, 1);
156     FAIL(); // Unreachable.
157   } else {
158     AssertSigmaskEquals(ss.two);
159   }
160 }
161 
TEST(setjmp,sigsetjmp_1_signal_mask)162 TEST(setjmp, sigsetjmp_1_signal_mask) {
163   SignalMaskRestorer smr;
164 
165   // sigsetjmp(1)/siglongjmp does save/restore the signal mask.
166   SigSets ss;
167   sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
168   sigjmp_buf sjb;
169   if (sigsetjmp(sjb, 1) == 0) {
170     sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
171     siglongjmp(sjb, 1);
172     FAIL(); // Unreachable.
173   } else {
174     AssertSigmaskEquals(ss.one);
175   }
176 }
177 
178 #if defined(__arm__) || defined(__aarch64__)
179 // arm and arm64 have the same callee save fp registers (8-15),
180 // but use different instructions for accessing them.
181 #if defined(__arm__)
182 #define SET_FREG(n, v) asm volatile("vmov.f64 d"#n ", #"#v : : : "d"#n)
183 #define GET_FREG(n) ({ double _r; asm volatile("fcpyd %P0, d"#n : "=w"(_r) : :); _r;})
184 #define CLEAR_FREG(n) asm volatile("vmov.i64 d"#n ", #0x0" : : : "d"#n)
185 #elif defined(__aarch64__)
186 #define SET_FREG(n, v) asm volatile("fmov d"#n ", "#v : : : "d"#n)
187 #define GET_FREG(n) ({ double _r; asm volatile("fmov %0, d"#n : "=r"(_r) : :); _r; })
188 #define CLEAR_FREG(n) asm volatile("fmov d"#n ", xzr" : : : "d"#n)
189 #endif
190 #define SET_FREGS \
191   SET_FREG(8, 8.0); SET_FREG(9, 9.0); SET_FREG(10, 10.0); SET_FREG(11, 11.0); \
192   SET_FREG(12, 12.0); SET_FREG(13, 13.0); SET_FREG(14, 14.0); SET_FREG(15, 15.0)
193 #define CLEAR_FREGS \
194   CLEAR_FREG(8); CLEAR_FREG(9); CLEAR_FREG(10); CLEAR_FREG(11); \
195   CLEAR_FREG(12); CLEAR_FREG(13); CLEAR_FREG(14); CLEAR_FREG(15)
196 #define CHECK_FREGS \
197   EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \
198   EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11)); \
199   EXPECT_EQ(12.0, GET_FREG(12)); EXPECT_EQ(13.0, GET_FREG(13)); \
200   EXPECT_EQ(14.0, GET_FREG(14)); EXPECT_EQ(15.0, GET_FREG(15))
201 
202 #elif defined(__riscv)
203 // riscv64 has callee save registers fs0-fs11.
204 // TODO: use Zfa to get 1.0 rather than the one_p trick.
205 #define SET_FREGS \
206   double one = 1, *one_p = &one; \
207   asm volatile("fmv.d.x fs0, zero ; fld fs1, (%0) ; \
208                 fadd.d fs2, fs1, fs1 ; fadd.d fs3, fs2, fs1 ; \
209                 fadd.d fs4, fs3, fs1 ; fadd.d fs5, fs4, fs1 ; \
210                 fadd.d fs6, fs5, fs1 ; fadd.d fs7, fs6, fs1 ; \
211                 fadd.d fs8, fs7, fs1 ; fadd.d fs9, fs8, fs1 ; \
212                 fadd.d fs10, fs9, fs1 ; fadd.d fs11, fs10, fs1" \
213                : \
214                : "r"(one_p) \
215                : "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", \
216                   "fs6", "fs7", "fs8", "fs9", "fs10", "fs11")
217 #define CLEAR_FREGS \
218   asm volatile("fmv.d.x fs0, zero ; fmv.d.x fs1, zero ; \
219                 fmv.d.x fs2, zero ; fmv.d.x fs3, zero ; \
220                 fmv.d.x fs4, zero ; fmv.d.x fs5, zero ; \
221                 fmv.d.x fs6, zero ; fmv.d.x fs7, zero ; \
222                 fmv.d.x fs8, zero ; fmv.d.x fs9, zero ; \
223                 fmv.d.x fs10, zero ; fmv.d.x fs11, zero" \
224                : : : "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", \
225                      "fs6", "fs7", "fs8", "fs9", "fs10", "fs11")
226 #define GET_FREG(n) ({ double _r; asm volatile("fmv.d %0, fs"#n : "=f"(_r) : :); _r; })
227 #define CHECK_FREGS \
228   EXPECT_EQ(0.0, GET_FREG(0)); EXPECT_EQ(1.0, GET_FREG(1)); \
229   EXPECT_EQ(2.0, GET_FREG(2)); EXPECT_EQ(3.0, GET_FREG(3)); \
230   EXPECT_EQ(4.0, GET_FREG(4)); EXPECT_EQ(5.0, GET_FREG(5)); \
231   EXPECT_EQ(6.0, GET_FREG(6)); EXPECT_EQ(7.0, GET_FREG(7)); \
232   EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \
233   EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11))
234 
235 #else
236 // x86 and x86-64 don't save/restore fp registers.
237 #define SET_FREGS
238 #define CLEAR_FREGS
239 #define CHECK_FREGS
240 #endif
241 
TEST(setjmp,setjmp_fp_registers)242 TEST(setjmp, setjmp_fp_registers) {
243   int value;
244   jmp_buf jb;
245   SET_FREGS;
246   if ((value = setjmp(jb)) == 0) {
247     CLEAR_FREGS;
248     longjmp(jb, 123);
249     FAIL(); // Unreachable.
250   } else {
251     ASSERT_EQ(123, value);
252     CHECK_FREGS;
253   }
254 }
255 
256 #if defined(__arm__)
257 #define JB_SIGFLAG_OFFSET 0
258 #elif defined(__aarch64__)
259 #define JB_SIGFLAG_OFFSET 0
260 #elif defined(__i386__)
261 #define JB_SIGFLAG_OFFSET 8
262 #elif defined(__riscv)
263 #define JB_SIGFLAG_OFFSET 0
264 #elif defined(__x86_64)
265 #define JB_SIGFLAG_OFFSET 8
266 #endif
267 
TEST_F(setjmp_DeathTest,setjmp_cookie)268 TEST_F(setjmp_DeathTest, setjmp_cookie) {
269   jmp_buf jb;
270   int value = setjmp(jb);
271   ASSERT_EQ(0, value);
272 
273   long* sigflag = reinterpret_cast<long*>(jb) + JB_SIGFLAG_OFFSET;
274 
275   // Make sure there's actually a cookie.
276   EXPECT_NE(0, *sigflag & ~1);
277 
278   // Wipe it out
279   *sigflag &= 1;
280   EXPECT_DEATH(longjmp(jb, 0), "");
281 }
282 
TEST_F(setjmp_DeathTest,setjmp_cookie_checksum)283 TEST_F(setjmp_DeathTest, setjmp_cookie_checksum) {
284   jmp_buf jb;
285   int value = setjmp(jb);
286 
287   if (value == 0) {
288     // Flip a bit.
289     reinterpret_cast<long*>(jb)[1] ^= 1;
290 
291     EXPECT_DEATH(longjmp(jb, 1), "checksum mismatch");
292   } else {
293     fprintf(stderr, "setjmp_cookie_checksum: longjmp succeeded?");
294   }
295 }
296 
call_longjmp(jmp_buf buf)297 __attribute__((noinline)) void call_longjmp(jmp_buf buf) {
298   longjmp(buf, 123);
299 }
300 
TEST(setjmp,setjmp_stack)301 TEST(setjmp, setjmp_stack) {
302   jmp_buf buf;
303   int value = setjmp(buf);
304   if (value == 0) call_longjmp(buf);
305   EXPECT_EQ(123, value);
306 }
307 
TEST(setjmp,bug_152210274)308 TEST(setjmp, bug_152210274) {
309   // Ensure that we never have a mangled value in the stack pointer.
310 #if defined(__BIONIC__)
311   struct sigaction sa = {.sa_flags = SA_SIGINFO, .sa_sigaction = [](int, siginfo_t*, void*) {}};
312   ASSERT_EQ(0, sigaction(SIGPROF, &sa, 0));
313 
314   constexpr size_t kNumThreads = 20;
315 
316   // Start a bunch of threads calling setjmp/longjmp.
317   auto jumper = [](void* arg) -> void* {
318     sigset_t set;
319     sigemptyset(&set);
320     sigaddset(&set, SIGPROF);
321     pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
322 
323     jmp_buf buf;
324     for (size_t count = 0; count < 100000; ++count) {
325       if (setjmp(buf) != 0) {
326         perror("setjmp");
327         abort();
328       }
329       // This will never be true, but the compiler doesn't know that, so the
330       // setjmp won't be removed by DCE. With HWASan/MTE this also acts as a
331       // kind of enforcement that the threads are done before leaving the test.
332       if (*static_cast<size_t*>(arg) != 123) longjmp(buf, 1);
333     }
334     return nullptr;
335   };
336   pthread_t threads[kNumThreads];
337   pid_t tids[kNumThreads] = {};
338   size_t var = 123;
339   for (size_t i = 0; i < kNumThreads; ++i) {
340     ASSERT_EQ(0, pthread_create(&threads[i], nullptr, jumper, &var));
341     tids[i] = pthread_gettid_np(threads[i]);
342   }
343 
344   // Start the interrupter thread.
345   auto interrupter = [](void* arg) -> void* {
346     pid_t* tids = static_cast<pid_t*>(arg);
347     for (size_t count = 0; count < 1000; ++count) {
348       for (size_t i = 0; i < kNumThreads; i++) {
349         if (tgkill(getpid(), tids[i], SIGPROF) == -1 && errno != ESRCH) {
350           perror("tgkill failed");
351           abort();
352         }
353       }
354       usleep(100);
355     }
356     return nullptr;
357   };
358   pthread_t t;
359   ASSERT_EQ(0, pthread_create(&t, nullptr, interrupter, tids));
360   pthread_join(t, nullptr);
361   for (size_t i = 0; i < kNumThreads; i++) {
362     pthread_join(threads[i], nullptr);
363   }
364 #else
365   GTEST_SKIP() << "tests uses functions not in glibc";
366 #endif
367 }
368 
369 #if defined(__aarch64__)
TEST(setjmp,sigsetjmp_sme)370 TEST(setjmp, sigsetjmp_sme) {
371   if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
372     GTEST_SKIP() << "SME is not enabled on device.";
373   }
374 
375   uint64_t svcr, za_state;
376   sigjmp_buf jb;
377   __asm__ __volatile__(".arch_extension sme; smstart za");
378   sigsetjmp(jb, 0);
379   __asm__ __volatile__(".arch_extension sme; mrs %0, SVCR" : "=r"(svcr));
380   __asm__ __volatile__(".arch_extension sme; smstop za");  // Turn ZA off anyway.
381   za_state = svcr & 0x2UL;
382   ASSERT_EQ(0UL, za_state);
383 }
384 
TEST(setjmp,siglongjmp_sme)385 TEST(setjmp, siglongjmp_sme) {
386   if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
387     GTEST_SKIP() << "SME is not enabled on device.";
388   }
389 
390   uint64_t svcr, za_state;
391   int value;
392   sigjmp_buf jb;
393   if ((value = sigsetjmp(jb, 0)) == 0) {
394     __asm__ __volatile__(".arch_extension sme; smstart za");
395     siglongjmp(jb, 789);
396     __asm__ __volatile__(".arch_extension sme; smstop za");
397     FAIL();  // Unreachable.
398   } else {
399     __asm__ __volatile__(".arch_extension sme; mrs %0, SVCR" : "=r"(svcr));
400     __asm__ __volatile__(".arch_extension sme; smstop za");  // Turn ZA off anyway.
401     za_state = svcr & 0x2UL;
402     ASSERT_EQ(789, value);
403     ASSERT_EQ(0UL, za_state);
404   }
405 }
406 #endif
407