1 /* $NetBSD: t_setjmp.c,v 1.13 2025/04/28 18:29:09 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * Copyright (c) 1994 Christopher G. Demetriou 31 * All rights reserved. 32 * 33 * Redistribution and use in source and binary forms, with or without 34 * modification, are permitted provided that the following conditions 35 * are met: 36 * 1. Redistributions of source code must retain the above copyright 37 * notice, this list of conditions and the following disclaimer. 38 * 2. Redistributions in binary form must reproduce the above copyright 39 * notice, this list of conditions and the following disclaimer in the 40 * documentation and/or other materials provided with the distribution. 41 * 3. All advertising materials mentioning features or use of this software 42 * must display the following acknowledgement: 43 * This product includes software developed for the 44 * NetBSD Project. See http://www.NetBSD.org/ for 45 * information about NetBSD. 46 * 4. The name of the author may not be used to endorse or promote products 47 * derived from this software without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 50 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 51 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 52 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 53 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 54 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 55 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 56 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 57 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 58 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 * 60 * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>> 61 */ 62 63 #include <sys/cdefs.h> 64 __COPYRIGHT("@(#) Copyright (c) 2008\ 65 The NetBSD Foundation, inc. All rights reserved."); 66 __RCSID("$NetBSD: t_setjmp.c,v 1.13 2025/04/28 18:29:09 martin Exp $"); 67 68 #include <sys/types.h> 69 70 #include <dlfcn.h> 71 #include <errno.h> 72 #include <setjmp.h> 73 #include <signal.h> 74 #include <stdbool.h> 75 #include <stdio.h> 76 #include <stdlib.h> 77 #include <string.h> 78 #include <unistd.h> 79 80 #include <atf-c.h> 81 82 #include "h_macros.h" 83 84 enum test { 85 TEST_SETJMP, 86 TEST_U_SETJMP, 87 TEST_SIGSETJMP_SAVE, 88 TEST_SIGSETJMP_NOSAVE, 89 TEST_LONGJMP_ZERO, 90 TEST_U_LONGJMP_ZERO, 91 92 TEST_COMPAT13_SETJMP, 93 TEST_COMPAT13_SIGSETJMP_SAVE, 94 TEST_COMPAT13_SIGSETJMP_NOSAVE, 95 TEST_COMPAT13_LONGJMP_ZERO, 96 }; 97 98 /* 99 * Optional compat13 functions from when sigcontext was expanded. 100 * Fortunately the only change visible to the caller is that the size 101 * of jmp_buf increased, so we can always use the old symbols with new 102 * jmp_buf arrays. 103 */ 104 int (*compat13_sigsetjmp)(sigjmp_buf, int); 105 void (*compat13_siglongjmp)(sigjmp_buf, int); 106 int (*compat13_setjmp)(jmp_buf); 107 void (*compat13_longjmp)(jmp_buf, int); 108 109 /* 110 * compatsigsys(signo) 111 * 112 * Signal handler for SIGSYS in case compat_13_sigreturn13 is not 113 * implemented by the kernel -- we will just skip the test in that 114 * case. 115 */ 116 static void 117 compatsigsys(int signo) 118 { 119 120 atf_tc_skip("no compat syscalls to test"); 121 } 122 123 static void 124 compatsetup(void) 125 { 126 127 /* 128 * Grab the libc library symbols if available. 129 */ 130 if ((compat13_sigsetjmp = dlsym(RTLD_SELF, "sigsetjmp")) == NULL || 131 (compat13_siglongjmp = dlsym(RTLD_SELF, "siglongjmp")) == NULL || 132 (compat13_setjmp = dlsym(RTLD_SELF, "setjmp")) == NULL || 133 (compat13_longjmp = dlsym(RTLD_SELF, "longjmp")) == NULL) 134 atf_tc_skip("no compat functions to test"); 135 136 /* 137 * Arrange for SIGSYS to skip the test -- this happens if the 138 * libc stub has the function, but the kernel isn't built with 139 * support for the compat13 sigreturn syscall for longjmp. 140 */ 141 REQUIRE_LIBC(signal(SIGSYS, &compatsigsys), SIG_ERR); 142 } 143 144 static int expectsignal; 145 146 static void 147 aborthandler(int signo __unused) 148 { 149 ATF_REQUIRE_MSG(expectsignal, "kill(SIGABRT) succeeded"); 150 atf_tc_pass(); 151 } 152 153 static void 154 h_check(enum test test) 155 { 156 struct sigaction sa; 157 jmp_buf jb; 158 sigjmp_buf sjb; 159 sigset_t ss; 160 int i, x; 161 volatile bool did_longjmp; 162 163 i = getpid(); 164 did_longjmp = false; 165 166 switch (test) { 167 case TEST_COMPAT13_SETJMP: 168 case TEST_COMPAT13_SIGSETJMP_SAVE: 169 case TEST_COMPAT13_LONGJMP_ZERO: 170 case TEST_COMPAT13_SIGSETJMP_NOSAVE: 171 compatsetup(); 172 break; 173 default: 174 break; 175 } 176 177 switch (test) { 178 case TEST_SETJMP: 179 case TEST_SIGSETJMP_SAVE: 180 case TEST_LONGJMP_ZERO: 181 case TEST_COMPAT13_SETJMP: 182 case TEST_COMPAT13_SIGSETJMP_SAVE: 183 case TEST_COMPAT13_LONGJMP_ZERO: 184 expectsignal = 0; 185 break; 186 case TEST_U_SETJMP: 187 case TEST_SIGSETJMP_NOSAVE: 188 case TEST_U_LONGJMP_ZERO: 189 case TEST_COMPAT13_SIGSETJMP_NOSAVE: 190 expectsignal = 1; 191 break; 192 default: 193 atf_tc_fail("unknown test"); 194 } 195 196 sa.sa_handler = aborthandler; 197 sigemptyset(&sa.sa_mask); 198 sa.sa_flags = 0; 199 RL(sigaction(SIGABRT, &sa, NULL)); 200 RL(sigemptyset(&ss)); 201 RL(sigaddset(&ss, SIGABRT)); 202 RL(sigprocmask(SIG_BLOCK, &ss, NULL)); 203 204 switch (test) { 205 case TEST_SETJMP: 206 case TEST_LONGJMP_ZERO: 207 x = setjmp(jb); 208 break; 209 case TEST_COMPAT13_SETJMP: 210 case TEST_COMPAT13_LONGJMP_ZERO: 211 x = (*compat13_setjmp)(jb); 212 break; 213 case TEST_U_SETJMP: 214 case TEST_U_LONGJMP_ZERO: 215 x = _setjmp(jb); 216 break; 217 case TEST_SIGSETJMP_SAVE: 218 case TEST_SIGSETJMP_NOSAVE: 219 x = sigsetjmp(sjb, !expectsignal); 220 break; 221 case TEST_COMPAT13_SIGSETJMP_SAVE: 222 case TEST_COMPAT13_SIGSETJMP_NOSAVE: 223 x = (*compat13_sigsetjmp)(sjb, !expectsignal); 224 break; 225 default: 226 atf_tc_fail("unknown test"); 227 } 228 229 if (x != 0) { 230 switch (test) { 231 case TEST_LONGJMP_ZERO: 232 case TEST_U_LONGJMP_ZERO: 233 case TEST_COMPAT13_LONGJMP_ZERO: 234 ATF_REQUIRE_MSG(x == 1, "setjmp returned wrong value"); 235 break; 236 default: 237 ATF_REQUIRE_MSG(x == i, "setjmp returned wrong value"); 238 } 239 240 kill(i, SIGABRT); 241 ATF_REQUIRE_MSG(!expectsignal, "kill(SIGABRT) failed"); 242 atf_tc_pass(); 243 } else if (did_longjmp) { 244 atf_tc_fail("setjmp returned zero after longjmp"); 245 } 246 247 RL(sigprocmask(SIG_UNBLOCK, &ss, NULL)); 248 249 did_longjmp = true; 250 switch (test) { 251 case TEST_SETJMP: 252 longjmp(jb, i); 253 break; 254 case TEST_COMPAT13_SETJMP: 255 (*compat13_longjmp)(jb, i); 256 break; 257 case TEST_LONGJMP_ZERO: 258 longjmp(jb, 0); 259 break; 260 case TEST_COMPAT13_LONGJMP_ZERO: 261 (*compat13_longjmp)(jb, 0); 262 break; 263 case TEST_U_SETJMP: 264 _longjmp(jb, i); 265 break; 266 case TEST_U_LONGJMP_ZERO: 267 _longjmp(jb, 0); 268 break; 269 case TEST_SIGSETJMP_SAVE: 270 case TEST_SIGSETJMP_NOSAVE: 271 siglongjmp(sjb, i); 272 break; 273 case TEST_COMPAT13_SIGSETJMP_SAVE: 274 case TEST_COMPAT13_SIGSETJMP_NOSAVE: 275 (*compat13_siglongjmp)(sjb, i); 276 break; 277 default: 278 atf_tc_fail("unknown test"); 279 } 280 281 atf_tc_fail("jmp failed"); 282 } 283 284 ATF_TC(setjmp); 285 ATF_TC_HEAD(setjmp, tc) 286 { 287 atf_tc_set_md_var(tc, "descr", "Checks setjmp(3)"); 288 } 289 ATF_TC_BODY(setjmp, tc) 290 { 291 h_check(TEST_SETJMP); 292 } 293 294 ATF_TC(_setjmp); 295 ATF_TC_HEAD(_setjmp, tc) 296 { 297 atf_tc_set_md_var(tc, "descr", "Checks _setjmp(3)"); 298 } 299 ATF_TC_BODY(_setjmp, tc) 300 { 301 h_check(TEST_U_SETJMP); 302 } 303 304 ATF_TC(sigsetjmp_save); 305 ATF_TC_HEAD(sigsetjmp_save, tc) 306 { 307 atf_tc_set_md_var(tc, "descr", 308 "Checks sigsetjmp(3) with savemask enabled"); 309 } 310 ATF_TC_BODY(sigsetjmp_save, tc) 311 { 312 h_check(TEST_SIGSETJMP_SAVE); 313 } 314 315 ATF_TC(sigsetjmp_nosave); 316 ATF_TC_HEAD(sigsetjmp_nosave, tc) 317 { 318 atf_tc_set_md_var(tc, "descr", 319 "Checks sigsetjmp(3) with savemask disabled"); 320 } 321 ATF_TC_BODY(sigsetjmp_nosave, tc) 322 { 323 h_check(TEST_SIGSETJMP_NOSAVE); 324 } 325 326 ATF_TC(longjmp_zero); 327 ATF_TC_HEAD(longjmp_zero, tc) 328 { 329 atf_tc_set_md_var(tc, "descr", 330 "Checks longjmp(3) with a zero value"); 331 } 332 ATF_TC_BODY(longjmp_zero, tc) 333 { 334 h_check(TEST_LONGJMP_ZERO); 335 } 336 337 ATF_TC(_longjmp_zero); 338 ATF_TC_HEAD(_longjmp_zero, tc) 339 { 340 atf_tc_set_md_var(tc, "descr", 341 "Checks _longjmp(3) with a zero value"); 342 } 343 ATF_TC_BODY(_longjmp_zero, tc) 344 { 345 h_check(TEST_U_LONGJMP_ZERO); 346 } 347 348 ATF_TC(compat13_setjmp); 349 ATF_TC_HEAD(compat13_setjmp, tc) 350 { 351 atf_tc_set_md_var(tc, "descr", "Checks compat13 setjmp(3)"); 352 } 353 ATF_TC_BODY(compat13_setjmp, tc) 354 { 355 #ifdef __arm__ 356 atf_tc_expect_signal(-1, "PR port-arm/59351: compat_setjmp is busted"); 357 #endif 358 h_check(TEST_COMPAT13_SETJMP); 359 } 360 361 ATF_TC(compat13_sigsetjmp_save); 362 ATF_TC_HEAD(compat13_sigsetjmp_save, tc) 363 { 364 atf_tc_set_md_var(tc, "descr", 365 "Checks compat13 sigsetjmp(3) with savemask enabled"); 366 } 367 ATF_TC_BODY(compat13_sigsetjmp_save, tc) 368 { 369 #ifdef __arm__ 370 atf_tc_expect_signal(-1, "PR port-arm/59351: compat_setjmp is busted"); 371 #endif 372 h_check(TEST_COMPAT13_SIGSETJMP_SAVE); 373 } 374 375 ATF_TC(compat13_sigsetjmp_nosave); 376 ATF_TC_HEAD(compat13_sigsetjmp_nosave, tc) 377 { 378 atf_tc_set_md_var(tc, "descr", 379 "Checks compat13 sigsetjmp(3) with savemask disabled"); 380 } 381 ATF_TC_BODY(compat13_sigsetjmp_nosave, tc) 382 { 383 h_check(TEST_COMPAT13_SIGSETJMP_NOSAVE); 384 } 385 386 ATF_TC(compat13_longjmp_zero); 387 ATF_TC_HEAD(compat13_longjmp_zero, tc) 388 { 389 atf_tc_set_md_var(tc, "descr", 390 "Checks compat13 longjmp(3) with a zero value"); 391 } 392 ATF_TC_BODY(compat13_longjmp_zero, tc) 393 { 394 #ifdef __arm__ 395 atf_tc_expect_signal(-1, "PR port-arm/59351: compat_setjmp is busted"); 396 #endif 397 h_check(TEST_COMPAT13_LONGJMP_ZERO); 398 } 399 400 ATF_TP_ADD_TCS(tp) 401 { 402 403 ATF_TP_ADD_TC(tp, setjmp); 404 ATF_TP_ADD_TC(tp, _setjmp); 405 ATF_TP_ADD_TC(tp, sigsetjmp_save); 406 ATF_TP_ADD_TC(tp, sigsetjmp_nosave); 407 ATF_TP_ADD_TC(tp, longjmp_zero); 408 ATF_TP_ADD_TC(tp, _longjmp_zero); 409 410 ATF_TP_ADD_TC(tp, compat13_setjmp); 411 ATF_TP_ADD_TC(tp, compat13_sigsetjmp_save); 412 ATF_TP_ADD_TC(tp, compat13_sigsetjmp_nosave); 413 ATF_TP_ADD_TC(tp, compat13_longjmp_zero); 414 415 return atf_no_error(); 416 } 417