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 22 TEST(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 33 TEST(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 44 TEST(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 55 TEST(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 67 struct 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 88 void 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 97 TEST(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 112 TEST(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 135 TEST(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 150 TEST(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 202 TEST(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 216 #if defined(__arm__) 217 #define __JB_SIGFLAG 0 218 #elif defined(__aarch64__) 219 #define __JB_SIGFLAG 0 220 #elif defined(__i386__) 221 #define __JB_SIGFLAG 7 222 #elif defined(__x86_64) 223 #define __JB_SIGFLAG 8 224 #elif defined(__mips__) && defined(__LP64__) 225 #define __JB_SIGFLAG 1 226 #elif defined(__mips__) 227 #define __JB_SIGFLAG 2 228 #endif 229 230 TEST(setjmp, setjmp_cookie) { 231 jmp_buf jb; 232 int value = setjmp(jb); 233 ASSERT_EQ(0, value); 234 235 #if defined(__mips__) && !defined(__LP64__) 236 // round address to 8-byte boundry 237 uintptr_t jb_aligned = reinterpret_cast<uintptr_t>(jb) & ~7L; 238 long* sigflag = reinterpret_cast<long*>(jb_aligned) + __JB_SIGFLAG; 239 #else 240 long* sigflag = reinterpret_cast<long*>(jb) + __JB_SIGFLAG; 241 #endif 242 243 // Make sure there's actually a cookie. 244 EXPECT_NE(0, *sigflag & ~1); 245 246 // Wipe it out 247 *sigflag &= 1; 248 EXPECT_DEATH(longjmp(jb, 0), ""); 249 } 250 251 TEST(setjmp, setjmp_cookie_checksum) { 252 jmp_buf jb; 253 int value = setjmp(jb); 254 255 if (value == 0) { 256 // Flip a bit. 257 reinterpret_cast<long*>(jb)[0] ^= 1; 258 259 EXPECT_DEATH(longjmp(jb, 1), "checksum mismatch"); 260 } else { 261 fprintf(stderr, "setjmp_cookie_checksum: longjmp succeeded?"); 262 } 263 } 264