setjmp_test.cpp revision 87dd503018c075a7afe5f0c0613262aca3861d21
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 22TEST(setjmp, setjmp_smoke) { 23 int value; 24 jmp_buf jb; 25 if ((value = setjmp(jb)) == 0) { 26 longjmp(jb, 123); 27 FAIL(); // Unreachable. 28 } else { 29 ASSERT_EQ(123, value); 30 } 31} 32 33TEST(setjmp, _setjmp_smoke) { 34 int value; 35 jmp_buf jb; 36 if ((value = _setjmp(jb)) == 0) { 37 _longjmp(jb, 456); 38 FAIL(); // Unreachable. 39 } else { 40 ASSERT_EQ(456, value); 41 } 42} 43 44TEST(setjmp, sigsetjmp_0_smoke) { 45 int value; 46 sigjmp_buf jb; 47 if ((value = sigsetjmp(jb, 0)) == 0) { 48 siglongjmp(jb, 789); 49 FAIL(); // Unreachable. 50 } else { 51 ASSERT_EQ(789, value); 52 } 53} 54 55TEST(setjmp, sigsetjmp_1_smoke) { 56 int value; 57 sigjmp_buf jb; 58 if ((value = sigsetjmp(jb, 0)) == 0) { 59 siglongjmp(jb, 0xabc); 60 FAIL(); // Unreachable. 61 } else { 62 ASSERT_EQ(0xabc, value); 63 } 64} 65 66// Two distinct signal sets, pipu 67struct SigSets { 68 SigSets() : one(MakeSigSet(0)), two(MakeSigSet(1)) { 69 } 70 71 static sigset_t MakeSigSet(int offset) { 72 sigset_t ss; 73 sigemptyset(&ss); 74 sigaddset(&ss, SIGUSR1 + offset); 75#if defined(__LP64__) 76 // For arm and x86, sigset_t was too small for the RT signals. 77 // For mips, sigset_t was large enough but jmp_buf wasn't. 78 sigaddset(&ss, SIGRTMIN + offset); 79#endif 80 return ss; 81 } 82 83 sigset_t one; 84 sigset_t two; 85 sigset_t original; 86}; 87 88void AssertSigmaskEquals(const sigset_t& expected) { 89 sigset_t actual; 90 sigprocmask(0 /* ignored */, NULL, &actual); 91 size_t end = sizeof(sigset_t) * 8; 92 for (size_t i = 1; i <= end; ++i) { 93 EXPECT_EQ(sigismember(&expected, i), sigismember(&actual, i)) << i; 94 } 95} 96 97TEST(setjmp, _setjmp_signal_mask) { 98 // _setjmp/_longjmp do not save/restore the signal mask. 99 SigSets ss; 100 sigprocmask(SIG_SETMASK, &ss.one, &ss.original); 101 jmp_buf jb; 102 if (_setjmp(jb) == 0) { 103 sigprocmask(SIG_SETMASK, &ss.two, NULL); 104 _longjmp(jb, 1); 105 FAIL(); // Unreachable. 106 } else { 107 AssertSigmaskEquals(ss.two); 108 } 109 sigprocmask(SIG_SETMASK, &ss.original, NULL); 110} 111 112TEST(setjmp, setjmp_signal_mask) { 113 // setjmp/longjmp do save/restore the signal mask on bionic, but not on glibc. 114 // This is a BSD versus System V historical accident. POSIX leaves the 115 // behavior unspecified, so any code that cares needs to use sigsetjmp. 116 SigSets ss; 117 sigprocmask(SIG_SETMASK, &ss.one, &ss.original); 118 jmp_buf jb; 119 if (setjmp(jb) == 0) { 120 sigprocmask(SIG_SETMASK, &ss.two, NULL); 121 longjmp(jb, 1); 122 FAIL(); // Unreachable. 123 } else { 124#if defined(__BIONIC__) 125 // bionic behaves like BSD and does save/restore the signal mask. 126 AssertSigmaskEquals(ss.one); 127#else 128 // glibc behaves like System V and doesn't save/restore the signal mask. 129 AssertSigmaskEquals(ss.two); 130#endif 131 } 132 sigprocmask(SIG_SETMASK, &ss.original, NULL); 133} 134 135TEST(setjmp, sigsetjmp_0_signal_mask) { 136 // sigsetjmp(0)/siglongjmp do not save/restore the signal mask. 137 SigSets ss; 138 sigprocmask(SIG_SETMASK, &ss.one, &ss.original); 139 sigjmp_buf sjb; 140 if (sigsetjmp(sjb, 0) == 0) { 141 sigprocmask(SIG_SETMASK, &ss.two, NULL); 142 siglongjmp(sjb, 1); 143 FAIL(); // Unreachable. 144 } else { 145 AssertSigmaskEquals(ss.two); 146 } 147 sigprocmask(SIG_SETMASK, &ss.original, NULL); 148} 149 150TEST(setjmp, sigsetjmp_1_signal_mask) { 151 // sigsetjmp(1)/siglongjmp does save/restore the signal mask. 152 SigSets ss; 153 sigprocmask(SIG_SETMASK, &ss.one, &ss.original); 154 sigjmp_buf sjb; 155 if (sigsetjmp(sjb, 1) == 0) { 156 sigprocmask(SIG_SETMASK, &ss.two, NULL); 157 siglongjmp(sjb, 1); 158 FAIL(); // Unreachable. 159 } else { 160 AssertSigmaskEquals(ss.one); 161 } 162 sigprocmask(SIG_SETMASK, &ss.original, NULL); 163} 164 165#if defined(__aarch64__) 166#define SET_FREG(n, v) asm volatile("fmov d"#n ", "#v : : : "d"#n) 167#define CLEAR_FREG(n) asm volatile("fmov d"#n ", xzr" : : : "d"#n) 168#define SET_FREGS \ 169 SET_FREG(8, 8.0); SET_FREG(9, 9.0); SET_FREG(10, 10.0); SET_FREG(11, 11.0); \ 170 SET_FREG(12, 12.0); SET_FREG(13, 13.0); SET_FREG(14, 14.0); SET_FREG(15, 15.0); 171#define CLEAR_FREGS \ 172 CLEAR_FREG(8); CLEAR_FREG(9); CLEAR_FREG(10); CLEAR_FREG(11); \ 173 CLEAR_FREG(12); CLEAR_FREG(13); CLEAR_FREG(14); CLEAR_FREG(15); 174#define GET_FREG(n) ({ double _r; asm volatile("fmov %0, d"#n : "=r"(_r) : :); _r; }) 175#define CHECK_FREGS \ 176 EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \ 177 EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11)); \ 178 EXPECT_EQ(12.0, GET_FREG(12)); EXPECT_EQ(13.0, GET_FREG(13)); \ 179 EXPECT_EQ(14.0, GET_FREG(14)); EXPECT_EQ(15.0, GET_FREG(15)); 180#elif defined(__arm__) 181#define SET_FREG(n, v) \ 182 ({ const double _v{v}; asm volatile("fcpyd d"#n ", %P0" : : "w"(_v) : "d"#n); }) 183#define SET_FREGS \ 184 SET_FREG(8, 8); SET_FREG(9, 9); SET_FREG(10, 10); SET_FREG(11, 11); \ 185 SET_FREG(12, 12); SET_FREG(13, 13); SET_FREG(14, 14); SET_FREG(15, 15); 186#define CLEAR_FREGS \ 187 SET_FREG(8, 0); SET_FREG(9, 0); SET_FREG(10, 0); SET_FREG(11, 0); \ 188 SET_FREG(12, 0); SET_FREG(13, 0); SET_FREG(14, 0); SET_FREG(15, 0); 189#define GET_FREG(n) ({ double _r; asm volatile("fcpyd %P0, d"#n : "=w"(_r) : :); _r;}) 190#define CHECK_FREGS \ 191 EXPECT_EQ(8.0, GET_FREG(8)); EXPECT_EQ(9.0, GET_FREG(9)); \ 192 EXPECT_EQ(10.0, GET_FREG(10)); EXPECT_EQ(11.0, GET_FREG(11)); \ 193 EXPECT_EQ(12.0, GET_FREG(12)); EXPECT_EQ(13.0, GET_FREG(13)); \ 194 EXPECT_EQ(14.0, GET_FREG(14)); EXPECT_EQ(15.0, GET_FREG(15)); 195#else 196/* The other architectures don't save/restore fp registers. */ 197#define SET_FREGS 198#define CLEAR_FREGS 199#define CHECK_FREGS 200#endif 201 202TEST(setjmp, setjmp_fp_registers) { 203 int value; 204 jmp_buf jb; 205 SET_FREGS; 206 if ((value = setjmp(jb)) == 0) { 207 CLEAR_FREGS; 208 longjmp(jb, 123); 209 FAIL(); // Unreachable. 210 } else { 211 ASSERT_EQ(123, value); 212 CHECK_FREGS; 213 } 214} 215