• 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/syscall.h>
22 #include <unistd.h>
23 
24 #include <android-base/silent_death_test.h>
25 #include <android-base/test_utils.h>
26 
27 #include "SignalUtils.h"
28 
29 using setjmp_DeathTest = SilentDeathTest;
30 
TEST(setjmp,setjmp_smoke)31 TEST(setjmp, setjmp_smoke) {
32   int value;
33   jmp_buf jb;
34   if ((value = setjmp(jb)) == 0) {
35     longjmp(jb, 123);
36     FAIL(); // Unreachable.
37   } else {
38     ASSERT_EQ(123, value);
39   }
40 }
41 
TEST(setjmp,_setjmp_smoke)42 TEST(setjmp, _setjmp_smoke) {
43   int value;
44   jmp_buf jb;
45   if ((value = _setjmp(jb)) == 0) {
46     _longjmp(jb, 456);
47     FAIL(); // Unreachable.
48   } else {
49     ASSERT_EQ(456, value);
50   }
51 }
52 
TEST(setjmp,sigsetjmp_0_smoke)53 TEST(setjmp, sigsetjmp_0_smoke) {
54   int value;
55   sigjmp_buf jb;
56   if ((value = sigsetjmp(jb, 0)) == 0) {
57     siglongjmp(jb, 789);
58     FAIL(); // Unreachable.
59   } else {
60     ASSERT_EQ(789, value);
61   }
62 }
63 
TEST(setjmp,sigsetjmp_1_smoke)64 TEST(setjmp, sigsetjmp_1_smoke) {
65   int value;
66   sigjmp_buf jb;
67   if ((value = sigsetjmp(jb, 0)) == 0) {
68     siglongjmp(jb, 0xabc);
69     FAIL(); // Unreachable.
70   } else {
71     ASSERT_EQ(0xabc, value);
72   }
73 }
74 
75 // Two distinct signal sets.
76 struct SigSets {
SigSetsSigSets77   SigSets() : one(MakeSigSet(0)), two(MakeSigSet(1)) {
78   }
79 
MakeSigSetSigSets80   static sigset64_t MakeSigSet(int offset) {
81     sigset64_t ss;
82     sigemptyset64(&ss);
83     sigaddset64(&ss, SIGUSR1 + offset);
84 #if defined(__BIONIC__)
85     // TIMER_SIGNAL.
86     sigaddset64(&ss, __SIGRTMIN);
87 #endif
88     sigaddset64(&ss, SIGRTMIN + offset);
89     return ss;
90   }
91 
92   sigset64_t one;
93   sigset64_t two;
94 };
95 
AssertSigmaskEquals(const sigset64_t & expected)96 void AssertSigmaskEquals(const sigset64_t& expected) {
97   sigset64_t actual;
98   sigprocmask64(SIG_SETMASK, nullptr, &actual);
99   size_t end = sizeof(expected) * 8;
100   for (size_t i = 1; i <= end; ++i) {
101     EXPECT_EQ(sigismember64(&expected, i), sigismember64(&actual, i)) << i;
102   }
103 }
104 
TEST(setjmp,_setjmp_signal_mask)105 TEST(setjmp, _setjmp_signal_mask) {
106   SignalMaskRestorer smr;
107 
108   // _setjmp/_longjmp do not save/restore the signal mask.
109   SigSets ss;
110   sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
111   jmp_buf jb;
112   if (_setjmp(jb) == 0) {
113     sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
114     _longjmp(jb, 1);
115     FAIL(); // Unreachable.
116   } else {
117     AssertSigmaskEquals(ss.two);
118   }
119 }
120 
TEST(setjmp,setjmp_signal_mask)121 TEST(setjmp, setjmp_signal_mask) {
122   SignalMaskRestorer smr;
123 
124   // setjmp/longjmp do save/restore the signal mask on bionic, but not on glibc.
125   // This is a BSD versus System V historical accident. POSIX leaves the
126   // behavior unspecified, so any code that cares needs to use sigsetjmp.
127   SigSets ss;
128   sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
129   jmp_buf jb;
130   if (setjmp(jb) == 0) {
131     sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
132     longjmp(jb, 1);
133     FAIL(); // Unreachable.
134   } else {
135 #if defined(__BIONIC__)
136     // bionic behaves like BSD and does save/restore the signal mask.
137     AssertSigmaskEquals(ss.one);
138 #else
139     // glibc behaves like System V and doesn't save/restore the signal mask.
140     AssertSigmaskEquals(ss.two);
141 #endif
142   }
143 }
144 
TEST(setjmp,sigsetjmp_0_signal_mask)145 TEST(setjmp, sigsetjmp_0_signal_mask) {
146   SignalMaskRestorer smr;
147 
148   // sigsetjmp(0)/siglongjmp do not save/restore the signal mask.
149   SigSets ss;
150   sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
151   sigjmp_buf sjb;
152   if (sigsetjmp(sjb, 0) == 0) {
153     sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
154     siglongjmp(sjb, 1);
155     FAIL(); // Unreachable.
156   } else {
157     AssertSigmaskEquals(ss.two);
158   }
159 }
160 
TEST(setjmp,sigsetjmp_1_signal_mask)161 TEST(setjmp, sigsetjmp_1_signal_mask) {
162   SignalMaskRestorer smr;
163 
164   // sigsetjmp(1)/siglongjmp does save/restore the signal mask.
165   SigSets ss;
166   sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
167   sigjmp_buf sjb;
168   if (sigsetjmp(sjb, 1) == 0) {
169     sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
170     siglongjmp(sjb, 1);
171     FAIL(); // Unreachable.
172   } else {
173     AssertSigmaskEquals(ss.one);
174   }
175 }
176 
177 #if defined(__aarch64__)
178 #define SET_FREG(n, v) asm volatile("fmov d"#n ", "#v : : : "d"#n)
179 #define CLEAR_FREG(n) asm volatile("fmov d"#n ", xzr" : : : "d"#n)
180 #define SET_FREGS \
181   SET_FREG(8, 8.0); SET_FREG(9, 9.0); SET_FREG(10, 10.0); SET_FREG(11, 11.0); \
182   SET_FREG(12, 12.0); SET_FREG(13, 13.0); SET_FREG(14, 14.0); SET_FREG(15, 15.0);
183 #define CLEAR_FREGS \
184   CLEAR_FREG(8); CLEAR_FREG(9); CLEAR_FREG(10); CLEAR_FREG(11); \
185   CLEAR_FREG(12); CLEAR_FREG(13); CLEAR_FREG(14); CLEAR_FREG(15);
186 #define GET_FREG(n) ({ double _r; asm volatile("fmov %0, d"#n : "=r"(_r) : :); _r; })
187 #define CHECK_FREGS \
188     EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \
189     EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11)); \
190     EXPECT_EQ(12.0, GET_FREG(12)); EXPECT_EQ(13.0, GET_FREG(13)); \
191     EXPECT_EQ(14.0, GET_FREG(14)); EXPECT_EQ(15.0, GET_FREG(15));
192 #elif defined(__arm__)
193 #define SET_FREG(n, v) \
194   ({ const double _v{v}; asm volatile("fcpyd d"#n ", %P0" : : "w"(_v) : "d"#n); })
195 #define SET_FREGS \
196   SET_FREG(8, 8); SET_FREG(9, 9); SET_FREG(10, 10); SET_FREG(11, 11); \
197   SET_FREG(12, 12); SET_FREG(13, 13); SET_FREG(14, 14); SET_FREG(15, 15);
198 #define CLEAR_FREGS \
199   SET_FREG(8, 0); SET_FREG(9, 0); SET_FREG(10, 0); SET_FREG(11, 0); \
200   SET_FREG(12, 0); SET_FREG(13, 0); SET_FREG(14, 0); SET_FREG(15, 0);
201 #define GET_FREG(n) ({ double _r; asm volatile("fcpyd %P0, d"#n : "=w"(_r) : :); _r;})
202 #define CHECK_FREGS \
203     EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \
204     EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11)); \
205     EXPECT_EQ(12.0, GET_FREG(12)); EXPECT_EQ(13.0, GET_FREG(13)); \
206     EXPECT_EQ(14.0, GET_FREG(14)); EXPECT_EQ(15.0, GET_FREG(15));
207 #else
208 /* The other architectures don't save/restore fp registers. */
209 #define SET_FREGS
210 #define CLEAR_FREGS
211 #define CHECK_FREGS
212 #endif
213 
TEST(setjmp,setjmp_fp_registers)214 TEST(setjmp, setjmp_fp_registers) {
215   int value;
216   jmp_buf jb;
217   SET_FREGS;
218   if ((value = setjmp(jb)) == 0) {
219     CLEAR_FREGS;
220     longjmp(jb, 123);
221     FAIL(); // Unreachable.
222   } else {
223     ASSERT_EQ(123, value);
224     CHECK_FREGS;
225   }
226 }
227 
228 #if defined(__arm__)
229 #define JB_SIGFLAG_OFFSET 0
230 #elif defined(__aarch64__)
231 #define JB_SIGFLAG_OFFSET 0
232 #elif defined(__i386__)
233 #define JB_SIGFLAG_OFFSET 8
234 #elif defined(__riscv)
235 #define JB_SIGFLAG_OFFSET 0
236 #elif defined(__x86_64)
237 #define JB_SIGFLAG_OFFSET 8
238 #endif
239 
TEST_F(setjmp_DeathTest,setjmp_cookie)240 TEST_F(setjmp_DeathTest, setjmp_cookie) {
241   jmp_buf jb;
242   int value = setjmp(jb);
243   ASSERT_EQ(0, value);
244 
245   long* sigflag = reinterpret_cast<long*>(jb) + JB_SIGFLAG_OFFSET;
246 
247   // Make sure there's actually a cookie.
248   EXPECT_NE(0, *sigflag & ~1);
249 
250   // Wipe it out
251   *sigflag &= 1;
252   EXPECT_DEATH(longjmp(jb, 0), "");
253 }
254 
TEST_F(setjmp_DeathTest,setjmp_cookie_checksum)255 TEST_F(setjmp_DeathTest, setjmp_cookie_checksum) {
256   jmp_buf jb;
257   int value = setjmp(jb);
258 
259   if (value == 0) {
260     // Flip a bit.
261     reinterpret_cast<long*>(jb)[1] ^= 1;
262 
263     EXPECT_DEATH(longjmp(jb, 1), "checksum mismatch");
264   } else {
265     fprintf(stderr, "setjmp_cookie_checksum: longjmp succeeded?");
266   }
267 }
268 
call_longjmp(jmp_buf buf)269 __attribute__((noinline)) void call_longjmp(jmp_buf buf) {
270   longjmp(buf, 123);
271 }
272 
TEST(setjmp,setjmp_stack)273 TEST(setjmp, setjmp_stack) {
274   jmp_buf buf;
275   int value = setjmp(buf);
276   if (value == 0) call_longjmp(buf);
277   EXPECT_EQ(123, value);
278 }
279 
TEST(setjmp,bug_152210274)280 TEST(setjmp, bug_152210274) {
281   // Ensure that we never have a mangled value in the stack pointer.
282 #if defined(__BIONIC__)
283   struct sigaction sa = {.sa_flags = SA_SIGINFO, .sa_sigaction = [](int, siginfo_t*, void*) {}};
284   ASSERT_EQ(0, sigaction(SIGPROF, &sa, 0));
285 
286   constexpr size_t kNumThreads = 20;
287 
288   // Start a bunch of threads calling setjmp/longjmp.
289   auto jumper = [](void* arg) -> void* {
290     sigset_t set;
291     sigemptyset(&set);
292     sigaddset(&set, SIGPROF);
293     pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
294 
295     jmp_buf buf;
296     for (size_t count = 0; count < 100000; ++count) {
297       if (setjmp(buf) != 0) {
298         perror("setjmp");
299         abort();
300       }
301       // This will never be true, but the compiler doesn't know that, so the
302       // setjmp won't be removed by DCE. With HWASan/MTE this also acts as a
303       // kind of enforcement that the threads are done before leaving the test.
304       if (*static_cast<size_t*>(arg) != 123) longjmp(buf, 1);
305     }
306     return nullptr;
307   };
308   pthread_t threads[kNumThreads];
309   pid_t tids[kNumThreads] = {};
310   size_t var = 123;
311   for (size_t i = 0; i < kNumThreads; ++i) {
312     ASSERT_EQ(0, pthread_create(&threads[i], nullptr, jumper, &var));
313     tids[i] = pthread_gettid_np(threads[i]);
314   }
315 
316   // Start the interrupter thread.
317   auto interrupter = [](void* arg) -> void* {
318     pid_t* tids = static_cast<pid_t*>(arg);
319     for (size_t count = 0; count < 1000; ++count) {
320       for (size_t i = 0; i < kNumThreads; i++) {
321         if (tgkill(getpid(), tids[i], SIGPROF) == -1 && errno != ESRCH) {
322           perror("tgkill failed");
323           abort();
324         }
325       }
326       usleep(100);
327     }
328     return nullptr;
329   };
330   pthread_t t;
331   ASSERT_EQ(0, pthread_create(&t, nullptr, interrupter, tids));
332   pthread_join(t, nullptr);
333   for (size_t i = 0; i < kNumThreads; i++) {
334     pthread_join(threads[i], nullptr);
335   }
336 #else
337   GTEST_SKIP() << "tests uses functions not in glibc";
338 #endif
339 }
340