blob: 454390ebde8e2083178c478503152757faf677d9 [file] [log] [blame]
Yongqin Liu9fea4092014-10-31 16:37:09 +08001/*
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>
Tamas Zsoldos6f106f72025-04-28 10:07:30 -070021#include <sys/auxv.h>
Elliott Hughesc0d41db2021-04-02 18:02:38 -070022#include <sys/syscall.h>
23#include <unistd.h>
Yongqin Liu9fea4092014-10-31 16:37:09 +080024
Elliott Hughes141b9172021-04-09 17:13:09 -070025#include <android-base/silent_death_test.h>
Florian Mayer4817ca62022-04-15 22:53:51 +000026#include <android-base/test_utils.h>
Elliott Hughes141b9172021-04-09 17:13:09 -070027
Elliott Hughes71ba5892018-02-07 12:44:45 -080028#include "SignalUtils.h"
Tamas Petz99032782025-05-14 14:03:43 +020029#include "sme_utils.h"
Elliott Hughes460130b2018-01-31 09:05:26 -080030
Elliott Hughes141b9172021-04-09 17:13:09 -070031using setjmp_DeathTest = SilentDeathTest;
Elliott Hughese657eb42021-02-18 17:11:56 -080032
Yongqin Liu9fea4092014-10-31 16:37:09 +080033TEST(setjmp, setjmp_smoke) {
34 int value;
35 jmp_buf jb;
36 if ((value = setjmp(jb)) == 0) {
37 longjmp(jb, 123);
38 FAIL(); // Unreachable.
39 } else {
40 ASSERT_EQ(123, value);
41 }
42}
43
44TEST(setjmp, _setjmp_smoke) {
45 int value;
46 jmp_buf jb;
47 if ((value = _setjmp(jb)) == 0) {
48 _longjmp(jb, 456);
49 FAIL(); // Unreachable.
50 } else {
51 ASSERT_EQ(456, value);
52 }
53}
54
55TEST(setjmp, sigsetjmp_0_smoke) {
56 int value;
57 sigjmp_buf jb;
58 if ((value = sigsetjmp(jb, 0)) == 0) {
59 siglongjmp(jb, 789);
60 FAIL(); // Unreachable.
61 } else {
62 ASSERT_EQ(789, value);
63 }
64}
65
66TEST(setjmp, sigsetjmp_1_smoke) {
67 int value;
68 sigjmp_buf jb;
69 if ((value = sigsetjmp(jb, 0)) == 0) {
70 siglongjmp(jb, 0xabc);
71 FAIL(); // Unreachable.
72 } else {
73 ASSERT_EQ(0xabc, value);
74 }
75}
76
Elliott Hughes460130b2018-01-31 09:05:26 -080077// Two distinct signal sets.
Elliott Hughes1510a1c2014-12-10 09:31:04 -080078struct SigSets {
79 SigSets() : one(MakeSigSet(0)), two(MakeSigSet(1)) {
Elliott Hughes1c0c0ed2014-12-05 22:24:49 -080080 }
Elliott Hughes1510a1c2014-12-10 09:31:04 -080081
Elliott Hughes460130b2018-01-31 09:05:26 -080082 static sigset64_t MakeSigSet(int offset) {
83 sigset64_t ss;
84 sigemptyset64(&ss);
85 sigaddset64(&ss, SIGUSR1 + offset);
Colin Cross23b986c2022-10-19 15:03:59 -070086#if defined(__BIONIC__)
Josh Gaobaf20fc2018-10-08 17:28:07 -070087 // TIMER_SIGNAL.
88 sigaddset64(&ss, __SIGRTMIN);
Colin Cross23b986c2022-10-19 15:03:59 -070089#endif
Elliott Hughes460130b2018-01-31 09:05:26 -080090 sigaddset64(&ss, SIGRTMIN + offset);
Elliott Hughes1510a1c2014-12-10 09:31:04 -080091 return ss;
92 }
93
Elliott Hughes460130b2018-01-31 09:05:26 -080094 sigset64_t one;
95 sigset64_t two;
Elliott Hughes1510a1c2014-12-10 09:31:04 -080096};
Yongqin Liu9fea4092014-10-31 16:37:09 +080097
Elliott Hughes460130b2018-01-31 09:05:26 -080098void AssertSigmaskEquals(const sigset64_t& expected) {
99 sigset64_t actual;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700100 sigprocmask64(SIG_SETMASK, nullptr, &actual);
Elliott Hughes460130b2018-01-31 09:05:26 -0800101 size_t end = sizeof(expected) * 8;
Elliott Hughes1c0c0ed2014-12-05 22:24:49 -0800102 for (size_t i = 1; i <= end; ++i) {
Elliott Hughes460130b2018-01-31 09:05:26 -0800103 EXPECT_EQ(sigismember64(&expected, i), sigismember64(&actual, i)) << i;
Elliott Hughes1c0c0ed2014-12-05 22:24:49 -0800104 }
105}
106
Yongqin Liu9fea4092014-10-31 16:37:09 +0800107TEST(setjmp, _setjmp_signal_mask) {
Elliott Hughes460130b2018-01-31 09:05:26 -0800108 SignalMaskRestorer smr;
109
Yongqin Liu9fea4092014-10-31 16:37:09 +0800110 // _setjmp/_longjmp do not save/restore the signal mask.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800111 SigSets ss;
Elliott Hughes460130b2018-01-31 09:05:26 -0800112 sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800113 jmp_buf jb;
114 if (_setjmp(jb) == 0) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700115 sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800116 _longjmp(jb, 1);
117 FAIL(); // Unreachable.
118 } else {
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800119 AssertSigmaskEquals(ss.two);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800120 }
Yongqin Liu9fea4092014-10-31 16:37:09 +0800121}
122
123TEST(setjmp, setjmp_signal_mask) {
Elliott Hughes460130b2018-01-31 09:05:26 -0800124 SignalMaskRestorer smr;
125
Yongqin Liu9fea4092014-10-31 16:37:09 +0800126 // setjmp/longjmp do save/restore the signal mask on bionic, but not on glibc.
127 // This is a BSD versus System V historical accident. POSIX leaves the
128 // behavior unspecified, so any code that cares needs to use sigsetjmp.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800129 SigSets ss;
Elliott Hughes460130b2018-01-31 09:05:26 -0800130 sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800131 jmp_buf jb;
132 if (setjmp(jb) == 0) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700133 sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800134 longjmp(jb, 1);
135 FAIL(); // Unreachable.
136 } else {
Yongqin Liu9fea4092014-10-31 16:37:09 +0800137#if defined(__BIONIC__)
138 // bionic behaves like BSD and does save/restore the signal mask.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800139 AssertSigmaskEquals(ss.one);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800140#else
141 // glibc behaves like System V and doesn't save/restore the signal mask.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800142 AssertSigmaskEquals(ss.two);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800143#endif
144 }
Yongqin Liu9fea4092014-10-31 16:37:09 +0800145}
146
147TEST(setjmp, sigsetjmp_0_signal_mask) {
Elliott Hughes460130b2018-01-31 09:05:26 -0800148 SignalMaskRestorer smr;
149
Yongqin Liu9fea4092014-10-31 16:37:09 +0800150 // sigsetjmp(0)/siglongjmp do not save/restore the signal mask.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800151 SigSets ss;
Elliott Hughes460130b2018-01-31 09:05:26 -0800152 sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800153 sigjmp_buf sjb;
154 if (sigsetjmp(sjb, 0) == 0) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700155 sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800156 siglongjmp(sjb, 1);
157 FAIL(); // Unreachable.
158 } else {
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800159 AssertSigmaskEquals(ss.two);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800160 }
Yongqin Liu9fea4092014-10-31 16:37:09 +0800161}
162
163TEST(setjmp, sigsetjmp_1_signal_mask) {
Elliott Hughes460130b2018-01-31 09:05:26 -0800164 SignalMaskRestorer smr;
165
Yongqin Liu9fea4092014-10-31 16:37:09 +0800166 // sigsetjmp(1)/siglongjmp does save/restore the signal mask.
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800167 SigSets ss;
Elliott Hughes460130b2018-01-31 09:05:26 -0800168 sigprocmask64(SIG_SETMASK, &ss.one, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800169 sigjmp_buf sjb;
170 if (sigsetjmp(sjb, 1) == 0) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700171 sigprocmask64(SIG_SETMASK, &ss.two, nullptr);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800172 siglongjmp(sjb, 1);
173 FAIL(); // Unreachable.
174 } else {
Elliott Hughes1510a1c2014-12-10 09:31:04 -0800175 AssertSigmaskEquals(ss.one);
Yongqin Liu9fea4092014-10-31 16:37:09 +0800176 }
Yongqin Liu9fea4092014-10-31 16:37:09 +0800177}
Elliott Hughes87dd5032015-01-26 20:52:34 -0800178
Elliott Hughes86968d92024-05-21 21:25:50 +0000179#if defined(__arm__) || defined(__aarch64__)
180// arm and arm64 have the same callee save fp registers (8-15),
181// but use different instructions for accessing them.
Yi Kong11f696a2024-05-15 02:30:44 +0900182#if defined(__arm__)
183#define SET_FREG(n, v) asm volatile("vmov.f64 d"#n ", #"#v : : : "d"#n)
184#define GET_FREG(n) ({ double _r; asm volatile("fcpyd %P0, d"#n : "=w"(_r) : :); _r;})
185#define CLEAR_FREG(n) asm volatile("vmov.i64 d"#n ", #0x0" : : : "d"#n)
186#elif defined(__aarch64__)
Elliott Hughes87dd5032015-01-26 20:52:34 -0800187#define SET_FREG(n, v) asm volatile("fmov d"#n ", "#v : : : "d"#n)
Yi Kong11f696a2024-05-15 02:30:44 +0900188#define GET_FREG(n) ({ double _r; asm volatile("fmov %0, d"#n : "=r"(_r) : :); _r; })
Elliott Hughes87dd5032015-01-26 20:52:34 -0800189#define CLEAR_FREG(n) asm volatile("fmov d"#n ", xzr" : : : "d"#n)
Yi Kong11f696a2024-05-15 02:30:44 +0900190#endif
Elliott Hughes87dd5032015-01-26 20:52:34 -0800191#define SET_FREGS \
192 SET_FREG(8, 8.0); SET_FREG(9, 9.0); SET_FREG(10, 10.0); SET_FREG(11, 11.0); \
Elliott Hughes86968d92024-05-21 21:25:50 +0000193 SET_FREG(12, 12.0); SET_FREG(13, 13.0); SET_FREG(14, 14.0); SET_FREG(15, 15.0)
Elliott Hughes87dd5032015-01-26 20:52:34 -0800194#define CLEAR_FREGS \
195 CLEAR_FREG(8); CLEAR_FREG(9); CLEAR_FREG(10); CLEAR_FREG(11); \
Elliott Hughes86968d92024-05-21 21:25:50 +0000196 CLEAR_FREG(12); CLEAR_FREG(13); CLEAR_FREG(14); CLEAR_FREG(15)
Elliott Hughes87dd5032015-01-26 20:52:34 -0800197#define CHECK_FREGS \
Elliott Hughes86968d92024-05-21 21:25:50 +0000198 EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \
199 EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11)); \
200 EXPECT_EQ(12.0, GET_FREG(12)); EXPECT_EQ(13.0, GET_FREG(13)); \
201 EXPECT_EQ(14.0, GET_FREG(14)); EXPECT_EQ(15.0, GET_FREG(15))
202
203#elif defined(__riscv)
204// riscv64 has callee save registers fs0-fs11.
205// TODO: use Zfa to get 1.0 rather than the one_p trick.
206#define SET_FREGS \
207 double one = 1, *one_p = &one; \
208 asm volatile("fmv.d.x fs0, zero ; fld fs1, (%0) ; \
209 fadd.d fs2, fs1, fs1 ; fadd.d fs3, fs2, fs1 ; \
210 fadd.d fs4, fs3, fs1 ; fadd.d fs5, fs4, fs1 ; \
211 fadd.d fs6, fs5, fs1 ; fadd.d fs7, fs6, fs1 ; \
212 fadd.d fs8, fs7, fs1 ; fadd.d fs9, fs8, fs1 ; \
213 fadd.d fs10, fs9, fs1 ; fadd.d fs11, fs10, fs1" \
214 : \
215 : "r"(one_p) \
216 : "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", \
217 "fs6", "fs7", "fs8", "fs9", "fs10", "fs11")
218#define CLEAR_FREGS \
219 asm volatile("fmv.d.x fs0, zero ; fmv.d.x fs1, zero ; \
220 fmv.d.x fs2, zero ; fmv.d.x fs3, zero ; \
221 fmv.d.x fs4, zero ; fmv.d.x fs5, zero ; \
222 fmv.d.x fs6, zero ; fmv.d.x fs7, zero ; \
223 fmv.d.x fs8, zero ; fmv.d.x fs9, zero ; \
224 fmv.d.x fs10, zero ; fmv.d.x fs11, zero" \
225 : : : "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", \
226 "fs6", "fs7", "fs8", "fs9", "fs10", "fs11")
227#define GET_FREG(n) ({ double _r; asm volatile("fmv.d %0, fs"#n : "=f"(_r) : :); _r; })
228#define CHECK_FREGS \
229 EXPECT_EQ(0.0, GET_FREG(0)); EXPECT_EQ(1.0, GET_FREG(1)); \
230 EXPECT_EQ(2.0, GET_FREG(2)); EXPECT_EQ(3.0, GET_FREG(3)); \
231 EXPECT_EQ(4.0, GET_FREG(4)); EXPECT_EQ(5.0, GET_FREG(5)); \
232 EXPECT_EQ(6.0, GET_FREG(6)); EXPECT_EQ(7.0, GET_FREG(7)); \
233 EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \
234 EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11))
235
Elliott Hughes87dd5032015-01-26 20:52:34 -0800236#else
Elliott Hughes86968d92024-05-21 21:25:50 +0000237// x86 and x86-64 don't save/restore fp registers.
Elliott Hughes87dd5032015-01-26 20:52:34 -0800238#define SET_FREGS
239#define CLEAR_FREGS
240#define CHECK_FREGS
241#endif
242
243TEST(setjmp, setjmp_fp_registers) {
244 int value;
245 jmp_buf jb;
246 SET_FREGS;
247 if ((value = setjmp(jb)) == 0) {
248 CLEAR_FREGS;
249 longjmp(jb, 123);
250 FAIL(); // Unreachable.
251 } else {
252 ASSERT_EQ(123, value);
253 CHECK_FREGS;
254 }
255}
Josh Gao7fda8d22015-09-10 15:40:24 -0700256
257#if defined(__arm__)
Elliott Hughese1905ed2022-10-17 23:23:36 +0000258#define JB_SIGFLAG_OFFSET 0
Josh Gao7fda8d22015-09-10 15:40:24 -0700259#elif defined(__aarch64__)
Elliott Hughese1905ed2022-10-17 23:23:36 +0000260#define JB_SIGFLAG_OFFSET 0
Josh Gao7fda8d22015-09-10 15:40:24 -0700261#elif defined(__i386__)
Elliott Hughese1905ed2022-10-17 23:23:36 +0000262#define JB_SIGFLAG_OFFSET 8
263#elif defined(__riscv)
264#define JB_SIGFLAG_OFFSET 0
Josh Gao7fda8d22015-09-10 15:40:24 -0700265#elif defined(__x86_64)
Elliott Hughese1905ed2022-10-17 23:23:36 +0000266#define JB_SIGFLAG_OFFSET 8
Josh Gao7fda8d22015-09-10 15:40:24 -0700267#endif
268
Elliott Hughese657eb42021-02-18 17:11:56 -0800269TEST_F(setjmp_DeathTest, setjmp_cookie) {
Josh Gao7fda8d22015-09-10 15:40:24 -0700270 jmp_buf jb;
271 int value = setjmp(jb);
272 ASSERT_EQ(0, value);
273
Elliott Hughese1905ed2022-10-17 23:23:36 +0000274 long* sigflag = reinterpret_cast<long*>(jb) + JB_SIGFLAG_OFFSET;
Josh Gao7fda8d22015-09-10 15:40:24 -0700275
276 // Make sure there's actually a cookie.
277 EXPECT_NE(0, *sigflag & ~1);
278
279 // Wipe it out
280 *sigflag &= 1;
281 EXPECT_DEATH(longjmp(jb, 0), "");
Josh Gao7fda8d22015-09-10 15:40:24 -0700282}
Josh Gaoa4c69132016-03-02 19:03:17 -0800283
Elliott Hughese657eb42021-02-18 17:11:56 -0800284TEST_F(setjmp_DeathTest, setjmp_cookie_checksum) {
Josh Gaoa4c69132016-03-02 19:03:17 -0800285 jmp_buf jb;
286 int value = setjmp(jb);
287
288 if (value == 0) {
289 // Flip a bit.
Predrag Blagojevic32995902016-03-16 15:49:12 +0100290 reinterpret_cast<long*>(jb)[1] ^= 1;
Josh Gaoa4c69132016-03-02 19:03:17 -0800291
292 EXPECT_DEATH(longjmp(jb, 1), "checksum mismatch");
293 } else {
294 fprintf(stderr, "setjmp_cookie_checksum: longjmp succeeded?");
295 }
296}
Peter Collingbourne734beec2018-11-14 12:41:41 -0800297
298__attribute__((noinline)) void call_longjmp(jmp_buf buf) {
299 longjmp(buf, 123);
300}
301
302TEST(setjmp, setjmp_stack) {
303 jmp_buf buf;
304 int value = setjmp(buf);
305 if (value == 0) call_longjmp(buf);
306 EXPECT_EQ(123, value);
307}
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700308
309TEST(setjmp, bug_152210274) {
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700310 // Ensure that we never have a mangled value in the stack pointer.
311#if defined(__BIONIC__)
312 struct sigaction sa = {.sa_flags = SA_SIGINFO, .sa_sigaction = [](int, siginfo_t*, void*) {}};
313 ASSERT_EQ(0, sigaction(SIGPROF, &sa, 0));
314
315 constexpr size_t kNumThreads = 20;
316
317 // Start a bunch of threads calling setjmp/longjmp.
318 auto jumper = [](void* arg) -> void* {
319 sigset_t set;
320 sigemptyset(&set);
321 sigaddset(&set, SIGPROF);
322 pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
323
324 jmp_buf buf;
325 for (size_t count = 0; count < 100000; ++count) {
326 if (setjmp(buf) != 0) {
327 perror("setjmp");
328 abort();
329 }
Peter Collingbourne25a7c3f2023-03-21 22:20:22 -0700330 // This will never be true, but the compiler doesn't know that, so the
331 // setjmp won't be removed by DCE. With HWASan/MTE this also acts as a
332 // kind of enforcement that the threads are done before leaving the test.
333 if (*static_cast<size_t*>(arg) != 123) longjmp(buf, 1);
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700334 }
335 return nullptr;
336 };
Peter Collingbourne25a7c3f2023-03-21 22:20:22 -0700337 pthread_t threads[kNumThreads];
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700338 pid_t tids[kNumThreads] = {};
Peter Collingbourne25a7c3f2023-03-21 22:20:22 -0700339 size_t var = 123;
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700340 for (size_t i = 0; i < kNumThreads; ++i) {
Peter Collingbourne25a7c3f2023-03-21 22:20:22 -0700341 ASSERT_EQ(0, pthread_create(&threads[i], nullptr, jumper, &var));
342 tids[i] = pthread_gettid_np(threads[i]);
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700343 }
344
345 // Start the interrupter thread.
346 auto interrupter = [](void* arg) -> void* {
347 pid_t* tids = static_cast<pid_t*>(arg);
348 for (size_t count = 0; count < 1000; ++count) {
349 for (size_t i = 0; i < kNumThreads; i++) {
350 if (tgkill(getpid(), tids[i], SIGPROF) == -1 && errno != ESRCH) {
351 perror("tgkill failed");
352 abort();
353 }
354 }
355 usleep(100);
356 }
357 return nullptr;
358 };
359 pthread_t t;
360 ASSERT_EQ(0, pthread_create(&t, nullptr, interrupter, tids));
361 pthread_join(t, nullptr);
Peter Collingbourne25a7c3f2023-03-21 22:20:22 -0700362 for (size_t i = 0; i < kNumThreads; i++) {
363 pthread_join(threads[i], nullptr);
364 }
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700365#else
Elliott Hughes14ab3532021-04-08 20:59:50 -0700366 GTEST_SKIP() << "tests uses functions not in glibc";
Elliott Hughesc0d41db2021-04-02 18:02:38 -0700367#endif
368}
Tamas Zsoldos6f106f72025-04-28 10:07:30 -0700369
370#if defined(__aarch64__)
371TEST(setjmp, sigsetjmp_sme) {
Tamas Petz99032782025-05-14 14:03:43 +0200372 if (!sme_is_enabled()) {
Tamas Zsoldos6f106f72025-04-28 10:07:30 -0700373 GTEST_SKIP() << "SME is not enabled on device.";
374 }
375
Tamas Zsoldos6f106f72025-04-28 10:07:30 -0700376 sigjmp_buf jb;
Tamas Petz99032782025-05-14 14:03:43 +0200377 sme_enable_za();
Tamas Zsoldos6f106f72025-04-28 10:07:30 -0700378 sigsetjmp(jb, 0);
Tamas Petz99032782025-05-14 14:03:43 +0200379 bool za_state = sme_is_za_on();
380 sme_disable_za(); // Turn ZA off anyway.
381 ASSERT_FALSE(za_state);
Tamas Zsoldos6f106f72025-04-28 10:07:30 -0700382}
383
384TEST(setjmp, siglongjmp_sme) {
Tamas Petz99032782025-05-14 14:03:43 +0200385 if (!sme_is_enabled()) {
Tamas Zsoldos6f106f72025-04-28 10:07:30 -0700386 GTEST_SKIP() << "SME is not enabled on device.";
387 }
388
Tamas Zsoldos6f106f72025-04-28 10:07:30 -0700389 int value;
390 sigjmp_buf jb;
391 if ((value = sigsetjmp(jb, 0)) == 0) {
Tamas Petz99032782025-05-14 14:03:43 +0200392 sme_enable_za();
Tamas Zsoldos6f106f72025-04-28 10:07:30 -0700393 siglongjmp(jb, 789);
Tamas Petz99032782025-05-14 14:03:43 +0200394 sme_disable_za();
Tamas Zsoldos6f106f72025-04-28 10:07:30 -0700395 FAIL(); // Unreachable.
396 } else {
Tamas Petz99032782025-05-14 14:03:43 +0200397 bool za_state = sme_is_za_on();
398 sme_disable_za(); // Turn ZA off anyway.
Tamas Zsoldos6f106f72025-04-28 10:07:30 -0700399 ASSERT_EQ(789, value);
Tamas Petz99032782025-05-14 14:03:43 +0200400 ASSERT_FALSE(za_state);
Tamas Zsoldos6f106f72025-04-28 10:07:30 -0700401 }
402}
403#endif