diff options
327 files changed, 29404 insertions, 0 deletions
diff --git a/compat/Makefile b/compat/Makefile new file mode 100644 index 000000000000..8bd2100560a4 --- /dev/null +++ b/compat/Makefile @@ -0,0 +1,7 @@ +.include <bsd.own.mk> + +TESTSDIR= ${TESTSBASE}/compat + +TESTS_SUBDIRS= linux + +.include <bsd.test.mk> diff --git a/compat/linux/Makefile b/compat/linux/Makefile new file mode 100644 index 000000000000..cd3b1a91bf21 --- /dev/null +++ b/compat/linux/Makefile @@ -0,0 +1,61 @@ +# $NetBSD: Makefile,v 1.1 2023/08/19 22:56:44 christos Exp $ + +.include <bsd.own.mk> + +TESTSDIR= ${TESTSBASE}/compat/linux +TESTS_SH= t_inotify + +TC_PROGS= h_inotify_init +TC_PROGS+= h_inotify_directory +TC_PROGS+= h_inotify_single_file +TC_PROGS+= h_inotify_watch_change + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH} + +LDFLAGS+= -nostartfiles -static +CFLAGS+= -I${.CURDIR}/../../../sys +CFLAGS+= -I${.CURDIR} +CFLAGS+= -D_STANDALONE + +FILESDIR= ${TESTSDIR} + +.for _P in ${TESTS_SH} +.if ${MACHINE_ARCH} == "x86_64" +TESTS_SH_SRC_${_P}= h_common.sh +.else +TESTS_SH_SRC_${_P}= h_not_supported.sh +.endif +TESTS_SH_SRC_${_P}+= ${_P}.sh +.endfor + +.for _P in ${TC_PROGS} +CLEANFILES+= ${_P} +FILES+= ${_P} + +.if ${MACHINE_ARCH} == "x86_64" +PROGS+= ${_P}.out +SRCS.${_P}.out= ${_P}.c +SRCS.${_P}.out+= h_linux.c +SRCS.${_P}.out+= h_syscall.c +MAN.${_P}.out= # empty +FILESMODE_${_P}= ${BINMODE} + +proginstall-${_P}.out: + # Do not install + +${_P}: ${_P}.out + ${_MKTARGET_CREATE} + cp ${.ALLSRC} ${.TARGET} + ${ELFEDIT} --output-osabi Linux ${.TARGET} +.else +${_P}: + echo '' > ${.TARGET} +.endif + +realall: ${_P} +.endfor + +CLEANFILES+= ${TESTS_SH} +CLEANFILES+= Atffile + +.include <bsd.test.mk> diff --git a/compat/linux/arch/x86_64/h_syscall.c b/compat/linux/arch/x86_64/h_syscall.c new file mode 100644 index 000000000000..32485c121a47 --- /dev/null +++ b/compat/linux/arch/x86_64/h_syscall.c @@ -0,0 +1,55 @@ +/* $NetBSD: h_syscall.c,v 1.1 2023/08/19 22:56:44 christos Exp $ */ + +/*- + * Copyright (c) 2023 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Theodore Preduta. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_syscall.c,v 1.1 2023/08/19 22:56:44 christos Exp $"); +#include "h_linux.h" + +long +syscall6(long number, register_t arg1, register_t arg2, register_t arg3, + register_t arg4, register_t arg5, register_t arg6, ...) +{ + long retval; + register register_t r10 __asm__ ("r10") = arg4; + register register_t r8 __asm__ ("r8") = arg5; + register register_t r9 __asm__ ("r9") = arg6; + + __asm__ __volatile__ ("syscall" + : "=a"(retval) + : "a"(number), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10), "r"(r8), "r"(r9) + : "rcx", "r11", "memory"); + + if (retval < 0) { + errno = -retval; + return -1; + } + + return retval; +} diff --git a/compat/linux/h_common.sh b/compat/linux/h_common.sh new file mode 100644 index 000000000000..79e4d700566c --- /dev/null +++ b/compat/linux/h_common.sh @@ -0,0 +1,34 @@ +# $NetBSD: h_common.sh,v 1.1 2023/08/19 22:56:44 christos Exp $ +# +# Copyright (c) 2023 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Theodore Preduta. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +#/ + +h_ensure_emul_exists() { + modstat | grep -q '^compat_linux\W' \ + || atf_skip "Linux emulation not loaded" +} diff --git a/compat/linux/h_inotify_directory.c b/compat/linux/h_inotify_directory.c new file mode 100644 index 000000000000..3fc8d91e7674 --- /dev/null +++ b/compat/linux/h_inotify_directory.c @@ -0,0 +1,108 @@ +/* $NetBSD: h_inotify_directory.c,v 1.1 2023/08/19 22:56:44 christos Exp $ */ + +/*- + * Copyright (c) 2023 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Theodore Preduta. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_inotify_directory.c,v 1.1 2023/08/19 22:56:44 christos Exp $"); + +#include "h_linux.h" + +#include <sys/null.h> + +#include <compat/linux/linux_syscall.h> +#include <compat/linux/common/linux_inotify.h> + +#define INOTIFY_ALL_DIRECTORY (LINUX_IN_ATTRIB|LINUX_IN_CREATE \ + |LINUX_IN_MOVE_SELF|LINUX_IN_MOVED_FROM \ + |LINUX_IN_MOVED_TO|LINUX_IN_DELETE \ + |LINUX_IN_DELETE_SELF) + +char buf[8192]; + +struct { + uint32_t mask; + bool cookie; + char name[16]; +} target_events[] = { + { .mask = LINUX_IN_CREATE, .cookie = 0, .name = "test", }, + { .mask = LINUX_IN_MOVED_FROM, .cookie = 1, .name = "test", }, + { .mask = LINUX_IN_MOVED_TO, .cookie = 1, .name = "test2", }, + { .mask = LINUX_IN_DELETE, .cookie = 0, .name = "test2", }, + { .mask = LINUX_IN_MOVE_SELF, .cookie = 0, .name = "", }, + { .mask = LINUX_IN_DELETE_SELF, .cookie = 0, .name = "", }, + { .mask = LINUX_IN_IGNORED, .cookie = 0, .name = "", }, +}; + +void +_start(void) +{ + int fd, wd, targetfd; + char *cur_buf; + struct linux_inotify_event *cur_ie; + + RS(mkdir("test", 0644)); + + RS(fd = syscall(LINUX_SYS_inotify_init)); + RS(wd = syscall(LINUX_SYS_inotify_add_watch, fd, (register_t)"test", + INOTIFY_ALL_DIRECTORY)); + + /* Create some events. */ + RS(targetfd = open("test/test", LINUX_O_RDWR|LINUX_O_CREAT, 0644)); + RS(write(targetfd, &targetfd, sizeof(targetfd))); + RS(close(targetfd)); + RS(rename("test/test", "test/test2")); + RS(unlink("test/test2")); + RS(rename("test", "test2")); + RS(rmdir("test2")); + + /* Check the events. */ + RS(read(fd, buf, sizeof(buf))); + cur_buf = buf; + for (size_t i = 0; i < __arraycount(target_events); i++) { + cur_ie = (struct linux_inotify_event *)cur_buf; + + REQUIRE(cur_ie->wd == wd); + REQUIRE(cur_ie->mask == target_events[i].mask); + + if (target_events[i].cookie) + REQUIRE(cur_ie->cookie != 0); + else + REQUIRE(cur_ie->cookie == 0); + + if (target_events[i].name[0] != '\0') { + REQUIRE(cur_ie->len > strlen(target_events[i].name)); + REQUIRE(strcmp(cur_ie->name, target_events[i].name) == 0); + } else + REQUIRE(cur_ie->len == 0); + + cur_buf += sizeof(struct linux_inotify_event) + cur_ie->len; + } + + exit(0); +} diff --git a/compat/linux/h_inotify_init.c b/compat/linux/h_inotify_init.c new file mode 100644 index 000000000000..c1a45d9ad570 --- /dev/null +++ b/compat/linux/h_inotify_init.c @@ -0,0 +1,65 @@ +/* $NetBSD: h_inotify_init.c,v 1.1 2023/08/19 22:56:44 christos Exp $ */ + +/*- + * Copyright (c) 2023 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Theodore Preduta. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_inotify_init.c,v 1.1 2023/08/19 22:56:44 christos Exp $"); + +#include "h_linux.h" + +#include <compat/linux/linux_syscall.h> +#include <compat/linux/common/linux_errno.h> +#include <compat/linux/common/linux_fcntl.h> +#include <compat/linux/common/linux_inotify.h> + +void +_start(void) +{ + int fd; + + /* Check that none of CLOEXEC or NONBLOCK are set. */ + RS(fd = syscall(LINUX_SYS_inotify_init)); + REQUIRE(fcntl(fd, LINUX_F_GETFD) == 0); + REQUIRE((fcntl(fd, LINUX_F_GETFL) & LINUX_O_NONBLOCK) == 0); + RS(close(fd)); + + /* Check that only NONBLOCK is set. */ + RS(fd = syscall(LINUX_SYS_inotify_init1, LINUX_IN_NONBLOCK)); + REQUIRE(fcntl(fd, LINUX_F_GETFD) == 0); + REQUIRE((fcntl(fd, LINUX_F_GETFL) & LINUX_O_NONBLOCK) != 0); + RS(close(fd)); + + /* Check that only CLOEXEC is set. */ + RS(fd = syscall(LINUX_SYS_inotify_init1, LINUX_IN_CLOEXEC)); + REQUIRE(fcntl(fd, LINUX_F_GETFD) != 0); + REQUIRE((fcntl(fd, LINUX_F_GETFL) & LINUX_O_NONBLOCK) == 0); + RS(close(fd)); + + exit(0); +} diff --git a/compat/linux/h_inotify_single_file.c b/compat/linux/h_inotify_single_file.c new file mode 100644 index 000000000000..6e2f7125b120 --- /dev/null +++ b/compat/linux/h_inotify_single_file.c @@ -0,0 +1,87 @@ +/* $NetBSD: h_inotify_single_file.c,v 1.1 2023/08/19 22:56:44 christos Exp $ */ + +/*- + * Copyright (c) 2023 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Theodore Preduta. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_inotify_single_file.c,v 1.1 2023/08/19 22:56:44 christos Exp $"); + +#include "h_linux.h" + +#include <compat/linux/linux_syscall.h> +#include <compat/linux/common/linux_inotify.h> + +#define INOTIFY_ALL_FILE (LINUX_IN_ATTRIB|LINUX_IN_CLOSE_NOWRITE \ + |LINUX_IN_OPEN|LINUX_IN_MOVE_SELF \ + |LINUX_IN_ACCESS|LINUX_IN_CLOSE_WRITE \ + |LINUX_IN_MODIFY|LINUX_IN_DELETE_SELF) + +struct linux_inotify_event events[10]; + +void +_start(void) +{ + int fd, wd, targetfd, buf; + + RS(targetfd = open("test", LINUX_O_RDWR|LINUX_O_CREAT, 0644)); + RS(close(targetfd)); + + RS(fd = syscall(LINUX_SYS_inotify_init)); + RS(wd = syscall(LINUX_SYS_inotify_add_watch, fd, (register_t)"test", + INOTIFY_ALL_FILE)); + + /* Create some events. */ + RS(targetfd = open("test", LINUX_O_RDWR|LINUX_O_CREAT, 0644)); + RS(write(targetfd, &buf, sizeof(buf))); + RS(read(targetfd, &buf, sizeof(buf))); + RS(close(targetfd)); + RS(targetfd = open("test", LINUX_O_RDONLY|LINUX_O_CREAT, 0644)); + RS(close(targetfd)); + RS(rename("test", "test2")); + RS(unlink("test2")); + + /* Get and check the events. */ + RS(read(fd, events, sizeof(events))); + + for (size_t i = 0; i < __arraycount(events); i++) + REQUIRE(events[i].wd == wd && events[i].cookie == 0 + && events[i].len == 0); + + REQUIRE(events[0].mask == LINUX_IN_OPEN); + REQUIRE(events[1].mask == LINUX_IN_MODIFY); + REQUIRE(events[2].mask == LINUX_IN_ACCESS); + REQUIRE(events[3].mask == LINUX_IN_CLOSE_WRITE); + REQUIRE(events[4].mask == LINUX_IN_OPEN); + REQUIRE(events[5].mask == LINUX_IN_CLOSE_NOWRITE); + REQUIRE(events[6].mask == LINUX_IN_MOVE_SELF); + REQUIRE(events[7].mask == LINUX_IN_ATTRIB); + REQUIRE(events[8].mask == LINUX_IN_DELETE_SELF); + REQUIRE(events[9].mask == LINUX_IN_IGNORED); + + exit(0); +} diff --git a/compat/linux/h_inotify_watch_change.c b/compat/linux/h_inotify_watch_change.c new file mode 100644 index 000000000000..99075bd59940 --- /dev/null +++ b/compat/linux/h_inotify_watch_change.c @@ -0,0 +1,88 @@ +/* $NetBSD: h_inotify_watch_change.c,v 1.1 2023/08/19 22:56:44 christos Exp $ */ + +/*- + * Copyright (c) 2023 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Theodore Preduta. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_inotify_watch_change.c,v 1.1 2023/08/19 22:56:44 christos Exp $"); + +#include "h_linux.h" + +#include <compat/linux/linux_syscall.h> +#include <compat/linux/common/linux_inotify.h> + +struct linux_inotify_event events[2]; + +void +_start(void) +{ + int fd, wd, targetfd; + ssize_t nread; + + RS(targetfd = open("test", LINUX_O_RDWR|LINUX_O_CREAT, 0644)); + RS(close(targetfd)); + + RS(fd = syscall(LINUX_SYS_inotify_init)); + RS(wd = syscall(LINUX_SYS_inotify_add_watch, fd, (register_t)"test", + LINUX_IN_CLOSE_NOWRITE)); + + /* We should only get the close event. */ + RS(targetfd = open("test", LINUX_O_RDONLY|LINUX_O_CREAT, 0644)); + RS(close(targetfd)); + + RS(nread = read(fd, events, sizeof(events))); + REQUIRE(nread == sizeof(events[0])); + REQUIRE(events[0].mask == LINUX_IN_CLOSE_NOWRITE); + + /* Change the watch descriptor. */ + RS(wd = syscall(LINUX_SYS_inotify_add_watch, fd, (register_t)"test", + LINUX_IN_OPEN)); + + /* We should only get the open event. */ + RS(targetfd = open("test", LINUX_O_RDONLY|LINUX_O_CREAT, 0644)); + RS(close(targetfd)); + + RS(nread = read(fd, events, sizeof(events))); + REQUIRE(nread == sizeof(events[0])); + REQUIRE(events[0].mask == LINUX_IN_OPEN); + + /* Add to the watch descriptor. */ + RS(wd = syscall(LINUX_SYS_inotify_add_watch, fd, (register_t)"test", + LINUX_IN_CLOSE_NOWRITE|LINUX_IN_MASK_ADD)); + + /* Now we should get both the open and the close. */ + RS(targetfd = open("test", LINUX_O_RDONLY|LINUX_O_CREAT, 0644)); + RS(close(targetfd)); + + RS(nread = read(fd, events, sizeof(events))); + REQUIRE(nread == 2 * sizeof(events[0])); + REQUIRE(events[0].mask == LINUX_IN_OPEN); + REQUIRE(events[1].mask == LINUX_IN_CLOSE_NOWRITE); + + exit(0); +} diff --git a/compat/linux/h_linux.c b/compat/linux/h_linux.c new file mode 100644 index 000000000000..4acbb051626d --- /dev/null +++ b/compat/linux/h_linux.c @@ -0,0 +1,36 @@ +/* $NetBSD: h_linux.c,v 1.1 2023/08/19 22:56:44 christos Exp $ */ + +/*- + * Copyright (c) 2023 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Theodore Preduta. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_linux.c,v 1.1 2023/08/19 22:56:44 christos Exp $"); + +#include "h_linux.h" + +int errno = 0; diff --git a/compat/linux/h_linux.h b/compat/linux/h_linux.h new file mode 100644 index 000000000000..1b21fa6d39fc --- /dev/null +++ b/compat/linux/h_linux.h @@ -0,0 +1,76 @@ +/* $NetBSD: h_linux.h,v 1.2 2023/08/23 20:05:05 rillig Exp $ */ + +/*- + * Copyright (c) 2023 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Theodore Preduta. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef SRC_TESTS_COMPAT_LINUX_H_LINUX_H_ +#define SRC_TESTS_COMPAT_LINUX_H_LINUX_H_ + +#include <sys/types.h> /* For register_t. */ + +#define FAIL (-1) + +#define syscall(number, ...) syscall6(number, ## __VA_ARGS__, \ + 0, 0, 0, 0, 0, 0) + +#define RS(x) do { if ((x) == -1) exit(errno); } while (0) +#define REQUIRE(x) do { if (!(x)) exit(FAIL); } while (0) + +/* Convenience wrappers for common syscalls. */ +#define close(fd) (int)syscall(LINUX_SYS_close, fd) +#define exit(status) (void)syscall(LINUX_SYS_exit_group, status) +#define fcntl(fd, cmd, ...) (int)syscall(LINUX_SYS_fcntl, fd, cmd, \ + ## __VA_ARGS__) +#define lseek(fd, off, whence) (off_t)syscall(LINUX_SYS_lseek, fd, \ + (register_t)off, whence) +#define mkdir(path, mode) (int)syscall(LINUX_SYS_mkdir, \ + (register_t)path, mode) +#define open(path, flags, ...) (int)syscall(LINUX_SYS_open, \ + (register_t)path, flags, \ + ## __VA_ARGS__) +#define read(fd, buf, count) (ssize_t)syscall(LINUX_SYS_read, fd, \ + (register_t)buf, count) +#define rename(from, to) (int)syscall(LINUX_SYS___posix_rename, \ + (register_t)from, (register_t)to) +#define rmdir(path) (int)syscall(LINUX_SYS_rmdir, \ + (register_t)path) +#define unlink(path) (int)syscall(LINUX_SYS_unlink, \ + (register_t)path) +#define write(fd, buf, count) (ssize_t)syscall(LINUX_SYS_write, fd, \ + (register_t)buf, count) + +/* GCC builtins. */ +#define strcmp(s1, s2) __builtin_strcmp(s1, s2) +#define strlen(s) __builtin_strlen(s) + +long syscall6(long number, register_t, register_t, register_t, register_t, + register_t, register_t, ...); + +extern int errno; + +#endif /* !SRC_TESTS_COMPAT_LINUX_H_LINUX_H_ */ diff --git a/compat/linux/h_not_supported.sh b/compat/linux/h_not_supported.sh new file mode 100644 index 000000000000..97a8f58e75c1 --- /dev/null +++ b/compat/linux/h_not_supported.sh @@ -0,0 +1,33 @@ +# $NetBSD: h_not_supported.sh,v 1.1 2023/08/19 22:56:44 christos Exp $ +# +# Copyright (c) 2023 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Theodore Preduta. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +#/ + +h_ensure_emul_exists() { + atf_skip "Linux emulation tests are not supported on this architecture" +} diff --git a/compat/linux/t_inotify.sh b/compat/linux/t_inotify.sh new file mode 100644 index 000000000000..a25931a3b56d --- /dev/null +++ b/compat/linux/t_inotify.sh @@ -0,0 +1,79 @@ +# $NetBSD: t_inotify.sh,v 1.1 2023/08/19 22:56:44 christos Exp $ +# +# Copyright (c) 2023 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Theodore Preduta. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +#/ + +atf_test_case init +init_head() { + atf_set "descr" "Tests inotify_init applies its flags correctly" +} + +init_body() { + h_ensure_emul_exists + atf_check -s exit:0 "$(atf_get_srcdir)/h_inotify_init" +} + +atf_test_case single_file +single_file_head() { + atf_set "descr" \ + "Tests correct events are generated when a single file is watched" +} + +single_file_body() { + h_ensure_emul_exists + atf_check -s exit:0 "$(atf_get_srcdir)/h_inotify_single_file" +} + +atf_test_case directory +directory_head() { + atf_set "descr" \ + "Tests correct events are generated when a directory is watched" +} + +directory_body() { + h_ensure_emul_exists + atf_check -s exit:0 "$(atf_get_srcdir)/h_inotify_directory" +} + +atf_test_case watch_change +watch_change_head() { + atf_set "descr" \ + "Tests the watch descriptor can be modified" +} + +watch_change_body() { + h_ensure_emul_exists + atf_check -s exit:0 "$(atf_get_srcdir)/h_inotify_watch_change" +} + +atf_init_test_cases() { + atf_add_test_case init + atf_add_test_case directory + atf_add_test_case single_file + atf_add_test_case watch_change +} diff --git a/crypto/libcrypto/t_sha512trunc.c b/crypto/libcrypto/t_sha512trunc.c new file mode 100644 index 000000000000..619db68b7a21 --- /dev/null +++ b/crypto/libcrypto/t_sha512trunc.c @@ -0,0 +1,170 @@ +/* $NetBSD: t_sha512trunc.c,v 1.2 2024/03/15 18:10:37 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_sha512trunc.c,v 1.2 2024/03/15 18:10:37 riastradh Exp $"); + +#include <stddef.h> + +#include <atf-c.h> + +#include <openssl/evp.h> + +#include "h_macros.h" + +struct testcase { + const unsigned char in[128]; + size_t inlen; + const unsigned char out[32]; +}; + +static void +check(const struct testcase *C, size_t n, size_t digestlen, const EVP_MD *md) +{ + enum { C0 = 0xc0, C1 = 0xc1 }; + unsigned char *buf, *digest, *p0, *p1; + size_t i; + + ATF_REQUIRE_MSG(digestlen <= INT_MAX, "digestlen=%zu", digestlen); + ATF_REQUIRE_EQ_MSG((int)digestlen, EVP_MD_size(md), + "expected %d, got %d", (int)digestlen, EVP_MD_size(md)); + + ATF_REQUIRE_MSG(digestlen < SIZE_MAX - 2048, + "digestlen=%zu", digestlen); + REQUIRE_LIBC(buf = malloc(digestlen + 2048), NULL); + p0 = buf; + digest = buf + 1; + p1 = buf + 1 + digestlen; + + for (i = 0; i < n; i++) { + EVP_MD_CTX *ctx; + unsigned digestlen1; + + *p0 = C0; + *p1 = C1; + +#define REQUIRE(x) ATF_REQUIRE_MSG((x), "i=%zu", i) + REQUIRE(ctx = EVP_MD_CTX_new()); + REQUIRE(EVP_DigestInit_ex(ctx, md, NULL)); + REQUIRE(EVP_DigestUpdate(ctx, C->in, C->inlen)); + REQUIRE(EVP_DigestFinal_ex(ctx, digest, &digestlen1)); +#undef REQUIRE + ATF_CHECK_MSG(digestlen == digestlen1, + "i=%zu: expected %zu got %u", i, digestlen, digestlen1); + EVP_MD_CTX_free(ctx); + + ATF_CHECK_MSG(memcmp(digest, C->out, digestlen) == 0, + "i=%zu", i); + + ATF_CHECK_EQ_MSG(*p0, C0, "expected 0x%x got 0x%hhx", C0, *p0); + ATF_CHECK_EQ_MSG(*p1, C1, "expected 0x%x got 0x%hhx", C1, *p1); + } +} + +/* + * Test vectors from: + * + * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/Secure-Hashing#Testing + */ + +ATF_TC(sha512_224); +ATF_TC_HEAD(sha512_224, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test SHA512-224"); +} +ATF_TC_BODY(sha512_224, tc) +{ + static const struct testcase C[] = { + [0] = { + .inlen = 0, + .out = { + 0x6e,0xd0,0xdd,0x02, 0x80,0x6f,0xa8,0x9e, + 0x25,0xde,0x06,0x0c, 0x19,0xd3,0xac,0x86, + 0xca,0xbb,0x87,0xd6, 0xa0,0xdd,0xd0,0x5c, + 0x33,0x3b,0x84,0xf4, + }, + }, + [1] = { + .inlen = 1, + .in = { + 0xcf, + }, + .out = { + 0x41,0x99,0x23,0x9e, 0x87,0xd4,0x7b,0x6f, + 0xed,0xa0,0x16,0x80, 0x2b,0xf3,0x67,0xfb, + 0x6e,0x8b,0x56,0x55, 0xef,0xf6,0x22,0x5c, + 0xb2,0x66,0x8f,0x4a, + }, + }, + }; + + check(C, __arraycount(C), 28, EVP_sha512_224()); +} + +ATF_TC(sha512_256); +ATF_TC_HEAD(sha512_256, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test SHA512-256"); +} +ATF_TC_BODY(sha512_256, tc) +{ + static const struct testcase C[] = { + [0] = { + .inlen = 0, + .out = { + 0xc6,0x72,0xb8,0xd1, 0xef,0x56,0xed,0x28, + 0xab,0x87,0xc3,0x62, 0x2c,0x51,0x14,0x06, + 0x9b,0xdd,0x3a,0xd7, 0xb8,0xf9,0x73,0x74, + 0x98,0xd0,0xc0,0x1e, 0xce,0xf0,0x96,0x7a, + }, + }, + [1] = { + .inlen = 1, + .in = { + 0xfa, + }, + .out = { + 0xc4,0xef,0x36,0x92, 0x3c,0x64,0xe5,0x1e, + 0x87,0x57,0x20,0xe5, 0x50,0x29,0x8a,0x5a, + 0xb8,0xa3,0xf2,0xf8, 0x75,0xb1,0xe1,0xa4, + 0xc9,0xb9,0x5b,0xab, 0xf7,0x34,0x4f,0xef, + }, + }, + }; + + check(C, __arraycount(C), 32, EVP_sha512_256()); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, sha512_224); + ATF_TP_ADD_TC(tp, sha512_256); + + return atf_no_error(); +} diff --git a/fs/cd9660/h_hexdump_r.c b/fs/cd9660/h_hexdump_r.c new file mode 100644 index 000000000000..5436a71b5f8f --- /dev/null +++ b/fs/cd9660/h_hexdump_r.c @@ -0,0 +1,100 @@ +/* $NetBSD: h_hexdump_r.c,v 1.1 2024/04/28 14:39:22 rillig Exp $ */ + +/* + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code was contributed to The NetBSD Foundation by Roland Illig. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Given the output from "hexdump -C", reconstruct the original file. */ + +#include <err.h> +#include <inttypes.h> +#include <regex.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define H "[0-9a-f]" +#define HH " (" H H ")" + +static off_t off, noff; +static unsigned char prev_bytes[16], bytes[16], zeroes[16]; + +int +main(void) +{ + char line[81]; + regex_t data_re, end_re; + regmatch_t m[18]; + + if (regcomp(&data_re, "^(" H "{8,9})" + " " HH HH HH HH HH HH HH HH " " HH HH HH HH HH HH HH HH + " \\|.{16}\\|$", REG_EXTENDED) != 0) + err(1, "regcomp"); + if (regcomp(&end_re, "^(" H "{8,9})$", REG_EXTENDED) != 0) + err(1, "regcomp"); + + while (fgets(line, sizeof(line), stdin) != NULL) { + line[strcspn(line, "\n")] = '\0'; + + if (strcmp(line, "*") == 0) + continue; + + if (regexec(&data_re, line, 18, m, 0) == 0) { + noff = (off_t)strtoimax(line + m[1].rm_so, NULL, 16); + for (size_t i = 0; i < 16; i++) + bytes[i] = (unsigned char)strtoumax( + line + m[2 + i].rm_so, NULL, 16); + + } else if (regexec(&end_re, line, 2, m, 0) == 0) { + noff = (off_t)strtoimax(line + m[1].rm_so, NULL, 16); + if (off < noff) { + if (fseeko(stdout, noff - 16, SEEK_SET) != 0) + err(1, "fseeko"); + if (fwrite(prev_bytes, 1, 16, stdout) != 16) + err(1, "fwrite"); + } + } else + err(1, "invalid line '%s'", line); + + if (memcmp(prev_bytes, zeroes, 16) != 0) { + while (off < noff) { + if (fwrite(prev_bytes, 1, 16, stdout) != 16) + err(1, "fwrite"); + off += 16; + } + if (off != noff) + err(1, "off"); + } else { + if (fseeko(stdout, noff, SEEK_SET) != 0) + err(1, "fseeko"); + off = noff; + } + + memcpy(prev_bytes, bytes, 16); + } + return 0; +} diff --git a/fs/cd9660/pr_48787.image.hex b/fs/cd9660/pr_48787.image.hex new file mode 100644 index 000000000000..706af997e830 --- /dev/null +++ b/fs/cd9660/pr_48787.image.hex @@ -0,0 +1,278 @@ +00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +00008000 01 43 44 30 30 31 01 00 20 20 20 20 20 20 20 20 |.CD001.. | +00008010 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +00008020 20 20 20 20 20 20 20 20 49 53 4f 49 4d 41 47 45 | ISOIMAGE| +00008030 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +00008040 20 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00 | ........| +00008050 f9 41 20 00 00 20 41 f9 00 00 00 00 00 00 00 00 |.A .. A.........| +00008060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00008070 00 00 00 00 00 00 00 00 01 00 00 01 01 00 00 01 |................| +00008080 00 08 08 00 14 00 00 00 00 00 00 14 f5 41 20 00 |.............A .| +00008090 00 00 00 00 00 20 41 f6 00 00 00 00 22 00 f2 41 |..... A....."..A| +000080a0 20 00 00 20 41 f2 00 08 00 00 00 00 08 00 72 05 | .. A.........r.| +000080b0 06 0f 1f 21 00 02 00 00 01 00 00 01 01 00 20 20 |...!.......... | +000080c0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +* +000081b0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 58 4f | XO| +000081c0 52 52 49 53 4f 2d 31 2e 33 2e 37 20 32 30 31 34 |RRISO-1.3.7 2014| +000081d0 2e 30 35 2e 30 33 2e 31 31 35 30 31 31 2c 20 4c |.05.03.115011, L| +000081e0 49 42 49 53 4f 42 55 52 4e 2d 31 2e 33 2e 37 2c |IBISOBURN-1.3.7,| +000081f0 20 4c 49 42 49 53 4f 46 53 2d 31 2e 33 2e 37 2c | LIBISOFS-1.3.7,| +00008200 20 4c 49 42 42 55 52 4e 2d 31 2e 33 2e 37 20 20 | LIBBURN-1.3.7 | +00008210 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +* +00008320 20 20 20 20 20 20 20 20 20 20 20 20 20 32 30 31 | 201| +00008330 34 30 35 30 36 31 35 33 34 32 38 30 30 00 32 30 |4050615342800.20| +00008340 31 34 30 35 30 36 31 35 33 34 32 38 30 30 00 30 |14050615342800.0| +00008350 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 00 |000000000000000.| +00008360 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000| +00008370 00 01 00 20 20 20 20 20 20 20 20 20 20 20 20 20 |... | +00008380 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +* +00008570 20 20 20 00 00 00 00 00 00 00 00 00 00 00 00 00 | .............| +00008580 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +00008800 ff 43 44 30 30 31 01 00 00 00 00 00 00 00 00 00 |.CD001..........| +00008810 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +00018000 01 43 44 30 30 31 01 00 20 20 20 20 20 20 20 20 |.CD001.. | +00018010 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +00018020 20 20 20 20 20 20 20 20 49 53 4f 49 4d 41 47 45 | ISOIMAGE| +00018030 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +00018040 20 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00 | ........| +00018050 b9 41 20 00 00 20 41 b9 00 00 00 00 00 00 00 00 |.A .. A.........| +00018060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00018070 00 00 00 00 00 00 00 00 01 00 00 01 01 00 00 01 |................| +00018080 00 08 08 00 14 00 00 00 00 00 00 14 35 00 00 00 |............5...| +00018090 00 00 00 00 00 00 00 36 00 00 00 00 22 00 32 00 |.......6....".2.| +000180a0 00 00 00 00 00 32 00 08 00 00 00 00 08 00 72 05 |.....2........r.| +000180b0 06 0f 1f 21 00 02 00 00 01 00 00 01 01 00 20 20 |...!.......... | +000180c0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +* +000181b0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 58 4f | XO| +000181c0 52 52 49 53 4f 2d 31 2e 33 2e 37 20 32 30 31 34 |RRISO-1.3.7 2014| +000181d0 2e 30 35 2e 30 33 2e 31 31 35 30 31 31 2c 20 4c |.05.03.115011, L| +000181e0 49 42 49 53 4f 42 55 52 4e 2d 31 2e 33 2e 37 2c |IBISOBURN-1.3.7,| +000181f0 20 4c 49 42 49 53 4f 46 53 2d 31 2e 33 2e 37 2c | LIBISOFS-1.3.7,| +00018200 20 4c 49 42 42 55 52 4e 2d 31 2e 33 2e 37 20 20 | LIBBURN-1.3.7 | +00018210 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +* +00018320 20 20 20 20 20 20 20 20 20 20 20 20 20 32 30 31 | 201| +00018330 34 30 35 30 36 31 35 33 31 33 33 30 30 00 32 30 |4050615313300.20| +00018340 31 34 30 35 30 36 31 35 33 31 33 33 30 30 00 30 |14050615313300.0| +00018350 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 00 |000000000000000.| +00018360 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000| +00018370 00 01 00 20 20 20 20 20 20 20 20 20 20 20 20 20 |... | +00018380 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +* +00018570 20 20 20 00 00 00 00 00 00 00 00 00 00 00 00 00 | .............| +00018580 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +00018800 ff 43 44 30 30 31 01 00 00 00 00 00 00 00 00 00 |.CD001..........| +00018810 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +00019000 84 00 32 00 00 00 00 00 00 32 00 08 00 00 00 00 |..2......2......| +00019010 08 00 72 05 06 0f 1f 21 00 02 00 00 01 00 00 01 |..r....!........| +00019020 01 00 53 50 07 01 be ef 00 50 58 24 01 ed 41 00 |..SP.....PX$..A.| +00019030 00 00 00 41 ed 01 00 00 00 00 00 00 01 00 00 00 |...A............| +00019040 00 00 00 00 00 00 00 00 00 00 00 00 00 54 46 1a |.............TF.| +00019050 01 0e 72 05 06 0f 1f 21 00 72 05 06 0f 1f 21 00 |..r....!.r....!.| +00019060 72 05 06 0f 1f 21 00 43 45 1c 01 33 00 00 00 00 |r....!.CE..3....| +00019070 00 00 33 00 00 00 00 00 00 00 00 ed 00 00 00 00 |..3.............| +00019080 00 00 ed 00 60 00 32 00 00 00 00 00 00 32 00 08 |....`.2......2..| +00019090 00 00 00 00 08 00 72 05 06 0f 1f 21 00 02 00 00 |......r....!....| +000190a0 01 00 00 01 01 01 50 58 24 01 ed 41 00 00 00 00 |......PX$..A....| +000190b0 41 ed 01 00 00 00 00 00 00 01 00 00 00 00 00 00 |A...............| +000190c0 00 00 00 00 00 00 00 00 00 00 54 46 1a 01 0e 72 |..........TF...r| +000190d0 05 06 0f 1f 21 00 72 05 06 0f 1f 21 00 72 05 06 |....!.r....!.r..| +000190e0 0f 1f 21 00 6a 00 34 00 00 00 00 00 00 34 00 08 |..!.j.4......4..| +000190f0 00 00 00 00 08 00 72 05 06 0f 1e 12 00 02 00 00 |......r.........| +00019100 01 00 00 01 02 4d 59 00 50 58 24 01 ed 41 00 00 |.....MY.PX$..A..| +00019110 00 00 41 ed 01 00 00 00 00 00 00 01 e8 03 00 00 |..A.............| +00019120 00 00 03 e8 e8 03 00 00 00 00 03 e8 54 46 1a 01 |............TF..| +00019130 0e 72 05 06 0f 1e 12 00 72 05 06 0f 1a 0e 00 72 |.r......r......r| +00019140 05 06 0f 1e 12 00 4e 4d 07 01 00 6d 79 00 00 00 |......NM...my...| +00019150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +00019800 45 52 ed 01 0a 54 87 01 52 52 49 50 5f 31 39 39 |ER...T..RRIP_199| +00019810 31 41 54 48 45 20 52 4f 43 4b 20 52 49 44 47 45 |1ATHE ROCK RIDGE| +00019820 20 49 4e 54 45 52 43 48 41 4e 47 45 20 50 52 4f | INTERCHANGE PRO| +00019830 54 4f 43 4f 4c 20 50 52 4f 56 49 44 45 53 20 53 |TOCOL PROVIDES S| +00019840 55 50 50 4f 52 54 20 46 4f 52 20 50 4f 53 49 58 |UPPORT FOR POSIX| +00019850 20 46 49 4c 45 20 53 59 53 54 45 4d 20 53 45 4d | FILE SYSTEM SEM| +00019860 41 4e 54 49 43 53 50 4c 45 41 53 45 20 43 4f 4e |ANTICSPLEASE CON| +00019870 54 41 43 54 20 44 49 53 43 20 50 55 42 4c 49 53 |TACT DISC PUBLIS| +00019880 48 45 52 20 46 4f 52 20 53 50 45 43 49 46 49 43 |HER FOR SPECIFIC| +00019890 41 54 49 4f 4e 20 53 4f 55 52 43 45 2e 20 20 53 |ATION SOURCE. S| +000198a0 45 45 20 50 55 42 4c 49 53 48 45 52 20 49 44 45 |EE PUBLISHER IDE| +000198b0 4e 54 49 46 49 45 52 20 49 4e 20 50 52 49 4d 41 |NTIFIER IN PRIMA| +000198c0 52 59 20 56 4f 4c 55 4d 45 20 44 45 53 43 52 49 |RY VOLUME DESCRI| +000198d0 50 54 4f 52 20 46 4f 52 20 43 4f 4e 54 41 43 54 |PTOR FOR CONTACT| +000198e0 20 49 4e 46 4f 52 4d 41 54 49 4f 4e 2e 00 00 00 | INFORMATION....| +000198f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +0001a000 60 00 34 00 00 00 00 00 00 34 00 08 00 00 00 00 |`.4......4......| +0001a010 08 00 72 05 06 0f 1e 12 00 02 00 00 01 00 00 01 |..r.............| +0001a020 01 00 50 58 24 01 ed 41 00 00 00 00 41 ed 01 00 |..PX$..A....A...| +0001a030 00 00 00 00 00 01 e8 03 00 00 00 00 03 e8 e8 03 |................| +0001a040 00 00 00 00 03 e8 54 46 1a 01 0e 72 05 06 0f 1e |......TF...r....| +0001a050 12 00 72 05 06 0f 1a 0e 00 72 05 06 0f 1e 12 00 |..r......r......| +0001a060 60 00 32 00 00 00 00 00 00 32 00 08 00 00 00 00 |`.2......2......| +0001a070 08 00 72 05 06 0f 1f 21 00 02 00 00 01 00 00 01 |..r....!........| +0001a080 01 01 50 58 24 01 ed 41 00 00 00 00 41 ed 01 00 |..PX$..A....A...| +0001a090 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 |................| +0001a0a0 00 00 00 00 00 00 54 46 1a 01 0e 72 05 06 0f 1f |......TF...r....| +0001a0b0 21 00 72 05 06 0f 1f 21 00 72 05 06 0f 1f 21 00 |!.r....!.r....!.| +0001a0c0 7c 00 38 00 00 00 00 00 00 38 00 f8 ff ff ff ff ||.8......8......| +0001a0d0 f8 00 72 05 06 0f 1e 12 00 80 00 00 01 00 00 01 |..r.............| +0001a0e0 0d 4c 41 52 47 45 5f 46 49 4c 45 2e 3b 31 50 58 |.LARGE_FILE.;1PX| +0001a0f0 24 01 a4 81 00 00 00 00 81 a4 01 00 00 00 00 00 |$...............| +0001a100 00 01 e8 03 00 00 00 00 03 e8 e8 03 00 00 00 00 |................| +0001a110 03 e8 54 46 1a 01 0e 72 05 06 0f 1e 12 00 72 05 |..TF...r......r.| +0001a120 06 0f 1e 12 00 72 05 06 0f 1e 12 00 4e 4d 0f 01 |.....r......NM..| +0001a130 00 6c 61 72 67 65 5f 66 69 6c 65 00 7c 00 37 00 |.large_file.|.7.| +0001a140 20 00 00 20 00 37 00 10 0d 02 02 0d 10 00 72 05 | .. .7........r.| +0001a150 06 0f 1e 12 00 00 00 00 01 00 00 01 0d 4c 41 52 |.............LAR| +0001a160 47 45 5f 46 49 4c 45 2e 3b 31 50 58 24 01 a4 81 |GE_FILE.;1PX$...| +0001a170 00 00 00 00 81 a4 01 00 00 00 00 00 00 01 e8 03 |................| +0001a180 00 00 00 00 03 e8 e8 03 00 00 00 00 03 e8 54 46 |..............TF| +0001a190 1a 01 0e 72 05 06 0f 1e 12 00 72 05 06 0f 1e 12 |...r......r.....| +0001a1a0 00 72 05 06 0f 1e 12 00 4e 4d 0f 01 00 6c 61 72 |.r......NM...lar| +0001a1b0 67 65 5f 66 69 6c 65 00 00 00 00 00 00 00 00 00 |ge_file.........| +0001a1c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +0001a800 01 00 32 00 00 00 01 00 00 00 02 00 34 00 00 00 |..2.........4...| +0001a810 01 00 4d 59 00 00 00 00 00 00 00 00 00 00 00 00 |..MY............| +0001a820 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +0001b000 01 00 00 00 00 32 00 01 00 00 02 00 00 00 00 34 |.....2.........4| +0001b010 00 01 4d 59 00 00 00 00 00 00 00 00 00 00 00 00 |..MY............| +0001b020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +1020f8000 01 43 44 30 30 31 01 00 20 20 20 20 20 20 20 20 |.CD001.. | +1020f8010 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +1020f8020 20 20 20 20 20 20 20 20 49 53 4f 49 4d 41 47 45 | ISOIMAGE| +1020f8030 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +1020f8040 20 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00 | ........| +1020f8050 19 00 00 00 00 00 00 19 00 00 00 00 00 00 00 00 |................| +1020f8060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +1020f8070 00 00 00 00 00 00 00 00 01 00 00 01 01 00 00 01 |................| +1020f8080 00 08 08 00 14 00 00 00 00 00 00 14 f5 41 20 00 |.............A .| +1020f8090 00 00 00 00 00 20 41 f6 00 00 00 00 22 00 f2 41 |..... A....."..A| +1020f80a0 20 00 00 20 41 f2 00 08 00 00 00 00 08 00 72 05 | .. A.........r.| +1020f80b0 06 0f 1f 21 00 02 00 00 01 00 00 01 01 00 20 20 |...!.......... | +1020f80c0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +* +1020f81b0 20 20 20 20 20 20 20 20 20 20 20 20 20 20 58 4f | XO| +1020f81c0 52 52 49 53 4f 2d 31 2e 33 2e 37 20 32 30 31 34 |RRISO-1.3.7 2014| +1020f81d0 2e 30 35 2e 30 33 2e 31 31 35 30 31 31 2c 20 4c |.05.03.115011, L| +1020f81e0 49 42 49 53 4f 42 55 52 4e 2d 31 2e 33 2e 37 2c |IBISOBURN-1.3.7,| +1020f81f0 20 4c 49 42 49 53 4f 46 53 2d 31 2e 33 2e 37 2c | LIBISOFS-1.3.7,| +1020f8200 20 4c 49 42 42 55 52 4e 2d 31 2e 33 2e 37 20 20 | LIBBURN-1.3.7 | +1020f8210 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +* +1020f8320 20 20 20 20 20 20 20 20 20 20 20 20 20 32 30 31 | 201| +1020f8330 34 30 35 30 36 31 35 33 34 32 38 30 30 00 32 30 |4050615342800.20| +1020f8340 31 34 30 35 30 36 31 35 33 34 32 38 30 30 00 30 |14050615342800.0| +1020f8350 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 00 |000000000000000.| +1020f8360 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000| +1020f8370 00 01 00 20 20 20 20 20 20 20 20 20 20 20 20 20 |... | +1020f8380 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 | | +* +1020f8570 20 20 20 00 00 00 00 00 00 00 00 00 00 00 00 00 | .............| +1020f8580 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +1020f8800 ff 43 44 30 30 31 01 00 00 00 00 00 00 00 00 00 |.CD001..........| +1020f8810 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +1020f9000 84 00 f2 41 20 00 00 20 41 f2 00 08 00 00 00 00 |...A .. A.......| +1020f9010 08 00 72 05 06 0f 1f 21 00 02 00 00 01 00 00 01 |..r....!........| +1020f9020 01 00 53 50 07 01 be ef 00 50 58 24 01 ed 41 00 |..SP.....PX$..A.| +1020f9030 00 00 00 41 ed 01 00 00 00 00 00 00 01 00 00 00 |...A............| +1020f9040 00 00 00 00 00 00 00 00 00 00 00 00 00 54 46 1a |.............TF.| +1020f9050 01 0e 72 05 06 0f 1f 21 00 72 05 06 0f 1f 21 00 |..r....!.r....!.| +1020f9060 72 05 06 0f 1f 21 00 43 45 1c 01 f3 41 20 00 00 |r....!.CE...A ..| +1020f9070 20 41 f3 00 00 00 00 00 00 00 00 ed 00 00 00 00 | A..............| +1020f9080 00 00 ed 00 60 00 f2 41 20 00 00 20 41 f2 00 08 |....`..A .. A...| +1020f9090 00 00 00 00 08 00 72 05 06 0f 1f 21 00 02 00 00 |......r....!....| +1020f90a0 01 00 00 01 01 01 50 58 24 01 ed 41 00 00 00 00 |......PX$..A....| +1020f90b0 41 ed 01 00 00 00 00 00 00 01 00 00 00 00 00 00 |A...............| +1020f90c0 00 00 00 00 00 00 00 00 00 00 54 46 1a 01 0e 72 |..........TF...r| +1020f90d0 05 06 0f 1f 21 00 72 05 06 0f 1f 21 00 72 05 06 |....!.r....!.r..| +1020f90e0 0f 1f 21 00 6a 00 f4 41 20 00 00 20 41 f4 00 08 |..!.j..A .. A...| +1020f90f0 00 00 00 00 08 00 72 05 06 0f 1e 12 00 02 00 00 |......r.........| +1020f9100 01 00 00 01 02 4d 59 00 50 58 24 01 ed 41 00 00 |.....MY.PX$..A..| +1020f9110 00 00 41 ed 01 00 00 00 00 00 00 01 e8 03 00 00 |..A.............| +1020f9120 00 00 03 e8 e8 03 00 00 00 00 03 e8 54 46 1a 01 |............TF..| +1020f9130 0e 72 05 06 0f 1e 12 00 72 05 06 0f 1a 0e 00 72 |.r......r......r| +1020f9140 05 06 0f 1e 12 00 4e 4d 07 01 00 6d 79 00 7c 00 |......NM...my.|.| +1020f9150 f8 41 20 00 00 20 41 f8 06 00 00 00 00 00 00 06 |.A .. A.........| +1020f9160 72 05 06 0f 22 00 00 00 00 00 01 00 00 01 0d 53 |r..."..........S| +1020f9170 4d 41 4c 4c 5f 46 49 4c 45 2e 3b 31 50 58 24 01 |MALL_FILE.;1PX$.| +1020f9180 a4 81 00 00 00 00 81 a4 01 00 00 00 00 00 00 01 |................| +1020f9190 e8 03 00 00 00 00 03 e8 e8 03 00 00 00 00 03 e8 |................| +1020f91a0 54 46 1a 01 0e 72 05 06 0f 22 00 00 72 05 06 0f |TF...r..."..r...| +1020f91b0 22 00 00 72 05 06 0f 22 00 00 4e 4d 0f 01 00 73 |"..r..."..NM...s| +1020f91c0 6d 61 6c 6c 5f 66 69 6c 65 00 00 00 00 00 00 00 |mall_file.......| +1020f91d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +1020f9800 45 52 ed 01 0a 54 87 01 52 52 49 50 5f 31 39 39 |ER...T..RRIP_199| +1020f9810 31 41 54 48 45 20 52 4f 43 4b 20 52 49 44 47 45 |1ATHE ROCK RIDGE| +1020f9820 20 49 4e 54 45 52 43 48 41 4e 47 45 20 50 52 4f | INTERCHANGE PRO| +1020f9830 54 4f 43 4f 4c 20 50 52 4f 56 49 44 45 53 20 53 |TOCOL PROVIDES S| +1020f9840 55 50 50 4f 52 54 20 46 4f 52 20 50 4f 53 49 58 |UPPORT FOR POSIX| +1020f9850 20 46 49 4c 45 20 53 59 53 54 45 4d 20 53 45 4d | FILE SYSTEM SEM| +1020f9860 41 4e 54 49 43 53 50 4c 45 41 53 45 20 43 4f 4e |ANTICSPLEASE CON| +1020f9870 54 41 43 54 20 44 49 53 43 20 50 55 42 4c 49 53 |TACT DISC PUBLIS| +1020f9880 48 45 52 20 46 4f 52 20 53 50 45 43 49 46 49 43 |HER FOR SPECIFIC| +1020f9890 41 54 49 4f 4e 20 53 4f 55 52 43 45 2e 20 20 53 |ATION SOURCE. S| +1020f98a0 45 45 20 50 55 42 4c 49 53 48 45 52 20 49 44 45 |EE PUBLISHER IDE| +1020f98b0 4e 54 49 46 49 45 52 20 49 4e 20 50 52 49 4d 41 |NTIFIER IN PRIMA| +1020f98c0 52 59 20 56 4f 4c 55 4d 45 20 44 45 53 43 52 49 |RY VOLUME DESCRI| +1020f98d0 50 54 4f 52 20 46 4f 52 20 43 4f 4e 54 41 43 54 |PTOR FOR CONTACT| +1020f98e0 20 49 4e 46 4f 52 4d 41 54 49 4f 4e 2e 00 00 00 | INFORMATION....| +1020f98f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +1020fa000 60 00 f4 41 20 00 00 20 41 f4 00 08 00 00 00 00 |`..A .. A.......| +1020fa010 08 00 72 05 06 0f 1e 12 00 02 00 00 01 00 00 01 |..r.............| +1020fa020 01 00 50 58 24 01 ed 41 00 00 00 00 41 ed 01 00 |..PX$..A....A...| +1020fa030 00 00 00 00 00 01 e8 03 00 00 00 00 03 e8 e8 03 |................| +1020fa040 00 00 00 00 03 e8 54 46 1a 01 0e 72 05 06 0f 1e |......TF...r....| +1020fa050 12 00 72 05 06 0f 1a 0e 00 72 05 06 0f 1e 12 00 |..r......r......| +1020fa060 60 00 f2 41 20 00 00 20 41 f2 00 08 00 00 00 00 |`..A .. A.......| +1020fa070 08 00 72 05 06 0f 1f 21 00 02 00 00 01 00 00 01 |..r....!........| +1020fa080 01 01 50 58 24 01 ed 41 00 00 00 00 41 ed 01 00 |..PX$..A....A...| +1020fa090 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 |................| +1020fa0a0 00 00 00 00 00 00 54 46 1a 01 0e 72 05 06 0f 1f |......TF...r....| +1020fa0b0 21 00 72 05 06 0f 1f 21 00 72 05 06 0f 1f 21 00 |!.r....!.r....!.| +1020fa0c0 7c 00 38 00 00 00 00 00 00 38 00 f8 ff ff ff ff ||.8......8......| +1020fa0d0 f8 00 72 05 06 0f 1e 12 00 80 00 00 01 00 00 01 |..r.............| +1020fa0e0 0d 4c 41 52 47 45 5f 46 49 4c 45 2e 3b 31 50 58 |.LARGE_FILE.;1PX| +1020fa0f0 24 01 a4 81 00 00 00 00 81 a4 01 00 00 00 00 00 |$...............| +1020fa100 00 01 e8 03 00 00 00 00 03 e8 e8 03 00 00 00 00 |................| +1020fa110 03 e8 54 46 1a 01 0e 72 05 06 0f 1e 12 00 72 05 |..TF...r......r.| +1020fa120 06 0f 1e 12 00 72 05 06 0f 1e 12 00 4e 4d 0f 01 |.....r......NM..| +1020fa130 00 6c 61 72 67 65 5f 66 69 6c 65 00 7c 00 37 00 |.large_file.|.7.| +1020fa140 20 00 00 20 00 37 00 10 0d 02 02 0d 10 00 72 05 | .. .7........r.| +1020fa150 06 0f 1e 12 00 00 00 00 01 00 00 01 0d 4c 41 52 |.............LAR| +1020fa160 47 45 5f 46 49 4c 45 2e 3b 31 50 58 24 01 a4 81 |GE_FILE.;1PX$...| +1020fa170 00 00 00 00 81 a4 01 00 00 00 00 00 00 01 e8 03 |................| +1020fa180 00 00 00 00 03 e8 e8 03 00 00 00 00 03 e8 54 46 |..............TF| +1020fa190 1a 01 0e 72 05 06 0f 1e 12 00 72 05 06 0f 1e 12 |...r......r.....| +1020fa1a0 00 72 05 06 0f 1e 12 00 4e 4d 0f 01 00 6c 61 72 |.r......NM...lar| +1020fa1b0 67 65 5f 66 69 6c 65 00 00 00 00 00 00 00 00 00 |ge_file.........| +1020fa1c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +1020fa800 01 00 f2 41 20 00 01 00 00 00 02 00 f4 41 20 00 |...A ........A .| +1020fa810 01 00 4d 59 00 00 00 00 00 00 00 00 00 00 00 00 |..MY............| +1020fa820 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +1020fb000 01 00 00 20 41 f2 00 01 00 00 02 00 00 20 41 f4 |... A........ A.| +1020fb010 00 01 4d 59 00 00 00 00 00 00 00 00 00 00 00 00 |..MY............| +1020fb020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +1020fc000 68 65 6c 6c 6f 0a 00 00 00 00 00 00 00 00 00 00 |hello...........| +1020fc010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +* +102150000 diff --git a/fs/lfs/t_basic.c b/fs/lfs/t_basic.c new file mode 100644 index 000000000000..3a01a5a43569 --- /dev/null +++ b/fs/lfs/t_basic.c @@ -0,0 +1,79 @@ +/* $NetBSD: t_basic.c,v 1.1 2025/10/13 00:44:35 perseant Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <ufs/ufs/ufsmount.h> +#include <ufs/lfs/lfs.h> +#include <ufs/lfs/lfs_extern.h> + +#include "h_macros.h" +#include "util.h" + +#define FSSIZE 10000 + +/* Actually run the test */ +void test(int); + +ATF_TC(newfs_fsck32); +ATF_TC_HEAD(newfs_fsck32, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS32 newfs_lfs produces a filesystem that passes fsck_lfs"); + atf_tc_set_md_var(tc, "timeout", "20"); +} + +ATF_TC(newfs_fsck64); +ATF_TC_HEAD(newfs_fsck64, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS64 newfs_lfs produces a filesystem that passes fsck_lfs"); + atf_tc_set_md_var(tc, "timeout", "20"); +} + +ATF_TC_BODY(newfs_fsck32, tc) +{ + test(32); +} + +ATF_TC_BODY(newfs_fsck64, tc) +{ + test(64); +} + +void test(int width) +{ + setvbuf(stdout, NULL, _IONBF, 0); + + /* + * Initialize. + */ + + /* Create image file larger than filesystem */ + create_lfs(FSSIZE, FSSIZE, width, 1); + + if (fsck()) + atf_tc_fail_errno("fsck found errors after first unmount"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, newfs_fsck32); + ATF_TP_ADD_TC(tp, newfs_fsck64); + return atf_no_error(); +} diff --git a/fs/lfs/t_fcntl.c b/fs/lfs/t_fcntl.c new file mode 100644 index 000000000000..0d7c1f86d79f --- /dev/null +++ b/fs/lfs/t_fcntl.c @@ -0,0 +1,407 @@ +/* $NetBSD: t_fcntl.c,v 1.6 2025/12/10 03:08:52 perseant Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <string.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <ufs/ufs/ufsmount.h> +#include <ufs/lfs/lfs.h> +#include <ufs/lfs/lfs_extern.h> + +#include "h_macros.h" +#include "util.h" + +/* Debugging conditions */ +/* #define FORCE_SUCCESS */ /* Don't actually revert, everything worked */ +/* #define USE_DUMPLFS */ /* Dump the filesystem at certain steps */ + +#define UNCHANGED_CONTROL MP "/3-a-random-file" +#define FSSIZE 10000 /* In sectors */ +#define A_FEW_BLOCKS 6500 /* In bytes; a few blocks worth */ +#define MORE_THAN_A_SEGMENT (4 * SEGSIZE) /* In bytes; > SEGSIZE */ + +/* Set up filesystem with a file in it */ +int setup(int, struct ufs_args *, off_t); + +/* Actually run the test */ +void coalesce(int); +void cleanseg(int); +void autoclean(int); + +/* Unmount and check fsck */ +void teardown(int, struct ufs_args *, off_t); + +ATF_TC(coalesce32); +ATF_TC_HEAD(coalesce32, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS32 LFCNSCRAMBLE/LFCNREWRITEFILE"); + /* atf_tc_set_md_var(tc, "timeout", "20"); */ +} + +ATF_TC(coalesce64); +ATF_TC_HEAD(coalesce64, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS64 LFCNSCRAMBLE/LFCNREWRITEFILE"); + /* atf_tc_set_md_var(tc, "timeout", "20"); */ +} + +ATF_TC(cleanseg32); +ATF_TC_HEAD(cleanseg32, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS32 LFCNREWRITESEG"); + atf_tc_set_md_var(tc, "timeout", "20"); +} + +ATF_TC(cleanseg64); +ATF_TC_HEAD(cleanseg64, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS64 LFCNREWRITESEG"); + atf_tc_set_md_var(tc, "timeout", "20"); +} + +ATF_TC(autoclean32); +ATF_TC_HEAD(autoclean32, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS32 LFCNAUTOCLEAN"); + /* atf_tc_set_md_var(tc, "timeout", "20"); */ +} + +ATF_TC(autoclean64); +ATF_TC_HEAD(autoclean64, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS64 LFCNAUTOCLEAN"); + /* atf_tc_set_md_var(tc, "timeout", "20"); */ +} + +ATF_TC_BODY(coalesce32, tc) +{ + coalesce(32); +} + +ATF_TC_BODY(coalesce64, tc) +{ + coalesce(64); +} + +ATF_TC_BODY(cleanseg32, tc) +{ + cleanseg(32); +} + +ATF_TC_BODY(cleanseg64, tc) +{ + cleanseg(64); +} + +ATF_TC_BODY(autoclean32, tc) +{ + autoclean(32); +} + +ATF_TC_BODY(autoclean64, tc) +{ + autoclean(64); +} + +int setup(int width, struct ufs_args *argsp, off_t filesize) +{ + int fd; + + setvbuf(stdout, NULL, _IONBF, 0); + + /* + * Initialize. + */ + + /* Create image file */ + create_lfs(FSSIZE, FSSIZE, width, 1); + + /* Mount filesystem */ + fprintf(stderr, "* Mount fs [1]\n"); + memset(argsp, 0, sizeof *argsp); + argsp->fspec = __UNCONST(FAKEBLK); + if (rump_sys_mount(MOUNT_LFS, MP, 0, argsp, sizeof *argsp) == -1) + atf_tc_fail_errno("rump_sys_mount failed"); + + /* Payload */ + fprintf(stderr, "* Initial payload\n"); + write_file(UNCHANGED_CONTROL, filesize, 1, 3); + + /* Make the data go to disk */ + fprintf(stderr, "* Double sync\n"); + rump_sys_sync(); + rump_sys_sync(); + + /* Get a handle to the root of the file system */ + fd = rump_sys_open(MP, O_RDONLY); + if (fd < 0) + atf_tc_fail_errno("rump_sys_open mount point root failed"); + + return fd; +} + +void teardown(int fd, struct ufs_args *argsp, off_t filesize) +{ + /* Close descriptor */ + rump_sys_close(fd); + + /* Unmount */ + if (rump_sys_unmount(MP, 0) < 0) + atf_tc_fail_errno("rump_sys_unmount failed[1]"); + + /* Fsck */ + fprintf(stderr, "* Fsck after final unmount\n"); + if (fsck()) + atf_tc_fail("fsck found errors after final unmount"); + + /* + * Check file system contents + */ + + /* Mount filesystem one last time */ + fprintf(stderr, "* Mount fs again to check contents\n"); + if (rump_sys_mount(MOUNT_LFS, MP, 0, argsp, sizeof *argsp) == -1) + atf_tc_fail_errno("rump_sys_mount failed [4]"); + + if (check_file(UNCHANGED_CONTROL, filesize, 3) != 0) + atf_tc_fail("Unchanged control file differs(!)"); + + /* Umount filesystem */ + if (rump_sys_unmount(MP, 0) < 0) + atf_tc_fail_errno("rump_sys_unmount failed[2]"); + + /* Final fsck to double check */ + fprintf(stderr, "* Fsck after final unmount\n"); + if (fsck()) + atf_tc_fail("fsck found errors after final unmount"); +} + +void coalesce(int width) +{ + struct ufs_args args; + struct stat statbuf; + struct lfs_filestat_req fsr; + struct lfs_filestats fss_before, fss_scrambled, fss_after; + struct lfs_inode_array inotbl; + int fd; + ino_t ino; + + fd = setup(width, &args, A_FEW_BLOCKS); + + /* Get our file's inode number */ + if (rump_sys_stat(UNCHANGED_CONTROL, &statbuf) != 0) + atf_tc_fail_errno("rump_sys_stat failed"); + ino = statbuf.st_ino; + + fprintf(stderr, "Treating inode %d\n", (int)ino); + + /* Retrieve fragmentation statistics */ + memset(&fss_before, 0, sizeof fss_before); + memset(&fss_scrambled, 0, sizeof fss_scrambled); + memset(&fss_after, 0, sizeof fss_after); + + fsr.ino = ino; + fsr.len = 1; + fsr.fss = &fss_before; + if (rump_sys_fcntl(fd, LFCNFILESTATS, &fsr) < 0) + atf_tc_fail_errno("LFCNFILESTATS[1] failed"); + + inotbl.len = 1; + inotbl.inodes = &ino; + + fprintf(stderr, "Start ino %d nblk %d count %d total %d\n", + (int)ino, (int)fss_before.nblk, (int)fss_before.dc_count, + (int)fss_before.dc_sum); + + /* Scramble */ + if (rump_sys_fcntl(fd, LFCNSCRAMBLE, &inotbl) < 0) + atf_tc_fail_errno("LFCNSCRAMBLE failed"); + fsr.fss = &fss_scrambled; + if (rump_sys_fcntl(fd, LFCNFILESTATS, &fsr) < 0) + atf_tc_fail_errno("LFCNFILESTATS[2] failed"); + if (fss_scrambled.dc_count <= fss_before.dc_count) + atf_tc_fail("Scramble did not worsen gap count"); + if (fss_scrambled.dc_sum <= fss_before.dc_sum) + atf_tc_fail("Scramble did not worsen total gap length"); + + fprintf(stderr, "Scrambled ino %d nblk %d count %d total %d\n", + (int)ino, (int)fss_scrambled.nblk, (int)fss_scrambled.dc_count, + (int)fss_scrambled.dc_sum); + + /* Coalesce */ + if (rump_sys_fcntl(fd, LFCNREWRITEFILE, &inotbl) < 0) + atf_tc_fail_errno("LFCNREWRITEFILE failed"); + fsr.fss = &fss_after; + if (rump_sys_fcntl(fd, LFCNFILESTATS, &fsr) < 0) + atf_tc_fail_errno("LFCNFILESTATS[3] failed"); + if (fss_scrambled.dc_count <= fss_after.dc_count) + atf_tc_fail("Rewrite did not improve gap count"); + if (fss_scrambled.dc_sum <= fss_after.dc_sum) + atf_tc_fail("Rewrite did not improve total gap length"); + + fprintf(stderr, "Coalesced ino %d nblk %d count %d total %d\n", + (int)ino, (int)fss_after.nblk, (int)fss_after.dc_count, + (int)fss_after.dc_sum); + + teardown(fd, &args, A_FEW_BLOCKS); +} + +void cleanseg(int width) +{ + struct ufs_args args; + struct lfs_segnum_array sna; + struct lfs_seguse_array sua; + int fd, sn; + + fd = setup(width, &args, MORE_THAN_A_SEGMENT); + + fprintf(stderr, "* Get seguse\n"); + sua.len = LFS_SEGUSE_MAXCNT; + sua.start = 0; + sua.seguse = malloc(LFS_SEGUSE_MAXCNT * sizeof(*sua.seguse)); + if (rump_sys_fcntl(fd, LFCNSEGUSE, &sua) < 0) + atf_tc_fail_errno("LFCNSEGUSE[1] failed"); + + for (sn = 0; sn < (int)sua.len; ++sn) { + if (sua.seguse[sn].su_nbytes == 0) + continue; + if ((sua.seguse[sn].su_flags & (SEGUSE_DIRTY | SEGUSE_ACTIVE)) + != SEGUSE_DIRTY) + continue; + break; + } + if (sn == (int)sua.len) + atf_tc_fail("No segments found to clean"); + + fprintf(stderr, "* Cleaning segment #%d\n", sn); + + memset(&sna, 0, sizeof sna); + sna.len = 1; + sna.segments = &sn; + if (rump_sys_fcntl(fd, LFCNREWRITESEGS, &sna) < 0) + atf_tc_fail_errno("LFCNREWRITESEGS failed"); + + fprintf(stderr, "* Double sync\n"); + rump_sys_sync(); + rump_sys_sync(); + + fprintf(stderr, "* Get seguse again\n"); + sua.len = 1; + sua.start = sn; + if (rump_sys_fcntl(fd, LFCNSEGUSE, &sua) < 0) + atf_tc_fail_errno("LFCNSEGUSE[2] failed"); + + if (sua.seguse[0].su_nbytes > 0) + atf_tc_fail("Empty bytes after clean"); + + fprintf(stderr, "* Teardown\n"); + teardown(fd, &args, MORE_THAN_A_SEGMENT); +} + +void autoclean(int width) +{ + struct ufs_args args; + struct lfs_autoclean_params autoclean; + int i, fd; + char filename[1024]; + struct statvfs statbuf; + CLEANERINFO64 ci_before, ci_after; + unsigned long target; + + fd = setup(width, &args, CHUNKSIZE); + + rump_sys_fstatvfs1(fd, &statbuf, ST_WAIT); + target = 7 * statbuf.f_blocks / 8; + + /* Write a number of files, deleting every other one. */ + fprintf(stderr, "* Write numbered files\n"); + for (i = 4; ; i++) { + fprintf(stderr, "* create %d\n", i); + sprintf(filename, "%s/%d", MP, i); + write_file(filename, SEGSIZE / 3, 1, 0); + rump_sys_fstatvfs1(fd, &statbuf, ST_WAIT); + if (statbuf.f_bfree < target) + break; + fprintf(stderr, " %ld blocks vs target %ld\n", + (long)statbuf.f_bfree, (long)target); + } + rump_sys_sync(); + rump_sys_sync(); + + /* Record cleanerinfo */ + fprintf(stderr, "* Get cleanerinfo\n"); + if (rump_sys_fcntl(fd, LFCNCLEANERINFO, &ci_before) < 0) + atf_tc_fail_errno("LFCNCLEANERINFO[1] failed"); + + /* Start autocleaner */ + autoclean.size = sizeof(autoclean); + autoclean.mode = LFS_CLEANMODE_GREEDY; + autoclean.thresh = -1; + autoclean.target = -1; + if (rump_sys_fcntl(fd, LFCNAUTOCLEAN, &autoclean) < 0) + atf_tc_fail_errno("LFCNAUTOCLEAN[1] failed"); + + /* Make many segments almost empty */ + fprintf(stderr, "* Delete most files\n"); + for (; i > 0; i--) { + if (i % 3 == 0) + continue; + fprintf(stderr, "* delete %d\n", i); + sprintf(filename, "%s/%d", MP, i); + rump_sys_unlink(filename); + } + rump_sys_sync(); + rump_sys_sync(); + + /* Give the cleaner a chance to run */ + fprintf(stderr, "* Sleep\n"); + sleep(5); + + /* Auto reclaim freed segments */ + fprintf(stderr, "* Sync\n"); + rump_sys_sync(); + rump_sys_sync(); + + /* Record cleanerinfo again */ + fprintf(stderr, "* Get cleanerinfo again\n"); + if (rump_sys_fcntl(fd, LFCNCLEANERINFO, &ci_after) < 0) + atf_tc_fail_errno("LFCNCLEANERINFO[2] failed"); + + /* Compare */ + if (ci_before.avail >= ci_after.avail) + atf_tc_fail("No improvement"); + + teardown(fd, &args, CHUNKSIZE); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, coalesce32); + ATF_TP_ADD_TC(tp, coalesce64); + ATF_TP_ADD_TC(tp, cleanseg32); + ATF_TP_ADD_TC(tp, cleanseg64); + ATF_TP_ADD_TC(tp, autoclean32); + ATF_TP_ADD_TC(tp, autoclean64); + return atf_no_error(); +} diff --git a/fs/lfs/t_orphan.c b/fs/lfs/t_orphan.c new file mode 100644 index 000000000000..c1cf7f1f71b8 --- /dev/null +++ b/fs/lfs/t_orphan.c @@ -0,0 +1,203 @@ +/* $NetBSD: t_orphan.c,v 1.4 2025/12/19 20:58:08 perseant Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <string.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <ufs/ufs/ufsmount.h> +#include <ufs/lfs/lfs.h> +#include <ufs/lfs/lfs_extern.h> + +#include "h_macros.h" +#include "util.h" + +/* Debugging conditions */ +/* #define FORCE_SUCCESS */ /* Don't actually revert, everything worked */ +/* #define USE_DUMPLFS */ /* Dump the filesystem at certain steps */ + +#define UNCHANGED_CONTROL MP "/3-a-random-file" +#define FSSIZE 10000 /* In sectors */ +#define FILE_SIZE 65000 /* In bytes; a few blocks worth */ +#define TMPFILE "filehandle" + +/* Actually run the test */ +void orphan(int); + +ATF_TC(orphan32); +ATF_TC_HEAD(orphan32, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS32 orphan removal"); + atf_tc_set_md_var(tc, "timeout", "20"); +} + +ATF_TC(orphan64); +ATF_TC_HEAD(orphan64, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS64 orphan removal"); + atf_tc_set_md_var(tc, "timeout", "20"); +} + +ATF_TC_BODY(orphan32, tc) +{ + orphan(32); +} + +ATF_TC_BODY(orphan64, tc) +{ + orphan(64); +} + +void orphan(int width) +{ + char s[MAXLINE]; + struct ufs_args args; + struct stat statbuf; + int fd, status; + pid_t childpid; + FILE *fp; + int thisinum, version, found; + ino_t inum; + + setvbuf(stdout, NULL, _IONBF, 0); + + /* + * Initialize. + */ + + /* Create image file */ + create_lfs(FSSIZE, FSSIZE, width, 0); + + /* Prepare to mount */ + memset(&args, 0, sizeof args); + args.fspec = __UNCONST(FAKEBLK); + + if ((childpid = fork()) == 0) { + /* Set up rump */ + rump_init(); + if (rump_sys_mkdir(MP, 0777) == -1) + atf_tc_fail_errno("cannot create mountpoint"); + rump_pub_etfs_register(FAKEBLK, IMGNAME, RUMP_ETFS_BLK); + + /* Mount filesystem */ + fprintf(stderr, "* Mount fs [1]\n"); + if (rump_sys_mount(MOUNT_LFS, MP, 0, &args, sizeof args) == -1) + atf_tc_fail_errno("rump_sys_mount failed"); + + /* Payload */ + fprintf(stderr, "* Initial payload\n"); + fd = write_file(UNCHANGED_CONTROL, FILE_SIZE, 0, 0); + + /* Make the data go to disk */ + rump_sys_sync(); + rump_sys_sync(); + + /* Write the inode number into a temporary file */ + rump_sys_fstat(fd, &statbuf); + fprintf(stderr, "Inode is => %d <=\n", (int)statbuf.st_ino); + + fp = fopen(TMPFILE, "wb"); + fwrite(&statbuf.st_ino, sizeof(ino_t), 1, fp); + fclose(fp); + + /* Delete while still open */ + if (rump_sys_unlink(UNCHANGED_CONTROL) != 0) + atf_tc_fail_errno("rump_sys_unlink failed"); + + /* Sanity check values */ + if (statbuf.st_size != FILE_SIZE) + atf_tc_fail("wrong size in initial stat"); + if (statbuf.st_nlink <= 0) + atf_tc_fail("file already deleted"); + if (statbuf.st_blocks <= 0) + atf_tc_fail("no blocks"); + + /* Make the data go to disk */ + rump_sys_sync(); + rump_sys_sync(); + + /* Simulate a system crash */ + exit(0); + } + + /* Wait for child to terminate */ + waitpid(childpid, &status, 0); + + /* If it died, die ourselves */ + if (WEXITSTATUS(status)) + exit(WEXITSTATUS(status)); + + /* Fsck */ + fprintf(stderr, "* Fsck after crash\n"); + if (fsck()) + atf_tc_fail("fsck found errors after crash"); + + /* Read the inode number from temporary file */ + fp = fopen(TMPFILE, "rb"); + fread(&inum, sizeof(ino_t), 1, fp); + fclose(fp); + + fprintf(stderr, "Seeking inum => %d <=\n", (int)inum); + + /* Set up rump */ + rump_init(); + if (rump_sys_mkdir(MP, 0777) == -1) + atf_tc_fail_errno("cannot create mountpoint"); + rump_pub_etfs_register(FAKEBLK, IMGNAME, RUMP_ETFS_BLK); + + /* Remount */ + fprintf(stderr, "* Mount fs [2]\n"); + if (rump_sys_mount(MOUNT_LFS, MP, 0, &args, sizeof args) == -1) + atf_tc_fail_errno("rump_sys_mount failed[2]"); + + /* At this point the orphan should be deleted. */ + + /* Unmount */ + fprintf(stderr, "* Unmount\n"); + if (rump_sys_unmount(MP, 0) != 0) + atf_tc_fail_errno("rump_sys_unmount failed[1]"); + + /* Check that it was in fact deleted. */ + fprintf(stderr, "* Check for orphaned file\n"); + found = 0; + fp = popen("dumplfs -i -s9 ./" IMGNAME, "r"); + while (fgets(s, MAXLINE, fp) != NULL) { + if (sscanf(s, "%d FREE %d", &thisinum, &version) == 2 + && (ino_t)thisinum == inum) { + found = 1; + break; + } + } + fclose(fp); + if (!found) + atf_tc_fail("orphaned inode not freed on subsequent mount"); + + /* Fsck */ + fprintf(stderr, "* Fsck after final unmount\n"); + if (fsck()) + atf_tc_fail("fsck found errors after final unmount"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, orphan32); + ATF_TP_ADD_TC(tp, orphan64); + return atf_no_error(); +} + diff --git a/fs/lfs/t_resize.c b/fs/lfs/t_resize.c new file mode 100644 index 000000000000..0dae56429261 --- /dev/null +++ b/fs/lfs/t_resize.c @@ -0,0 +1,180 @@ +/* $NetBSD: t_resize.c,v 1.2 2025/10/30 15:30:17 perseant Exp $ */ + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include <ufs/ufs/ufsmount.h> +#include <ufs/lfs/lfs.h> +#include <ufs/lfs/lfs_extern.h> + +#include "h_macros.h" +#include "util.h" + +/* Debugging conditions */ +/* #define FORCE_SUCCESS */ /* Don't actually revert, everything worked */ +/* #define USE_DUMPLFS */ /* Dump the filesystem at certain steps */ + +#define UNCHANGED_CONTROL MP "/3-a-random-file" +#define BIGSIZE 15000 +#define SMALLSIZE 10000 +__CTASSERT(BIGSIZE > SMALLSIZE); + +/* Resize filesystem */ +void resize(int, size_t); + +/* Actually run the test */ +void test(int); + +ATF_TC(resize32); +ATF_TC_HEAD(resize32, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS32 resize_lfs creates an inconsistent filesystem"); + atf_tc_set_md_var(tc, "timeout", "20"); +} + +ATF_TC(resize64); +ATF_TC_HEAD(resize64, tc) +{ + atf_tc_set_md_var(tc, "descr", + "LFS64 resize_lfs creates an inconsistent filesystem"); + atf_tc_set_md_var(tc, "timeout", "20"); +} + +ATF_TC_BODY(resize32, tc) +{ + test(32); +} + +ATF_TC_BODY(resize64, tc) +{ + test(64); +} + +void test(int width) +{ + struct ufs_args args; + int fd; + + setvbuf(stdout, NULL, _IONBF, 0); + + /* + * Initialize. + */ + + /* Create image file larger than filesystem */ + create_lfs(BIGSIZE, SMALLSIZE, width, 1); + + /* Mount filesystem */ + fprintf(stderr, "* Mount fs [1]\n"); + memset(&args, 0, sizeof(args)); + args.fspec = __UNCONST(FAKEBLK); + if (rump_sys_mount(MOUNT_LFS, MP, 0, &args, sizeof(args)) == -1) + atf_tc_fail_errno("rump_sys_mount failed"); + + /* Payload */ + fprintf(stderr, "* Initial payload\n"); + write_file(UNCHANGED_CONTROL, CHUNKSIZE, 1, 0); + + /* Unmount */ + rump_sys_unmount(MP, 0); + if (fsck()) + atf_tc_fail_errno("fsck found errors after first unmount"); + + /* + * Remount and resize. + */ + + /* Reconfigure and mount filesystem again */ + fprintf(stderr, "* Remount fs [2, to enlarge]\n"); + if (rump_sys_mount(MOUNT_LFS, MP, 0, &args, sizeof(args)) == -1) + atf_tc_fail_errno("rump_sys_mount failed [2]"); + + /* Get a handle to the root of the file system */ + fd = rump_sys_open(MP, O_RDONLY); + if (fd < 0) + atf_tc_fail_errno("rump_sys_open mount point root failed"); + + /* Enlarge filesystem */ + fprintf(stderr, "* Resize (enlarge)\n"); + resize(fd, BIGSIZE); + + /* Unmount fs and check */ + rump_sys_close(fd); + rump_sys_unmount(MP, 0); + if (fsck()) + atf_tc_fail_errno("fsck found errors after enlarge"); + + /* Mount filesystem for shrink */ + fprintf(stderr, "* Mount fs [3, to shrink]\n"); + if (rump_sys_mount(MOUNT_LFS, MP, 0, &args, sizeof(args)) == -1) + atf_tc_fail_errno("rump_sys_mount failed [3]"); + + /* Get a handle to the root of the file system */ + fd = rump_sys_open(MP, O_RDONLY); + if (fd < 0) + atf_tc_fail_errno("rump_sys_open mount point root failed"); + + /* Shrink filesystem */ + fprintf(stderr, "* Resize (shrink)\n"); + resize(fd, SMALLSIZE); + + /* Unmount and check again */ + rump_sys_close(fd); + if (rump_sys_unmount(MP, 0) != 0) + atf_tc_fail_errno("rump_sys_umount failed after shrink"); + fprintf(stderr, "* Fsck after shrink\n"); + if (fsck()) + atf_tc_fail("fsck found errors after shrink"); + + /* + * Check file system contents + */ + + /* Mount filesystem one last time */ + fprintf(stderr, "* Mount fs [4, to check contents]\n"); + if (rump_sys_mount(MOUNT_LFS, MP, 0, &args, sizeof(args)) == -1) + atf_tc_fail_errno("rump_sys_mount failed [4]"); + + if (check_file(UNCHANGED_CONTROL, CHUNKSIZE, 0) != 0) + atf_tc_fail("Unchanged control file differs(!)"); + + /* Umount filesystem */ + rump_sys_unmount(MP, 0); + + /* Final fsck to double check */ + fprintf(stderr, "* Fsck after final unmount\n"); + if (fsck()) + atf_tc_fail("fsck found errors after final unmount"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, resize32); + ATF_TP_ADD_TC(tp, resize64); + return atf_no_error(); +} + +void +resize(int fd, size_t size) +{ + int newnseg = (size * DEV_BSIZE) / SEGSIZE; + + if (rump_sys_fcntl(fd, LFCNRESIZE, &newnseg) != 0) + atf_tc_fail_errno("LFCNRESIZE failed"); +} diff --git a/fs/lfs/util.c b/fs/lfs/util.c new file mode 100644 index 000000000000..75ca59983596 --- /dev/null +++ b/fs/lfs/util.c @@ -0,0 +1,181 @@ +/* $NetBSD: util.c,v 1.6 2025/12/19 20:58:08 perseant Exp $ */ + +#include <sys/mount.h> + +#include <ctype.h> +#include <fcntl.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_macros.h" +#include "util.h" + +long long sbaddr[2] = { -1, -1 }; + +/* Create filesystem, note superblock locations */ +void create_lfs(size_t imgsize, size_t fssize, int width, int do_setup) +{ + FILE *pipe; + char cmd[MAXLINE]; + char buf[MAXLINE]; + + /* Create image file larger than filesystem */ + sprintf(cmd, "dd if=/dev/zero of=%s bs=512 count=%zd", + IMGNAME, imgsize); + if (system(cmd) == -1) + atf_tc_fail_errno("create image failed"); + + /* Create filesystem */ + fprintf(stderr, "* Create file system\n"); + sprintf(cmd, "newfs_lfs -D -F -B %d -s %zd -w%d ./%s > %s", + SEGSIZE, fssize, width, IMGNAME, LOGFILE); + if (system(cmd) == -1) + atf_tc_fail_errno("newfs failed"); + pipe = fopen(LOGFILE, "r"); + if (pipe == NULL) + atf_tc_fail_errno("newfs failed to execute"); + while (fgets(buf, MAXLINE, pipe) != NULL) { + if (sscanf(buf, "%lld,%lld", sbaddr, sbaddr + 1) == 2) + break; + } + while (fgets(buf, MAXLINE, pipe) != NULL) + ; + fclose(pipe); + if (sbaddr[0] < 0 || sbaddr[1] < 0) + atf_tc_fail("superblock not found"); + fprintf(stderr, "* Superblocks at %lld and %lld\n", + sbaddr[0], sbaddr[1]); + + if (do_setup) { + /* Set up rump */ + rump_init(); + if (rump_sys_mkdir(MP, 0777) == -1) + atf_tc_fail_errno("cannot create mountpoint"); + rump_pub_etfs_register(FAKEBLK, IMGNAME, RUMP_ETFS_BLK); + } +} + +/* Write some data into a file */ +int write_file(const char *filename, off_t len, int close, unsigned int seed) +{ + int fd; + unsigned i, j; + struct stat statbuf; + int flags = O_CREAT|O_WRONLY; + char buf[1024]; + off_t size; + + srandom(seed); + if (rump_sys_stat(filename, &statbuf) < 0) + size = 0; + else { + size = statbuf.st_size; + flags |= O_APPEND; + + /* Reset randomness */ + for (i = 0; i < size; i++) + random(); + } + + fd = rump_sys_open(filename, flags); + + for (i = 0; i < len; i+= sizeof(buf)) { + for (j = 0; j < sizeof(buf); j++) + buf[j] = ((unsigned)random()) & 0xff; + rump_sys_write(fd, buf, MIN(len - i, (off_t)sizeof(buf))); + } + + if (close) { + rump_sys_close(fd); + fd = -1; + } + + return fd; +} + +/* Check file's existence, size and contents */ +int check_file(const char *filename, int size, unsigned int seed) +{ + int fd, i, j, res; + struct stat statbuf; + unsigned char b, buf[1024]; + + if (rump_sys_stat(filename, &statbuf) < 0) { + fprintf(stderr, "%s: stat failed\n", filename); + return 1; + } + if (size != statbuf.st_size) { + fprintf(stderr, "%s: expected %d bytes, found %d\n", + filename, size, (int)statbuf.st_size); + return 2; + } + + fd = rump_sys_open(filename, O_RDONLY); + + srandom(seed); + for (i = 0; i < size; i += sizeof(buf)) { + res = MIN(size - i, (off_t)sizeof(buf)); + rump_sys_read(fd, buf, res); + for (j = 0; j < res; j++) { + b = (((unsigned)random()) & 0xff); + if (buf[j] != b) { + fprintf(stderr, "%s: byte %d:" + " expected %hhx found %hhx\n", + filename, i + j, + b, buf[j]); + rump_sys_close(fd); + return 3; + } + } + } + rump_sys_close(fd); + fprintf(stderr, "%s: no problem\n", filename); + return 0; +} + +/* Run a file system consistency check */ +int fsck(void) +{ + char s[MAXLINE]; + int i, errors = 0; + FILE *pipe; + char cmd[MAXLINE]; + + for (i = 0; i < 2; i++) { + sprintf(cmd, "fsck_lfs -n -a -b %jd -f " IMGNAME, + (intmax_t)sbaddr[i]); + pipe = popen(cmd, "r"); + while (fgets(s, MAXLINE, pipe) != NULL) { + if (isdigit((int)s[0])) /* "5 files ... " */ + continue; + if (isspace((int)s[0]) || s[0] == '*') + continue; + if (strncmp(s, "Alternate", 9) == 0) + continue; + if (strncmp(s, "ROLL ", 5) == 0) + continue; + fprintf(stderr, "FSCK[sb@%lld]: %s", sbaddr[i], s); + ++errors; + } + pclose(pipe); + if (errors) { + break; + } + } + + return errors; +} + +/* Run dumplfs */ +void dumplfs() +{ + char s[MAXLINE]; + FILE *pipe; + + pipe = popen("dumplfs -S -s 2 -s 1 -s 0 " IMGNAME, "r"); + while (fgets(s, MAXLINE, pipe) != NULL) + fprintf(stderr, "DUMPLFS: %s", s); + pclose(pipe); +} + diff --git a/fs/lfs/util.h b/fs/lfs/util.h new file mode 100644 index 000000000000..b33f89d084ab --- /dev/null +++ b/fs/lfs/util.h @@ -0,0 +1,28 @@ +/* $NetBSD: util.h,v 1.4 2025/10/30 15:30:17 perseant Exp $ */ + +/* Create test image and filesystem, record superblock locations */ +void create_lfs(size_t, size_t, int, int); + +/* Write a well-known byte pattern into a file, appending if it exists */ +int write_file(const char *, off_t, int, unsigned int); + +/* Check the byte pattern and size of the file */ +int check_file(const char *, int, unsigned int); + +/* Check the file system for consistency */ +int fsck(void); + +/* Run dumplfs; for debugging */ +void dumplfs(void); + +#define MAXLINE 132 +#define CHUNKSIZE 300 +#define SEGSIZE 32768 + +#define IMGNAME "disk.img" +#define FAKEBLK "/dev/blk" +#define LOGFILE "newfs.log" + +#define MP "/mp" + +extern long long sbaddr[2]; diff --git a/games/t_morse.sh b/games/t_morse.sh new file mode 100644 index 000000000000..5bec82ebbfc7 --- /dev/null +++ b/games/t_morse.sh @@ -0,0 +1,127 @@ +# $NetBSD: t_morse.sh,v 1.3 2024/10/12 20:44:11 rillig Exp $ +# +# Copyright (c) 2024 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +atf_test_case digits +digits_head() +{ + atf_set 'require.progs' '/usr/games/morse' +} +digits_body() +{ + trailing_space=' ' + morse_s_digits="\ + ----- + .---- + ..--- + ...-- + ....- + ..... + -.... + --... + ---.. + ----. +$trailing_space + ...-.- +" + atf_check -o "inline:$morse_s_digits" \ + /usr/games/morse -s 0123456789 + + morse_digits="\ + daw daw daw daw daw + dit daw daw daw daw + dit dit daw daw daw + dit dit dit daw daw + dit dit dit dit daw + dit dit dit dit dit + daw dit dit dit dit + daw daw dit dit dit + daw daw daw dit dit + daw daw daw daw dit + + dit dit dit daw dit daw +" + atf_check -o "inline:$morse_digits" \ + /usr/games/morse 0123456789 +} + + +# Before 2024-06-16, non-ASCII characters invoked undefined behavior, +# possibly crashing morse. +atf_test_case nonascii +nonascii_head() +{ + atf_set 'require.progs' '/usr/games/morse' +} +nonascii_body() +{ + expected="\ + + dit dit dit daw dit daw +" + atf_check -o "inline:$expected" \ + /usr/games/morse äöü +} + + +atf_test_case roundtrip +roundtrip_head() { + atf_set 'require.progs' '/usr/games/morse' +} +roundtrip_body() +{ + # Most punctuation is ignored during encoding. + # Missing are: !#$%&*;<>[\]^{|}~ + + input=\ +' !"#$%&'\''()*+,-./'\ +'0123456789:;<=>?'\ +'@ABCDEFGHIJKLMNO'\ +'PQRSTUVWXYZ[\]^_'\ +'`abcdefghijklmno'\ +'pqrstuvwxyz{|}~' + + expected=\ +' "'\''()+,-./'\ +'0123456789:=?'\ +'@ABCDEFGHIJKLMNO'\ +'PQRSTUVWXYZ_'\ +'ABCDEFGHIJKLMNO'\ +'PQRSTUVWXYZ \n' + + atf_check -o 'save:roundtrip.morse' \ + /usr/games/morse -s "$input" + atf_check -o "inline:$expected" \ + /usr/games/morse -d < roundtrip.morse +} + + +atf_init_test_cases() +{ + atf_add_test_case digits + atf_add_test_case nonascii + atf_add_test_case roundtrip +} diff --git a/include/t_stddef.c b/include/t_stddef.c new file mode 100644 index 000000000000..b5f2c89b86a4 --- /dev/null +++ b/include/t_stddef.c @@ -0,0 +1,127 @@ +/* $NetBSD: t_stddef.c,v 1.1 2025/04/01 00:33:55 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Include <stddef.h> first to verify it declares everything we need. + */ +#include <stddef.h> + +#if __STDC_VERSION__ - 0 >= 202311L +#if __STDC_VERSION_STDDEF_H__ - 0 < 202311L +#error __STDC_VERSION_STDDEF_H__ not defined appropriately +#endif +#endif + +typedef ptrdiff_t nbtest_ptrdiff_t; +typedef size_t nbtest_size_t; +#if __STDC_VERSION__ - 0 >= 201112L +typedef max_align_t nbtest_max_align_t; +#endif +typedef wchar_t nbtest_wchar_t; +#if __STDC_VERSION__ - 0 >= 202311L +typedef nullptr_t nbtest_nullptr_t; +#endif + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_stddef.c,v 1.1 2025/04/01 00:33:55 riastradh Exp $"); + +#include <atf-c.h> +#include <stdalign.h> + +ATF_TC(macros); +ATF_TC_HEAD(macros, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test <stddef.h> macros work"); +} +ATF_TC_BODY(macros, tc) +{ + void *volatile pNULL = NULL; +#if __STDC_VERSION__ - 0 >= 202311L + void *volatile pnullptr = nullptr; +#endif + struct s { char x[3], y; }; + size_t o; + + ATF_CHECK(!pNULL); +#if __STDC_VERSION__ - 0 >= 202311L + ATF_CHECK(!pnullptr); +#endif + +#if __STDC_VERSION__ - 0 >= 202311L + volatile enum { A, B } x = A; + switch (x) { + case A: + break; + case B: + default: + unreachable(); + } +#endif + + ATF_CHECK_MSG((o = offsetof(struct s, y)) == 3, + "o=%zu", o); +} + +ATF_TC(types); +ATF_TC_HEAD(types, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test <stddef.h> types are reasonable"); +} +ATF_TC_BODY(types, tc) +{ + +#ifdef __GNUC__ + char *p, *q; + ATF_CHECK(__builtin_types_compatible_p(ptrdiff_t, typeof(p - q))); + ATF_CHECK(__builtin_types_compatible_p(size_t, typeof(sizeof(p)))); +#if __STDC_VERSION__ - 0 >= 202311L + ATF_CHECK(__builtin_types_compatible_p(nullptr_t, typeof(nullptr))); +#endif +#endif + +#if __STDC_VERSION__ - 0 >= 201112L + size_t a; + ATF_CHECK_MSG((a = alignof(max_align_t)) >= alignof(long long), + "a=%zu", a); + ATF_CHECK_MSG((a = alignof(max_align_t)) >= alignof(long double), + "a=%zu", a); + ATF_CHECK_MSG((a = alignof(max_align_t)) >= alignof(void *), + "a=%zu", a); + ATF_CHECK_MSG((a = alignof(max_align_t)) >= alignof(int (*)(void)), + "a=%zu", a); +#endif +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, macros); + ATF_TP_ADD_TC(tp, types); + + return atf_no_error(); +} diff --git a/kernel/arch/aarch64/contextspfunc.S b/kernel/arch/aarch64/contextspfunc.S new file mode 100644 index 000000000000..9a4e3059a8e0 --- /dev/null +++ b/kernel/arch/aarch64/contextspfunc.S @@ -0,0 +1,46 @@ +/* $NetBSD: contextspfunc.S,v 1.2 2025/06/08 18:55:35 christos Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.2 2025/06/08 18:55:35 christos Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + mov x0, sp + adrp x1, _C_LABEL(contextsp) + str x0, [x1, :lo12:_C_LABEL(contextsp)] + b _C_LABEL(contextdone) +END(contextspfunc) diff --git a/kernel/arch/aarch64/execregs.c b/kernel/arch/aarch64/execregs.c new file mode 100644 index 000000000000..4c7697fe98c7 --- /dev/null +++ b/kernel/arch/aarch64/execregs.c @@ -0,0 +1,226 @@ +/* $NetBSD: execregs.c,v 1.1 2025/02/27 00:55:31 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: execregs.c,v 1.1 2025/02/27 00:55:31 riastradh Exp $"); + +#include "execregs.h" + +#include <errno.h> +#include <spawn.h> +#include <stddef.h> +#include <unistd.h> + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + x |= x << 32; + return x; +} + +int +execregschild(char *path) +{ + /* x0: used to pass exec arg0, nonnull anyway (path) */ + /* x1: used to pass exec arg1, nonnull anyway (argv) */ + /* x2: used to pass exec arg2, nonnull anyway (environ) */ + register long x3 __asm("x3") = nonnull(3); + register long x4 __asm("x4") = nonnull(4); + register long x5 __asm("x5") = nonnull(5); + register long x6 __asm("x6") = nonnull(6); + register long x7 __asm("x7") = nonnull(7); + register long x8 __asm("x8") = nonnull(8); + register long x9 __asm("x9") = nonnull(9); + register long x10 __asm("x10") = nonnull(10); + register long x11 __asm("x11") = nonnull(11); + register long x12 __asm("x12") = nonnull(12); + register long x13 __asm("x13") = nonnull(13); + register long x14 __asm("x14") = nonnull(14); + register long x15 __asm("x15") = nonnull(15); + register long x16 __asm("x16") = nonnull(16); + register long x17 __asm("x17") = nonnull(17); + register long x18 __asm("x18") = nonnull(18); + register long x19 __asm("x19") = nonnull(19); + register long x20 __asm("x20") = nonnull(20); + register long x21 __asm("x21") = nonnull(21); + register long x22 __asm("x22") = nonnull(22); + register long x23 __asm("x23") = nonnull(23); + register long x24 __asm("x24") = nonnull(24); + register long x25 __asm("x25") = nonnull(25); + register long x26 __asm("x26") = nonnull(26); + register long x27 __asm("x27") = nonnull(27); + register long x28 __asm("x28") = nonnull(28); + /* x29: frame pointer, nonnull anyway */ + /* x30: link register, nonnull anyway */ + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(x3), + "+r"(x4), + "+r"(x5), + "+r"(x6), + "+r"(x7), + "+r"(x8), + "+r"(x9), + "+r"(x10), + "+r"(x11), + "+r"(x12), + "+r"(x13), + "+r"(x14), + "+r"(x15), + "+r"(x16), + "+r"(x17) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(x18), + "+r"(x19), + "+r"(x20), + "+r"(x21), + "+r"(x22), + "+r"(x23), + "+r"(x24), + "+r"(x25), + "+r"(x26), + "+r"(x27), + "+r"(x28) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + /* x0: used to pass posix_spawn arg0, nonnull anyway (&pid) */ + /* x1: used to pass posix_spawn arg1, nonnull anyway (path) */ + /* x2: used to pass posix_spawn arg2, nonnull anyway (&fileacts) */ + /* x3: used to pass posix_spawn arg3, nonnull anyway (&attr) */ + /* x4: used to pass posix_spawn arg3, nonnull anyway (argv) */ + /* x5: used to pass posix_spawn arg3, nonnull anyway (environ) */ + register long x6 __asm("x6") = nonnull(6); + register long x7 __asm("x7") = nonnull(7); + register long x8 __asm("x8") = nonnull(8); + register long x9 __asm("x9") = nonnull(9); + register long x10 __asm("x10") = nonnull(10); + register long x11 __asm("x11") = nonnull(11); + register long x12 __asm("x12") = nonnull(12); + register long x13 __asm("x13") = nonnull(13); + register long x14 __asm("x14") = nonnull(14); + register long x15 __asm("x15") = nonnull(15); + register long x16 __asm("x16") = nonnull(16); + register long x17 __asm("x17") = nonnull(17); + register long x18 __asm("x18") = nonnull(18); + register long x19 __asm("x19") = nonnull(19); + register long x20 __asm("x20") = nonnull(20); + register long x21 __asm("x21") = nonnull(21); + register long x22 __asm("x22") = nonnull(22); + register long x23 __asm("x23") = nonnull(23); + register long x24 __asm("x24") = nonnull(24); + register long x25 __asm("x25") = nonnull(25); + register long x26 __asm("x26") = nonnull(26); + register long x27 __asm("x27") = nonnull(27); + register long x28 __asm("x28") = nonnull(28); + /* x29: frame pointer, nonnull anyway */ + /* x30: link register, nonnull anyway */ + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(x6), + "+r"(x7), + "+r"(x8), + "+r"(x9), + "+r"(x10), + "+r"(x11), + "+r"(x12), + "+r"(x13), + "+r"(x14), + "+r"(x15), + "+r"(x16), + "+r"(x17), + "+r"(x18), + "+r"(x19), + "+r"(x20) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(x21), + "+r"(x22), + "+r"(x23), + "+r"(x24), + "+r"(x25), + "+r"(x26), + "+r"(x27), + "+r"(x28) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff --git a/kernel/arch/aarch64/execregs.h b/kernel/arch/aarch64/execregs.h new file mode 100644 index 000000000000..471a3859c4d1 --- /dev/null +++ b/kernel/arch/aarch64/execregs.h @@ -0,0 +1,86 @@ +/* $NetBSD: execregs.h,v 1.1 2025/02/27 00:55:31 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_AARCH64_EXECREGS_H +#define TESTS_KERNEL_ARCH_AARCH64_EXECREGS_H + +#include <sys/cdefs.h> + +#define NEXECREGS 31 + +#ifndef _LOCORE + +#include <unistd.h> + +/* + * Ordered by struct reg in sys/arch/aarch64/include/reg.h for + * convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + "x0", + "x1", + /* x2: ps_strings */ + "x3", + "x4", + "x5", + "x6", + "x7", + "x8", + "x9", + "x10", + "x11", + "x12", + "x13", + "x14", + "x15", + "x16", + "x17", + "x18", + "x19", + "x20", + "x21", + "x22", + "x23", + "x24", + "x25", + "x26", + "x27", + "x28", + "x29", + "x30", + "tpidr", +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_AARCH64_EXECREGS_H */ diff --git a/kernel/arch/aarch64/execsp.S b/kernel/arch/aarch64/execsp.S new file mode 100644 index 000000000000..52c1472afef6 --- /dev/null +++ b/kernel/arch/aarch64/execsp.S @@ -0,0 +1,99 @@ +/* $NetBSD: execsp.S,v 1.3 2025/06/04 19:25:45 christos Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.3 2025/06/04 19:25:45 christos Exp $") + +/* + * void execsp_start(void (*cleanup@x0)(void), void *obj_main@x1, + * struct ps_strings *ps_strings@x2) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) + mov x16, sp + adrp x17, _C_LABEL(startsp) + str x16, [x17, :lo12:_C_LABEL(startsp)] + b _C_LABEL(__start) +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + mov x16, sp + adrp x17, _C_LABEL(ctorsp) + str x16, [x17, :lo12:_C_LABEL(ctorsp)] + ret +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .init_array,"aw",%init_array + .p2align 3 + .xword _C_LABEL(execsp_ctor) + +/* + * int main(int argc@x0, char **argv@x1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + mov x16, sp + adrp x17, _C_LABEL(mainsp) + str x16, [x17, :lo12:_C_LABEL(mainsp)] + mov x0, #0 + ret +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + mov x16, sp + adrp x17, _C_LABEL(dtorsp) + str x16, [x17, :lo12:_C_LABEL(dtorsp)] + b _C_LABEL(execsp_main) +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .fini_array,"aw",%fini_array + .p2align 3 + .xword _C_LABEL(execsp_dtor) diff --git a/kernel/arch/aarch64/h_execregs.S b/kernel/arch/aarch64/h_execregs.S new file mode 100644 index 000000000000..f060911067f4 --- /dev/null +++ b/kernel/arch/aarch64/h_execregs.S @@ -0,0 +1,84 @@ +/* $NetBSD: h_execregs.S,v 1.2 2025/04/25 12:58:40 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <sys/syscall.h> + +#include <machine/asm.h> + +#include "execregs.h" + +ENTRY(execregs_start) + /* create a stack frame with NEXECREGS*8 bytes, aligned to 16-byte */ + stp fp, lr, [sp, #-(16 + ((NEXECREGS*8 + 15)/16)*16)]! + + /* store registers to buffer on stack */ + stp x0, x1, [sp, #16] /* order matches execregs.h */ + /* x2: ps_strings */ + stp x3, x4, [sp, #(16 + 1*2*8)] + stp x5, x6, [sp, #(16 + 2*2*8)] + stp x7, x8, [sp, #(16 + 3*2*8)] + stp x9, x10, [sp, #(16 + 4*2*8)] + stp x11, x12, [sp, #(16 + 5*2*8)] + stp x13, x14, [sp, #(16 + 6*2*8)] + stp x15, x16, [sp, #(16 + 7*2*8)] + stp x17, x18, [sp, #(16 + 8*2*8)] + stp x19, x20, [sp, #(16 + 9*2*8)] + stp x21, x22, [sp, #(16 + 10*2*8)] + stp x23, x24, [sp, #(16 + 11*2*8)] + stp x25, x26, [sp, #(16 + 12*2*8)] + stp x27, x28, [sp, #(16 + 13*2*8)] + stp x29, x30, [sp, #(16 + 14*2*8)] + mrs x0, tpidr_el0 + str x0, [sp, #(16 + 15*2*8)] + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + mov x0, #1 /* arg0 := STDOUT_FILENO */ + add x1, sp, #16 /* arg1 := regs */ + mov x2, #(NEXECREGS*8) /* arg2 := sizeof(regs) */ + svc #SYS_write + + b.cs 2f /* bail if write failed */ + cmp x0, #(NEXECREGS*8) /* bail if wrote wrong # of bytes */ + b.ne 2f + + /* call exit(0) */ + mov x0, #0 /* arg0 := 0 */ +1: svc #SYS_exit + brk #0xffff /* paranoia */ + +2: /* call exit(127) */ + mov x0, #127 /* arg0 := 127 */ + b 1b +END(execregs_start) + +/* main stub to simplify linking */ +ENTRY(main) + brk #0xffff +END(main) diff --git a/kernel/arch/aarch64/signalsphandler.S b/kernel/arch/aarch64/signalsphandler.S new file mode 100644 index 000000000000..246ed383273d --- /dev/null +++ b/kernel/arch/aarch64/signalsphandler.S @@ -0,0 +1,46 @@ +/* $NetBSD: signalsphandler.S,v 1.2 2025/06/08 18:55:35 christos Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.2 2025/06/08 18:55:35 christos Exp $") + +/* + * signalsphandler(signo@x0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + mov x0, sp + adrp x1, _C_LABEL(signalsp) + str x0, [x1, :lo12:_C_LABEL(signalsp)] + ret +END(signalsphandler) diff --git a/kernel/arch/aarch64/stack_pointer.h b/kernel/arch/aarch64/stack_pointer.h new file mode 100644 index 000000000000..3bd7e6f65335 --- /dev/null +++ b/kernel/arch/aarch64/stack_pointer.h @@ -0,0 +1,42 @@ +/* $NetBSD: stack_pointer.h,v 1.2 2025/04/20 22:31:00 riastradh Exp $ */ + +/* + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_AARCH64_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_AARCH64_STACK_POINTER_H + +#define MISALIGN_SP \ + __asm__ volatile ( \ + "sub sp, sp, #8" \ + ) + +#define FIX_SP \ + __asm__ volatile ( \ + "add sp, sp, #8" \ + ) + +#endif /* TESTS_KERNEL_ARCH_AARCH64_STACK_POINTER_H */ diff --git a/kernel/arch/aarch64/threadspfunc.S b/kernel/arch/aarch64/threadspfunc.S new file mode 100644 index 000000000000..90f779d5e961 --- /dev/null +++ b/kernel/arch/aarch64/threadspfunc.S @@ -0,0 +1,43 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@x0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + mov x0, sp + ret +END(threadspfunc) diff --git a/kernel/arch/alpha/contextspfunc.S b/kernel/arch/alpha/contextspfunc.S new file mode 100644 index 000000000000..da198f089124 --- /dev/null +++ b/kernel/arch/alpha/contextspfunc.S @@ -0,0 +1,50 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + + .set noat + .text + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +LEAF(contextspfunc, 1) + LDGP(pv) + ldq at_reg, contextsp(gp) !literal + stq sp, 0(at_reg) + ldq pv, contextdone(gp) !literal + jmp (pv), contextdone +END(contextspfunc) diff --git a/kernel/arch/alpha/execsp.S b/kernel/arch/alpha/execsp.S new file mode 100644 index 000000000000..08eaa521fa03 --- /dev/null +++ b/kernel/arch/alpha/execsp.S @@ -0,0 +1,106 @@ +/* $NetBSD: execsp.S,v 1.2 2025/04/21 02:31:22 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.2 2025/04/21 02:31:22 riastradh Exp $") + + .set noat + .text + +/* + * void execsp_start(void *stackpointer@a0, void (*cleanup@a1)(void), + * void *obj_main@a2, struct ps_strings *ps_strings@a3) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +LEAF(execsp_start, 4) + LDGP(pv) + ldq at_reg, startsp(gp) !literal + stq sp, 0(at_reg) + ldq pv, __start(gp) !literal + jmp (pv), __start +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +LEAF(execsp_ctor, 0) + LDGP(pv) + ldq at_reg, ctorsp(gp) !literal + stq sp, 0(at_reg) + RET +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .pushsection .ctors,"aw",@progbits + .p2align 3 + .quad execsp_ctor + .popsection + +/* + * int main(int argc@a0, char **argv@a1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +LEAF(main, 2) + LDGP(pv) + ldq at_reg, mainsp(gp) !literal + stq sp, 0(at_reg) + mov zero, v0 + RET +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +LEAF(execsp_dtor, 0) + LDGP(pv) + ldq at_reg, dtorsp(gp) !literal + stq sp, 0(at_reg) + ldq pv, execsp_main(gp) !literal + jmp (pv), execsp_main +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .pushsection .dtors,"aw",@progbits + .p2align 3 + .quad execsp_dtor + .popsection diff --git a/kernel/arch/alpha/signalsphandler.S b/kernel/arch/alpha/signalsphandler.S new file mode 100644 index 000000000000..eaa3f2cdb654 --- /dev/null +++ b/kernel/arch/alpha/signalsphandler.S @@ -0,0 +1,49 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:31:57 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:31:57 riastradh Exp $") + + .set noat + .text + +/* + * signalsphandler(signo@a0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +LEAF(signalsphandler, 1) + LDGP(pv) + ldq at_reg, signalsp(gp) !literal + stq sp, 0(at_reg) + RET +END(signalsphandler) diff --git a/kernel/arch/alpha/stack_pointer.h b/kernel/arch/alpha/stack_pointer.h new file mode 100644 index 000000000000..58c581ffde0a --- /dev/null +++ b/kernel/arch/alpha/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:31:57 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_ALPHA_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_ALPHA_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("lda $sp,-1($sp)" ::: "memory") +#define FIX_SP __asm __volatile("lda $sp,1($sp)" ::: "memory") + +#endif /* TESTS_KERNEL_ARCH_ALPHA_STACK_POINTER_H */ diff --git a/kernel/arch/alpha/threadspfunc.S b/kernel/arch/alpha/threadspfunc.S new file mode 100644 index 000000000000..413387bb0867 --- /dev/null +++ b/kernel/arch/alpha/threadspfunc.S @@ -0,0 +1,46 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + + .set noat + .text + +/* + * void *threadspfunc(void *cookie@a0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +LEAF(threadspfunc, 1) + mov sp, v0 + RET +END(threadspfunc) diff --git a/kernel/arch/arm/contextspfunc.S b/kernel/arch/arm/contextspfunc.S new file mode 100644 index 000000000000..cf7fec19fb2a --- /dev/null +++ b/kernel/arch/arm/contextspfunc.S @@ -0,0 +1,51 @@ +/* $NetBSD: contextspfunc.S,v 1.2 2025/05/07 16:26:47 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.2 2025/05/07 16:26:47 uwe Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) +0: GOT_INIT(r0, .Lgot) + mov r1, sp + GOT_GET(r2, r0, .Lcontextsp) + str r1, [r2] + b PLT_SYM(_C_LABEL(contextdone)) + + GOT_INITSYM(.Lgot, 0b) +.Lcontextsp: + .word GOT_SYM(contextsp) +END(contextspfunc) diff --git a/kernel/arch/arm/execsp.S b/kernel/arch/arm/execsp.S new file mode 100644 index 000000000000..b02587ef2b33 --- /dev/null +++ b/kernel/arch/arm/execsp.S @@ -0,0 +1,119 @@ +/* $NetBSD: execsp.S,v 1.4 2025/05/07 16:26:47 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.4 2025/05/07 16:26:47 uwe Exp $") + +/* + * void execsp_start(struct ps_strings *ps_strings@r0, void *obj_main@r1, + * void (*cleanup@r2)(void)) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) +0: GOT_INIT(r3, .Lgot.execsp_start) + mov r4, sp + GOT_GET(r5, r3, .Lstartsp) + str r4, [r5] + b PLT_SYM(_C_LABEL(__start)) + + GOT_INITSYM(.Lgot.execsp_start, 0b) +.Lstartsp: + .word GOT_SYM(startsp) +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) +0: GOT_INIT(r0, .Lgot.execsp_ctor) + mov r1, sp + GOT_GET(r2, r0, .Lctorsp) + str r1, [r2] + RET + + GOT_INITSYM(.Lgot.execsp_ctor, 0b) +.Lctorsp: + .word GOT_SYM(ctorsp) +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .init_array,"aw",%init_array + .p2align 2 + .word _C_LABEL(execsp_ctor) + +/* + * int main(int argc@r0, char **argv@r1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) +0: GOT_INIT(r0, .Lgot.main) + mov r1, sp + GOT_GET(r2, r0, .Lmainsp) + str r1, [r2] + mov r0, #0 + RET + + GOT_INITSYM(.Lgot.main, 0b) +.Lmainsp: + .word GOT_SYM(mainsp) +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) +0: GOT_INIT(r0, .Lgot.execsp_dtor) + mov r1, sp + GOT_GET(r2, r0, .Ldtorsp) + str r1, [r2] + b PLT_SYM(_C_LABEL(execsp_main)) + + GOT_INITSYM(.Lgot.execsp_dtor, 0b) +.Ldtorsp: + .word GOT_SYM(dtorsp) +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .fini_array,"aw",%fini_array + .p2align 2 + .word _C_LABEL(execsp_dtor) diff --git a/kernel/arch/arm/signalsphandler.S b/kernel/arch/arm/signalsphandler.S new file mode 100644 index 000000000000..21b7d26a53b9 --- /dev/null +++ b/kernel/arch/arm/signalsphandler.S @@ -0,0 +1,51 @@ +/* $NetBSD: signalsphandler.S,v 1.3 2025/05/07 16:26:47 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.3 2025/05/07 16:26:47 uwe Exp $") + +/* + * signalsphandler(signo@r0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) +0: GOT_INIT(r0, .Lgot) + mov r1, sp + GOT_GET(r2, r0, .Lsignalsp) + str r1, [r2] + RET + + GOT_INITSYM(.Lgot, 0b) +.Lsignalsp: + .word GOT_SYM(signalsp) +END(signalsphandler) diff --git a/kernel/arch/arm/stack_pointer.h b/kernel/arch/arm/stack_pointer.h new file mode 100644 index 000000000000..73d10c341138 --- /dev/null +++ b/kernel/arch/arm/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/25 02:24:01 riastradh Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_ARM_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_ARM_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("sub sp, sp, #1") +#define FIX_SP __asm __volatile("add sp, sp, #1") + +#endif /* TESTS_KERNEL_ARCH_ARM_STACK_POINTER_H */ diff --git a/kernel/arch/arm/threadspfunc.S b/kernel/arch/arm/threadspfunc.S new file mode 100644 index 000000000000..5f34c547cadf --- /dev/null +++ b/kernel/arch/arm/threadspfunc.S @@ -0,0 +1,43 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/25 02:24:01 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/25 02:24:01 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@r0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + mov r0, sp + RET +END(threadspfunc) diff --git a/kernel/arch/hppa/contextspfunc.S b/kernel/arch/hppa/contextspfunc.S new file mode 100644 index 000000000000..683f59808c95 --- /dev/null +++ b/kernel/arch/hppa/contextspfunc.S @@ -0,0 +1,48 @@ +/* $NetBSD: contextspfunc.S,v 1.2 2025/04/21 12:06:08 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.2 2025/04/21 12:06:08 riastradh Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +LEAF_ENTRY(contextspfunc) + addil LT%_C_LABEL(contextdone), %r19 /* r20 := contextdone */ + ldw RT%_C_LABEL(contextdone)(%r1), %r20 + addil LT%_C_LABEL(contextsp), %r19 /* r21 := &contextsp */ + ldw RT%_C_LABEL(contextsp)(%r1), %r21 + bv %r0(%r20) /* jump to contextdone */ + stw %sp, 0(%r21) /* contextsp := sp */ +EXIT(contextspfunc) diff --git a/kernel/arch/hppa/execregs.c b/kernel/arch/hppa/execregs.c new file mode 100644 index 000000000000..c064d3a36e37 --- /dev/null +++ b/kernel/arch/hppa/execregs.c @@ -0,0 +1,387 @@ +/* $NetBSD: execregs.c,v 1.2 2025/02/28 16:08:19 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: execregs.c,v 1.2 2025/02/28 16:08:19 riastradh Exp $"); + +#include "execregs.h" + +#include <errno.h> +#include <spawn.h> +#include <stddef.h> +#include <stdint.h> +#include <unistd.h> + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + return x; +} + +/* + * setfpregs() + * + * Set up all the floating-point registers with something nonzero + * in each one. We initialize the floating-point status register + * to set various bits so it's not all zero, but nothing that + * would trigger traps. + */ +static void +setfpregs(void) +{ + static const uint64_t fpe[] = { + (__BITS(63,59) /* all exception flags (VZOUI) set */ + | __BIT(58) /* C bit (comparison) set */ + | __BITS(54,43) /* CQ (comparison queue) all set */ + | __SHIFTIN(1, __BITS(42,41)) /* round toward zero */ + | __SHIFTIN(0, __BIT(38)) /* no delayed trap */ + | __SHIFTIN(1, __BIT(37)) /* Denormalized As Zero */ + | __SHIFTIN(0, __BITS(36,32)) /* exceptions masked */ + | 0x10101010), + 0x9191919111111111, + 0x9292929212121212, + 0x9393939313131313, + }; + const uint64_t *fpep = fpe; + + static const double fr[28] = { + 0x1.04p0, 0x1.05p0, 0x1.06p0, 0x1.07p0, + 0x1.08p0, 0x1.09p0, 0x1.0ap0, 0x1.0bp0, + 0x1.0cp0, 0x1.0dp0, 0x1.0ep0, 0x1.0fp0, + 0x1.10p0, 0x1.11p0, 0x1.12p0, 0x1.13p0, + 0x1.14p0, 0x1.15p0, 0x1.16p0, 0x1.17p0, + 0x1.18p0, 0x1.19p0, 0x1.1ap0, 0x1.1bp0, + 0x1.1cp0, 0x1.1dp0, 0x1.1ep0, 0x1.1fp0, + }; + const double *frp = fr; + + __asm volatile( + "fldds,ma 8(%0), %%fr0\n\t" + "fldds,ma 8(%0), %%fr1\n\t" + "fldds,ma 8(%0), %%fr2\n\t" + "fldds 0(%0), %%fr3" + : "+r"(fpep) + : "m"(fpe)); + + __asm volatile( + "fldds,ma 8(%0), %%fr4\n\t" + "fldds,ma 8(%0), %%fr5\n\t" + "fldds,ma 8(%0), %%fr6\n\t" + "fldds,ma 8(%0), %%fr7\n\t" + "fldds,ma 8(%0), %%fr8\n\t" + "fldds,ma 8(%0), %%fr9\n\t" + "fldds,ma 8(%0), %%fr10\n\t" + "fldds,ma 8(%0), %%fr11\n\t" + "fldds,ma 8(%0), %%fr12\n\t" + "fldds,ma 8(%0), %%fr13\n\t" + "fldds,ma 8(%0), %%fr14\n\t" + "fldds,ma 8(%0), %%fr15\n\t" + "fldds,ma 8(%0), %%fr16\n\t" + "fldds,ma 8(%0), %%fr17\n\t" + "fldds,ma 8(%0), %%fr18\n\t" + "fldds,ma 8(%0), %%fr19\n\t" + "fldds,ma 8(%0), %%fr20\n\t" + "fldds,ma 8(%0), %%fr21\n\t" + "fldds,ma 8(%0), %%fr22\n\t" + "fldds,ma 8(%0), %%fr23\n\t" + "fldds,ma 8(%0), %%fr24\n\t" + "fldds,ma 8(%0), %%fr25\n\t" + "fldds,ma 8(%0), %%fr26\n\t" + "fldds,ma 8(%0), %%fr27\n\t" + "fldds,ma 8(%0), %%fr28\n\t" + "fldds,ma 8(%0), %%fr29\n\t" + "fldds,ma 8(%0), %%fr30\n\t" + "fldds 0(%0), %%fr31" + : "+r"(frp) + : "m"(fr)); +} + +/* + * setpsw() + * + * Set some bits in PSW, the processor status word. + */ +static void +setpsw(void) +{ + uint32_t x = 0xe0000000, y = 0xffffffff, sum; + + /* + * Trigger some arithmetic that causes the carry/borrow + * (PSW[C/B]) bits to be set. + * + * XXX Also set PSW[V]. + */ + __asm volatile("sh3add %[sum], %[x], %[y]" + : /* outputs */ [sum] "=r"(sum) + : /* inputs */ [x] "r"(x), [y] "r"(y)); +} + +int +execregschild(char *path) +{ + register long t1 __asm("r22") = nonnull(22); + register long t2 __asm("r21") = nonnull(21); + /* r30/sp: stack pointer */ + register long t3 __asm("r20") = nonnull(20); + /* cr17/iisq_head: privileged */ + /* cr17/iisq_tail: privileged */ + /* cr18/iioq_head: privileged */ + /* cr18/iioq_tail: privileged */ + /* cr15/eiem: privileged */ + /* cr22/ipsw: privileged */ + /* sr3: privileged(?) */ + /* cr8/pidr1: privileged */ + /* cr20/isr: privileged */ + /* cr21/ior: privileged */ + /* cr19/iir: privileged */ + /* flags: N/A(?) */ + long sar = nonnull(0x8a); /* cr11 */ + /* r1: ADDIL (add immediate left) result, nonnull anyway */ + /* r2/rp: return pointer, nonnull anyway */ + /* r3: frame pointer, nonnull anyway */ + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + register long r16 __asm("r16") = nonnull(16); + register long r17 __asm("r17") = nonnull(17); + register long r18 __asm("r18") = nonnull(18); + register long t4 __asm("r19") = nonnull(19); + register long arg3 __asm("r23") = nonnull(23); + /* r24/arg2: envp, nonnull anyway */ + /* r25/arg1: argv, nonnull anyway */ + /* r26/arg0: path, nonnull anyway */ + /* r27/dp: data pointer, nonnull anyway */ + register long ret0 __asm("r28") = nonnull(28); + register long ret1 __asm("r29") = nonnull(29); + register long r31 __asm("r31") = nonnull(31); + /* sr0-sr7: space registers initialized by kernel */ + /* cr9/pidr2: privileged */ + /* cr12/pidr3: privileged */ + /* cr13/pidr4: privileged */ + /* cr0/rctr: privileged */ + /* cr10/ccr: privileged */ + /* cr23/eirr: privileged */ + /* cr24: privileged */ + /* cr25/vtop: privileged */ + /* cr27/tr3: _lwp_private, thread-local storage -- nonnull anyway */ + /* cr28: privileged */ + /* cr30/fpregs: privileged */ + /* cr31: privileged */ + + char *argv[] = {path, NULL}; + char **envp = environ; + + setfpregs(); + setpsw(); + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("mtctl %[sar], %%sar" /* cr11 */ + : /* outputs */ + : [sar] "r"(sar) + : "memory"); + __asm volatile("" : + "+r"(t1), + "+r"(t2), + "+r"(t3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11), + "+r"(r12) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(r16), + "+r"(r17), + "+r"(r18), + "+r"(t4), + "+r"(arg3), + "+r"(ret0), + "+r"(ret1), + "+r"(r31) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + register long t1 __asm("r22") = nonnull(22); + register long t2 __asm("r21") = nonnull(21); + /* r30/sp: stack pointer */ + register long t3 __asm("r20") = nonnull(20); + /* cr17/iisq_head: privileged */ + /* cr17/iisq_tail: privileged */ + /* cr18/iioq_head: privileged */ + /* cr18/iioq_tail: privileged */ + /* cr15/eiem: privileged */ + /* cr22/ipsw: privileged */ + /* sr3: privileged(?) */ + /* cr8/pidr1: privileged */ + /* cr20/isr: privileged */ + /* cr21/ior: privileged */ + /* cr19/iir: privileged */ + /* flags: N/A(?) */ + long sar = nonnull(0x8a); /* cr11 */ + /* r1: ADDIL (add immediate left) result, nonnull anyway */ + /* r2/rp: return pointer, nonnull anyway */ + /* r3: frame pointer, nonnull anyway */ + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + register long r16 __asm("r16") = nonnull(16); + register long r17 __asm("r17") = nonnull(17); + register long r18 __asm("r18") = nonnull(18); + register long t4 __asm("r19") = nonnull(19); + /* r23/arg3: attrp, nonnull anyway */ + /* r24/arg2: fileactsp, nonnull anyway */ + /* r25/arg1: path, nonnull anyway */ + /* r26/arg0: pidp, nonnull anyway */ + /* r27/dp: data pointer, nonnull anyway */ + register long ret0 __asm("r28") = nonnull(28); + register long ret1 __asm("r29") = nonnull(29); + register long r31 __asm("r31") = nonnull(31); + /* sr0-sr7: space registers initialized by kernel */ + /* cr9/pidr2: privileged */ + /* cr12/pidr3: privileged */ + /* cr13/pidr4: privileged */ + /* cr0/rctr: privileged */ + /* cr10/ccr: privileged */ + /* cr23/eirr: privileged */ + /* cr24: privileged */ + /* cr25/vtop: privileged */ + /* cr27/tr3: _lwp_private, thread-local storage -- nonnull anyway */ + /* cr28: privileged */ + /* cr30/fpregs: privileged */ + /* cr31: privileged */ + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + setfpregs(); + setpsw(); + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("mtctl %[sar], %%sar" /* cr11 */ + : /* outputs */ + : [sar] "r"(sar) + : "memory"); + __asm volatile("" : + "+r"(t1), + "+r"(t2), + "+r"(t3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11), + "+r"(r12) + :: "memory"); + /* pacify gcc error: more than 30 operands in 'asm' */ + __asm volatile("" : + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(r16), + "+r"(r17), + "+r"(r18), + "+r"(t4), + "+r"(ret0), + "+r"(ret1), + "+r"(r31) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff --git a/kernel/arch/hppa/execregs.h b/kernel/arch/hppa/execregs.h new file mode 100644 index 000000000000..ae4dbb2e39c0 --- /dev/null +++ b/kernel/arch/hppa/execregs.h @@ -0,0 +1,157 @@ +/* $NetBSD: execregs.h,v 1.2 2025/02/28 16:08:19 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_HPPA_EXECREGS_H +#define TESTS_KERNEL_ARCH_HPPA_EXECREGS_H + +#include <sys/cdefs.h> + +#define NEXECREGS 96 + +#ifndef _LOCORE + +#include <unistd.h> + +/* + * Ordered by struct struct trapframe in sys/arch/hppa/include/frame.h + * for convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + "t1", + "t2", + /* sp: stack pointer */ + "t3", + /* various privileged stuff */ + "sar", + "r1", + "rp", + /* r3: frame pointer (set to initial stack pointer) */ + "r4", + "r5", + "r6", + "r70", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", + "r16", + "r17", + "r18", + "t4", + "arg3", + "arg2", + "arg1", + /* arg0: ps_strings */ + "dp", + "ret0", + "ret1", + "r31", + "cr27", + "cr28", + + "psw", /* user-visible PSW bits: C/B and V */ + + /* Floating-point registers */ + "fr0l", + "fr0r", + "fr1l", + "fr1r", + "fr2l", + "fr2r", + "fr3l", + "fr3r", + "fr4l", + "fr4r", + "fr5l", + "fr5r", + "fr6l", + "fr6r", + "fr7l", + "fr7r", + "fr8l", + "fr8r", + "fr9l", + "fr9r", + "fr10l", + "fr10r", + "fr11l", + "fr11r", + "fr12l", + "fr12r", + "fr13l", + "fr13r", + "fr14l", + "fr14r", + "fr15l", + "fr15r", + "fr16l", + "fr16r", + "fr17l", + "fr17r", + "fr18l", + "fr18r", + "fr19l", + "fr19r", + "fr20l", + "fr20r", + "fr21l", + "fr21r", + "fr22l", + "fr22r", + "fr23l", + "fr23r", + "fr24l", + "fr24r", + "fr25l", + "fr25r", + "fr26l", + "fr26r", + "fr27l", + "fr27r", + "fr28l", + "fr28r", + "fr29l", + "fr29r", + "fr30l", + "fr30r", + "fr31l", + "fr31r", +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_HPPA_EXECREGS_H */ diff --git a/kernel/arch/hppa/execsp.S b/kernel/arch/hppa/execsp.S new file mode 100644 index 000000000000..520421a1f1fc --- /dev/null +++ b/kernel/arch/hppa/execsp.S @@ -0,0 +1,130 @@ +/* $NetBSD: execsp.S,v 1.1 2025/04/20 22:32:49 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.1 2025/04/20 22:32:49 riastradh Exp $") + + .import _GLOBAL_OFFSET_TABLE_ + +/* + * void execsp_start(struct ps_strings *ps_strings@arg0, + * void (*cleanup@arg1)(void), void *obj_main@arg2) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +LEAF_ENTRY(execsp_start) + /* + * Set up the data pointer (r19) and linkage table register + * (r27) like the real startup routine so we can get at the + * global symbols startsp and __start. + * + * XXX Not really sure why we need to set up r27, since we only + * use r19 here and the real startup routine, __start, will set + * up both r19 and r27 anyway. But this crashes with SIGSEGV + * shortly after startup if we don't set up r27, and gdb + * crashes on my attempts to single-step, so I'll just leave + * the initialization of r27 here for now until someone is + * motivated by the potential for a single-instruction + * micro-optimization in this test program to find out why r27 + * is needed too. + */ + bl L$lpc, %r27 + depi 0, 31, 2, %r27 +L$lpc: addil L'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 8), %r27 + ldo R'_GLOBAL_OFFSET_TABLE_ - ($PIC_pcrel$0 - 12)(%r1), %r27 + copy %r27, %r19 + + addil LT%_C_LABEL(startsp), %r19 /* r20 := &startsp */ + ldw RT%_C_LABEL(startsp)(%r1), %r20 + + /* PIC_TAILCALL(__start), if we had it */ + addil LT%_C_LABEL(__start), %r19 /* r1 := __start */ + ldw RT%_C_LABEL(__start)(%r1), %r1 + bv %r0(%r1) /* jump to __start */ + stw %sp, 0(%r20) /* startsp := sp */ +EXIT(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +LEAF_ENTRY(execsp_ctor) + addil LT%_C_LABEL(ctorsp), %r19 /* r1 := &ctorsp */ + ldw RT%_C_LABEL(ctorsp)(%r1), %r1 + bv %r0(%rp) /* return */ + stw %sp, 0(%r1) /* ctorsp := sp */ +EXIT(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .ctors,"aw",@progbits + .p2align 2 + .word _C_LABEL(execsp_ctor) + +/* + * int main(int argc@arg0, char **argv@arg1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +LEAF_ENTRY(main) + addil LT%_C_LABEL(mainsp), %r19 /* r1 := &mainsp */ + ldw RT%_C_LABEL(mainsp)(%r1), %r1 + stw %sp, 0(%r1) /* ctorsp := sp */ + bv %r0(%rp) /* return... */ + copy %r0, %ret0 /* ...zero */ +EXIT(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +LEAF_ENTRY(execsp_dtor) + addil LT%_C_LABEL(dtorsp), %r19 /* r20 := &dtorsp */ + ldw RT%_C_LABEL(dtorsp)(%r1), %r20 + + /* PIC_TAILCALL(__start), if we had it */ + addil LT%_C_LABEL(execsp_main), %r19 /* r1 := execsp_main */ + ldw RT%_C_LABEL(execsp_main)(%r1), %r1 + bv %r0(%r1) /* jump to execsp_main */ + stw %sp, 0(%r20) /* startsp := sp */ +EXIT(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .dtors,"aw",@progbits + .p2align 2 + .word _C_LABEL(execsp_dtor) diff --git a/kernel/arch/hppa/h_execregs.S b/kernel/arch/hppa/h_execregs.S new file mode 100644 index 000000000000..ad7a50a5b932 --- /dev/null +++ b/kernel/arch/hppa/h_execregs.S @@ -0,0 +1,168 @@ +/* $NetBSD: h_execregs.S,v 1.2 2025/02/28 16:08:19 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <sys/syscall.h> + +#include <machine/asm.h> +#include <machine/vmparam.h> + +#include "execregs.h" + +_ENTRY(execregs_start) + .callinfo frame=(NEXECREGS*4), calls + .entry + + ldo (NEXECREGS*4)(%sp), %sp /* space for NEXECREGS */ + stw %t1, (4*(0 - NEXECREGS))(%sp) /* order matches execregs.h */ + stw %t2, (4*(1 - NEXECREGS))(%sp) + /* sp: stack pointer */ + stw %t3, (4*(2 - NEXECREGS))(%sp) + /* cr17/iisq_head: privileged */ + /* cr17/iisq_tail: privileged */ + /* cr18/iioq_head: privileged */ + /* cr18/iioq_tail: privileged */ + /* cr15/eiem: privileged */ + /* cr22/ipsw: privileged */ + /* sr3: privileged(?) */ + /* cr8/pidr1: privileged */ + /* cr20/isr: privileged */ + /* cr21/ior: privileged */ + /* cr19/iir: privileged */ + /* flags: N/A(?) */ + stw %sar, (4*(3 - NEXECREGS))(%sp) + stw %r1, (4*(4 - NEXECREGS))(%sp) + stw %rp, (4*(5 - NEXECREGS))(%sp) + /* r3: frame pointer (set to initial stack pointer) */ + stw %r4, (4*(6 - NEXECREGS))(%sp) + stw %r5, (4*(7 - NEXECREGS))(%sp) + stw %r6, (4*(8 - NEXECREGS))(%sp) + stw %r7, (4*(9 - NEXECREGS))(%sp) + stw %r8, (4*(10 - NEXECREGS))(%sp) + stw %r9, (4*(11 - NEXECREGS))(%sp) + stw %r10, (4*(12 - NEXECREGS))(%sp) + stw %r11, (4*(13 - NEXECREGS))(%sp) + stw %r12, (4*(14 - NEXECREGS))(%sp) + stw %r13, (4*(15 - NEXECREGS))(%sp) + stw %r14, (4*(16 - NEXECREGS))(%sp) + stw %r15, (4*(17 - NEXECREGS))(%sp) + stw %r16, (4*(18 - NEXECREGS))(%sp) + stw %r17, (4*(19 - NEXECREGS))(%sp) + stw %r18, (4*(20 - NEXECREGS))(%sp) + stw %t4, (4*(21 - NEXECREGS))(%sp) + stw %arg3, (4*(22 - NEXECREGS))(%sp) + stw %arg2, (4*(23 - NEXECREGS))(%sp) + stw %arg1, (4*(24 - NEXECREGS))(%sp) + /* arg0: ps_strings */ + stw %dp, (4*(25 - NEXECREGS))(%sp) + stw %ret0, (4*(26 - NEXECREGS))(%sp) + stw %ret1, (4*(27 - NEXECREGS))(%sp) + stw %r31, (4*(28 - NEXECREGS))(%sp) + /* sr0-sr7: space registers initialized by kernel */ + /* cr9/pidr2: privileged */ + /* cr12/pidr3: privileged */ + /* cr13/pidr4: privileged */ + /* cr0/rctr: privileged */ + /* cr10/ccr: privileged */ + /* cr23/eirr: privileged */ + /* cr24: privileged */ + /* cr25/vtop: privileged */ + /* cr26: ??? */ + stw %cr27, (4*(29 - NEXECREGS))(%sp) + stw %cr28, (4*(30 - NEXECREGS))(%sp) + /* cr30/fpregs: privileged */ + /* cr31: privileged */ + + addc %t1, %r0, %r0 /* t1 := PSW[C/B]{0} */ + zdep %t1, 23, 8, %t1 /* t1 := PSW */ + stw %t1, (4*(31 - NEXECREGS))(%sp) + + /* store the fp registers */ + ldo (4*(32 - NEXECREGS))(%sp), %t1 + fstd,ma %fr0, 8(%t1) + fstd,ma %fr1, 8(%t1) + fstd,ma %fr2, 8(%t1) + fstd,ma %fr3, 8(%t1) + fstd,ma %fr4, 8(%t1) + fstd,ma %fr5, 8(%t1) + fstd,ma %fr6, 8(%t1) + fstd,ma %fr7, 8(%t1) + fstd,ma %fr8, 8(%t1) + fstd,ma %fr9, 8(%t1) + fstd,ma %fr10, 8(%t1) + fstd,ma %fr11, 8(%t1) + fstd,ma %fr12, 8(%t1) + fstd,ma %fr13, 8(%t1) + fstd,ma %fr14, 8(%t1) + fstd,ma %fr15, 8(%t1) + fstd,ma %fr16, 8(%t1) + fstd,ma %fr17, 8(%t1) + fstd,ma %fr18, 8(%t1) + fstd,ma %fr19, 8(%t1) + fstd,ma %fr20, 8(%t1) + fstd,ma %fr21, 8(%t1) + fstd,ma %fr22, 8(%t1) + fstd,ma %fr23, 8(%t1) + fstd,ma %fr24, 8(%t1) + fstd,ma %fr25, 8(%t1) + fstd,ma %fr26, 8(%t1) + fstd,ma %fr27, 8(%t1) + fstd,ma %fr28, 8(%t1) + fstd,ma %fr29, 8(%t1) + fstd,ma %fr30, 8(%t1) + fstd %fr31, 0(%t1) + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + ldi 1, %arg0 /* arg0 := STDOUT_FILENO */ + ldo -(4*NEXECREGS)(%sp), %arg1 /* arg1 := regs */ + ldi (4*NEXECREGS), %arg2 /* arg2 := sizeof(regs) */ + ldil L%SYSCALLGATE, %r1 + ble 4(%sr2, %r1) + ldi SYS_write, %t1 + + comb,<>,n %r0, %t1, 2f /* bail if write failed */ + ldi (4*NEXECREGS), %t1 /* bail if wrong # bytes */ + comb,<>,n %ret0, %t1, 2f + + /* call exit(0) */ + ldi 0, %arg0 +1: ldil L%SYSCALLGATE, %r1 + ble 4(%sr2, %r1) + ldi SYS_exit, %t1 + break 0, 0 /* paranoia */ + +2: /* call exit(127) */ + b 1b + ldi 127, %arg0 +EXIT(execregs_start) + +/* main stub to simplify linking */ +LEAF_ENTRY(main) + break 0, 0 /* paranoia */ +EXIT(main) diff --git a/kernel/arch/hppa/signalsphandler.S b/kernel/arch/hppa/signalsphandler.S new file mode 100644 index 000000000000..01633d99ff8b --- /dev/null +++ b/kernel/arch/hppa/signalsphandler.S @@ -0,0 +1,46 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:32:49 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:32:49 riastradh Exp $") + +/* + * signalsphandler(signo@arg0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +LEAF_ENTRY(signalsphandler) + addil LT%_C_LABEL(signalsp), %r19 /* r1 := &signalsp */ + ldw RT%_C_LABEL(signalsp)(%r1), %r1 + bv %r0(%rp) /* return */ + stw %sp, 0(%r1) /* signalsp := sp */ +EXIT(signalsphandler) diff --git a/kernel/arch/hppa/stack_pointer.h b/kernel/arch/hppa/stack_pointer.h new file mode 100644 index 000000000000..acb73443621c --- /dev/null +++ b/kernel/arch/hppa/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:32:49 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_HPPA_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_HPPA_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("ldo 1(%%sp),%%sp" ::: "memory") +#define FIX_SP __asm __volatile("ldo -1(%%sp),%%sp" ::: "memory") + +#endif /* TESTS_KERNEL_ARCH_HPPA_STACK_POINTER_H */ diff --git a/kernel/arch/hppa/threadspfunc.S b/kernel/arch/hppa/threadspfunc.S new file mode 100644 index 000000000000..f1b1d21fadfe --- /dev/null +++ b/kernel/arch/hppa/threadspfunc.S @@ -0,0 +1,43 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@arg0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +LEAF_ENTRY(threadspfunc) + bv %r0(%rp) /* return to caller */ + copy %sp, %ret0 /* return sp */ +EXIT(threadspfunc) diff --git a/kernel/arch/i386/contextspfunc.S b/kernel/arch/i386/contextspfunc.S new file mode 100644 index 000000000000..cc097cc61325 --- /dev/null +++ b/kernel/arch/i386/contextspfunc.S @@ -0,0 +1,56 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(contextsp)@GOT(%eax),%eax + movl %esp,(%eax) + jmp _C_LABEL(contextdone)@PLT +END(contextspfunc) + + .text + _ALIGN_TEXT + .local getpc_eax + .type getpc_eax,@function +getpc_eax: + movl (%esp),%eax + ret +END(getpc_eax) diff --git a/kernel/arch/i386/execregs.c b/kernel/arch/i386/execregs.c new file mode 100644 index 000000000000..477cd82989e9 --- /dev/null +++ b/kernel/arch/i386/execregs.c @@ -0,0 +1,132 @@ +/* $NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $"); + +#include "execregs.h" + +#include <errno.h> +#include <spawn.h> +#include <stddef.h> +#include <unistd.h> + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + return x; +} + +int +execregschild(char *path) +{ + register long edi __asm("edi") = nonnull('d'); + register long esi __asm("esi") = nonnull('s'); + /* ebp: frame pointer, can't touch that here, but it'll be nonnull */ + /* ebx: ps_strings, passed to child */ + register long edx __asm("edx") = nonnull('x'); + register long ecx __asm("ecx") = nonnull('c'); + register long eax __asm("eax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(edi), + "+r"(esi), + "+r"(edx), + "+r"(ecx), + "+r"(eax) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + register long edi __asm("edi") = nonnull('d'); + register long esi __asm("esi") = nonnull('s'); + /* ebp: frame pointer, can't touch that here, but it'll be nonnull */ + /* ebx: ps_strings, passed to child */ + register long edx __asm("edx") = nonnull('x'); + register long ecx __asm("ecx") = nonnull('c'); + register long eax __asm("eax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(edi), + "+r"(esi), + "+r"(edx), + "+r"(ecx), + "+r"(eax) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff --git a/kernel/arch/i386/execregs.h b/kernel/arch/i386/execregs.h new file mode 100644 index 000000000000..f512bbabc1c7 --- /dev/null +++ b/kernel/arch/i386/execregs.h @@ -0,0 +1,69 @@ +/* $NetBSD: execregs.h,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_I386_EXECREGS_H +#define TESTS_KERNEL_ARCH_I386_EXECREGS_H + +#include <sys/cdefs.h> + +#define NEXECREGS 6 + +#ifndef _LOCORE + +#include <unistd.h> + +/* + * Ordered by struct trapframe in sys/arch/i386/include/frame.h for + * convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + /* gs/fs/es/ds: segment registers, not really registers */ + "edi", + "esi", + "ebp", + /* ebx: ps_strings */ + "edx", + "ecx", + "eax", + /* trapno: not a register */ + /* err: not a register */ + /* eip: instruction pointer */ + /* cs: segment register */ + /* eflags */ + /* esp: stack pointer */ + /* ss: stack selector */ +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_I386_EXECREGS_H */ diff --git a/kernel/arch/i386/execsp.S b/kernel/arch/i386/execsp.S new file mode 100644 index 000000000000..133af37715ad --- /dev/null +++ b/kernel/arch/i386/execsp.S @@ -0,0 +1,112 @@ +/* $NetBSD: execsp.S,v 1.1 2025/04/20 22:33:13 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.1 2025/04/20 22:33:13 riastradh Exp $") + +/* + * void execsp_start(void (*cleanup@edx)(void), void *obj_main@ecx, + * struct ps_strings *ps_strings@ebx) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(startsp)@GOT(%eax),%eax + movl %esp,(%eax) + jmp _C_LABEL(__start)@PLT +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(ctorsp)@GOT(%eax),%eax + movl %esp,(%eax) + ret +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .ctors,"aw",@progbits + .p2align 2 + .long _C_LABEL(execsp_ctor) + +/* + * int main(int argc@rdi, char **argv@rsi, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(mainsp)@GOT(%eax),%eax + movl %esp,(%eax) + xorl %eax,%eax + ret +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(dtorsp)@GOT(%eax),%eax + movl %esp,(%eax) + jmp _C_LABEL(execsp_main)@PLT +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .dtors,"aw",@progbits + .p2align 2 + .long _C_LABEL(execsp_dtor) + + .text + _ALIGN_TEXT + .local getpc_eax + .type getpc_eax,@function +getpc_eax: + movl (%esp),%eax + ret +END(getpc_eax) diff --git a/kernel/arch/i386/h_execregs.S b/kernel/arch/i386/h_execregs.S new file mode 100644 index 000000000000..ac9b843f9d86 --- /dev/null +++ b/kernel/arch/i386/h_execregs.S @@ -0,0 +1,85 @@ +/* $NetBSD: h_execregs.S,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <sys/syscall.h> + +#include <machine/asm.h> + +#include "execregs.h" + +ENTRY(execregs_start) + andl $-0x4,%esp /* align stack to 4-byte boundary */ + + /* store registers to a buffer on stack */ + subl $(NEXECREGS*4),%esp /* space for NEXECREGS registers */ + movl %edi,0*4(%esp) /* order matches execregs.h */ + movl %esi,1*4(%esp) + movl %ebp,2*4(%esp) + movl %edx,3*4(%esp) + movl %ecx,4*4(%esp) + movl %eax,5*4(%esp) + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + movl %esp,%eax /* eax := regs */ + pushl $(NEXECREGS*4) /* arg2 := sizeof(regs) */ + pushl %eax /* arg1 := regs */ + pushl $0x1 /* arg0 := STDOUT_FILENO */ + call execregs_write + + jb 2f /* bail if write failed */ + cmpl $(NEXECREGS*4),%eax /* bail if wrote wrong # of bytes */ + jne 2f + + /* call exit(0) */ + pushl $0 /* arg0 := 0 */ +1: call execregs_exit + hlt /* paranoia */ + +2: /* call exit(127) */ + pushl $127 /* arg0 := 127 */ + jmp 1b +END(execregs_start) + +ENTRY(execregs_write) + movl $SYS_write,%eax /* syscall number */ + int $0x80 + retl +END(execregs_write) + +ENTRY(execregs_exit) + movl $SYS_exit,%eax /* syscall number */ + int $0x80 + hlt +END(execregs_exit) + +/* main stub to simplify linking */ +ENTRY(main) + hlt +END(main) diff --git a/kernel/arch/i386/signalsphandler.S b/kernel/arch/i386/signalsphandler.S new file mode 100644 index 000000000000..418825e78ab6 --- /dev/null +++ b/kernel/arch/i386/signalsphandler.S @@ -0,0 +1,56 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:33:13 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:33:13 riastradh Exp $") + +/* + * signalsphandler(signo@esp[4]) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + call getpc_eax + addl $_GLOBAL_OFFSET_TABLE_,%eax + movl _C_LABEL(signalsp)@GOT(%eax),%eax + movl %esp,(%eax) + ret +END(signalsphandler) + + .text + _ALIGN_TEXT + .local getpc_eax + .type getpc_eax,@function +getpc_eax: + movl (%esp),%eax + ret +END(getpc_eax) diff --git a/kernel/arch/i386/stack_pointer.h b/kernel/arch/i386/stack_pointer.h new file mode 100644 index 000000000000..6c95a28ab7b6 --- /dev/null +++ b/kernel/arch/i386/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:33:13 riastradh Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_I386_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_I386_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("addl $-1,%esp") +#define FIX_SP __asm __volatile("addl $1,%esp") + +#endif /* TESTS_KERNEL_ARCH_I386_STACK_POINTER_H */ diff --git a/kernel/arch/i386/threadspfunc.S b/kernel/arch/i386/threadspfunc.S new file mode 100644 index 000000000000..af03ff4c550e --- /dev/null +++ b/kernel/arch/i386/threadspfunc.S @@ -0,0 +1,43 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@esp[4]) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + mov %esp,%eax + ret +END(threadspfunc) diff --git a/kernel/arch/mips/contextspfunc.S b/kernel/arch/mips/contextspfunc.S new file mode 100644 index 000000000000..bee0a610dc86 --- /dev/null +++ b/kernel/arch/mips/contextspfunc.S @@ -0,0 +1,53 @@ +/* $NetBSD: contextspfunc.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $") + +#include "SYS.h" + + .text + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +LEAF(contextspfunc) + PIC_PROLOGUE(contextspfunc) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(contextsp) /* load t1 := &contextsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store contextsp := stack pointer */ + + PIC_TAILCALL(contextdone) +END(contextspfunc) diff --git a/kernel/arch/mips/execsp.S b/kernel/arch/mips/execsp.S new file mode 100644 index 000000000000..b4f2dcfd6e2c --- /dev/null +++ b/kernel/arch/mips/execsp.S @@ -0,0 +1,118 @@ +/* $NetBSD: execsp.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $") + +#include "SYS.h" + + .text + +/* + * void execsp_start(void *stackpointer@a0, void (*cleanup@a1)(void), + * void *obj_main@a2, struct ps_strings *ps_strings@a3) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +LEAF(execsp_start) + PIC_PROLOGUE(execsp_start) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(startsp) /* load t1 := &startsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store startsp := stack pointer */ + + PIC_TAILCALL(__start) /* gp restore, uses t3 */ +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +LEAF(execsp_ctor) + PIC_PROLOGUE(execsp_ctor) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(ctorsp) /* load t1 := &ctorsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store ctorsp := stack pointer */ + + PIC_RETURN() /* gp restore, uses t3 */ +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .pushsection .ctors,"aw",@progbits + .p2align PTR_SCALESHIFT + PTR_WORD _C_LABEL(execsp_ctor) + .popsection + +/* + * int main(int argc@a0, char **argv@a1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +LEAF(main) + PIC_PROLOGUE(main) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(mainsp) /* load t1 := &mainsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store mainsp := stack pointer */ + + move v0, zero /* return 0 */ + + PIC_RETURN() /* gp restore, uses t3 */ +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +LEAF(execsp_dtor) + PIC_PROLOGUE(execsp_dtor) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(dtorsp) /* load t1 := &dtorsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store dtorsp := stack pointer */ + + PIC_TAILCALL(execsp_main) /* gp restore, uses t3 */ +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .pushsection .dtors,"aw",@progbits + .p2align PTR_SCALESHIFT + PTR_WORD _C_LABEL(execsp_dtor) + .popsection diff --git a/kernel/arch/mips/signalsphandler.S b/kernel/arch/mips/signalsphandler.S new file mode 100644 index 000000000000..e742c2c95701 --- /dev/null +++ b/kernel/arch/mips/signalsphandler.S @@ -0,0 +1,53 @@ +/* $NetBSD: signalsphandler.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.2 2025/04/27 16:49:54 riastradh Exp $") + +#include "SYS.h" + + .text + +/* + * signalsphandler(signo@a0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +LEAF(signalsphandler) + PIC_PROLOGUE(signalsphandler) /* gp setup, sets t3 */ + + PTR_LA t1, _C_LABEL(signalsp) /* load t1 := &signalsp */ + NOP_L /* load hazard */ + PTR_S sp, 0(t1) /* store signalsp := stack pointer */ + + PIC_RETURN() +END(signalsphandler) diff --git a/kernel/arch/mips/stack_pointer.h b/kernel/arch/mips/stack_pointer.h new file mode 100644 index 000000000000..288c58928526 --- /dev/null +++ b/kernel/arch/mips/stack_pointer.h @@ -0,0 +1,40 @@ +/* $NetBSD: stack_pointer.h,v 1.2 2025/04/21 14:17:38 rin Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_MIPS_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_MIPS_STACK_POINTER_H + +#ifdef __mips_o32 +#define MISALIGN_SP __asm __volatile("addiu $sp,$sp,-1" ::: "memory") +#define FIX_SP __asm __volatile("addiu $sp,$sp,1" ::: "memory") +#else +#define MISALIGN_SP __asm __volatile("daddiu $sp,$sp,-1" ::: "memory") +#define FIX_SP __asm __volatile("daddiu $sp,$sp,1" ::: "memory") +#endif + +#endif /* TESTS_KERNEL_ARCH_MIPS_STACK_POINTER_H */ diff --git a/kernel/arch/mips/threadspfunc.S b/kernel/arch/mips/threadspfunc.S new file mode 100644 index 000000000000..a42362fee67d --- /dev/null +++ b/kernel/arch/mips/threadspfunc.S @@ -0,0 +1,46 @@ +/* $NetBSD: threadspfunc.S,v 1.2 2025/04/21 03:47:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.2 2025/04/21 03:47:32 riastradh Exp $") + + .text + .set noreorder + +/* + * void *threadspfunc(void *cookie@a0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +LEAF(threadspfunc) + j ra + move v0, sp +END(threadspfunc) diff --git a/kernel/arch/riscv/contextspfunc.S b/kernel/arch/riscv/contextspfunc.S new file mode 100644 index 000000000000..7f405123deb3 --- /dev/null +++ b/kernel/arch/riscv/contextspfunc.S @@ -0,0 +1,45 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + PTR_LA t0, _C_LABEL(contextsp) /* t0 := &contextsp */ + PTR_S sp, 0(t0) /* contextsp := sp */ + tail _C_LABEL(contextdone) /* tail call contextdone */ +END(contextspfunc) diff --git a/kernel/arch/riscv/execsp.S b/kernel/arch/riscv/execsp.S new file mode 100644 index 000000000000..d045cbf0d3af --- /dev/null +++ b/kernel/arch/riscv/execsp.S @@ -0,0 +1,100 @@ +/* $NetBSD: execsp.S,v 1.1 2025/04/20 22:34:07 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.1 2025/04/20 22:34:07 riastradh Exp $") + +/* + * void execsp_start(void (*cleanup@a0)(void), + * struct ps_strings *ps_strings@a1) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) + .option push + .option norelax /* Don't optimize this into `mv gp, gp'! */ + lla gp, __global_pointer$ + .option pop + + PTR_LA t0, _C_LABEL(startsp) /* t0 := &startsp */ + PTR_S sp, 0(t0) /* startsp := sp */ + tail _C_LABEL(__start) /* tail call __start */ +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + PTR_LA t0, _C_LABEL(ctorsp) /* t0 := &ctorsp */ + PTR_S sp, 0(t0) /* ctorsp := sp */ + ret +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .init_array,"aw" + .p2align PTR_SCALESHIFT + PTR_WORD _C_LABEL(execsp_ctor) + +/* + * int main(int argc@a0, char **argv@a1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + PTR_LA t0, _C_LABEL(mainsp) /* t0 := &mainsp */ + PTR_S sp, 0(t0) /* mainsp := sp */ + li a0, 0 /* return 0 */ + ret +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + PTR_LA t0, _C_LABEL(dtorsp) /* t0 := &dtorsp */ + PTR_S sp, 0(t0) /* dtorsp := sp */ + tail _C_LABEL(execsp_main) /* tail call execsp_main */ +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .fini_array,"aw" + .p2align PTR_SCALESHIFT + PTR_WORD _C_LABEL(execsp_dtor) diff --git a/kernel/arch/riscv/signalsphandler.S b/kernel/arch/riscv/signalsphandler.S new file mode 100644 index 000000000000..6a5d2f752ee2 --- /dev/null +++ b/kernel/arch/riscv/signalsphandler.S @@ -0,0 +1,45 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:34:07 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:34:07 riastradh Exp $") + +/* + * signalsphandler(signo@a0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + PTR_LA t0, _C_LABEL(signalsp) /* t0 := &signalsp */ + PTR_S sp, 0(t0) /* signalsp := sp */ + ret +END(signalsphandler) diff --git a/kernel/arch/riscv/stack_pointer.h b/kernel/arch/riscv/stack_pointer.h new file mode 100644 index 000000000000..22c246e4a86a --- /dev/null +++ b/kernel/arch/riscv/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:34:07 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_RISCV_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_RISCV_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("addi sp,sp,-1" ::: "memory") +#define FIX_SP __asm __volatile("addi sp,sp,1" ::: "memory") + +#endif /* TESTS_KERNEL_ARCH_RISCV_STACK_POINTER_H */ diff --git a/kernel/arch/riscv/threadspfunc.S b/kernel/arch/riscv/threadspfunc.S new file mode 100644 index 000000000000..30291ad2eb73 --- /dev/null +++ b/kernel/arch/riscv/threadspfunc.S @@ -0,0 +1,43 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:44 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@o0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + mv a0, sp /* return sp */ + ret /* return to caller */ +END(threadspfunc) diff --git a/kernel/arch/sh3/asm.h b/kernel/arch/sh3/asm.h new file mode 100644 index 000000000000..16389b5c299e --- /dev/null +++ b/kernel/arch/sh3/asm.h @@ -0,0 +1,58 @@ +/* $NetBSD: asm.h,v 1.1 2025/04/26 22:34:52 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_SH3_ASM_H +#define TESTS_KERNEL_ARCH_SH3_ASM_H + +#include <machine/asm.h> + +/* + * We define convenience macros to hide the difference between direct + * and PIC function calls, but with variable accesses it gets a bit + * more unwieldy, so don't impose this on the general audience + */ + +#ifdef __PIC__ + +#define VAR_DATUM(v) .long v@GOT + +#define MOVL_VAR(label, reg) \ + mov.l label, r0; \ + mov.l @(r0, r12), reg + +#else + +#define VAR_DATUM(v) .long v + +#define MOVL_VAR(label, reg) \ + mov.l label, reg; \ + +#endif + + +#endif /* TESTS_KERNEL_ARCH_SH3_ASM_H */ diff --git a/kernel/arch/sh3/contextspfunc.S b/kernel/arch/sh3/contextspfunc.S new file mode 100644 index 000000000000..51e91133417e --- /dev/null +++ b/kernel/arch/sh3/contextspfunc.S @@ -0,0 +1,55 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/26 22:34:52 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "asm.h" + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/26 22:34:52 uwe Exp $") + + +/* + * void contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + mov sp, r1 + PIC_PROLOGUE(.L_GOT) + + MOVL_VAR(.L_contextsp, r0) + mov.l r1, @r0 + + mov.l .L_contextdone, r0 +1: JUMP r0 + PIC_EPILOGUE_SLOT + + .p2align 2 +.L_GOT: PIC_GOT_DATUM +.L_contextsp: VAR_DATUM(contextsp) +.L_contextdone: CALL_DATUM(contextdone, 1b) + SET_ENTRY_SIZE(contextspfunc) diff --git a/kernel/arch/sh3/execsp.S b/kernel/arch/sh3/execsp.S new file mode 100644 index 000000000000..639ed4e6487b --- /dev/null +++ b/kernel/arch/sh3/execsp.S @@ -0,0 +1,146 @@ +/* $NetBSD: execsp.S,v 1.2 2025/04/27 00:03:46 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "asm.h" + +RCSID("$NetBSD: execsp.S,v 1.2 2025/04/27 00:03:46 riastradh Exp $") + + +/* + * void execsp_start() + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + * + * See sys/arch/sh3/sh3/sh3_machdep.c setregs() + */ +ENTRY(execsp_start) + mov sp, r1 // for consistency, don't need to + PIC_PROLOGUE_NOSAVE(.L_start_GOT) + + MOVL_VAR(.L_startsp, r0) + mov.l r1, @r0 + + mov.l .L___start, r0 +1: JUMP r0 + nop + + .p2align 2 +.L_start_GOT: PIC_GOT_DATUM +.L_startsp: VAR_DATUM(startsp) +.L___start: CALL_DATUM(__start, 1b) + SET_ENTRY_SIZE(execsp_start) + + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + mov sp, r1 + PIC_PROLOGUE(.L_ctor_GOT) + + MOVL_VAR(.L_ctorsp, r0) + mov.l r1, @r0 + + rts + PIC_EPILOGUE_SLOT + + .p2align 2 +.L_ctor_GOT: PIC_GOT_DATUM +.L_ctorsp: VAR_DATUM(ctorsp) + SET_ENTRY_SIZE(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .pushsection .ctors, "aw", @progbits + .p2align 2 + .long _C_LABEL(execsp_ctor) + .popsection + + +/* + * int main(int argc, char **argv, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + mov sp, r1 + PIC_PROLOGUE(.L_main_GOT) + + MOVL_VAR(.L_mainsp, r0) + mov.l r1, @r0 + + PIC_EPILOGUE + rts + mov #0, r0 + + .p2align 2 +.L_main_GOT: PIC_GOT_DATUM +.L_mainsp: VAR_DATUM(mainsp) + SET_ENTRY_SIZE(main) + + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + mov sp, r1 + sts.l pr, @-sp + PIC_PROLOGUE(.L_dtor_GOT) + + MOVL_VAR(.L_dtorsp, r0) + mov.l r1, @r0 + + mov.l .L_execsp_main, r0 +1: CALL r0 + nop + + PIC_EPILOGUE + lds.l @sp+, pr + rts + nop + + .p2align 2 +.L_dtor_GOT: PIC_GOT_DATUM +.L_dtorsp: VAR_DATUM(dtorsp) +.L_execsp_main: CALL_DATUM(execsp_main, 1b) + SET_ENTRY_SIZE(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .pushsection .dtors, "aw", @progbits + .p2align 2 + .long _C_LABEL(execsp_dtor) + .popsection diff --git a/kernel/arch/sh3/h_execregs.S b/kernel/arch/sh3/h_execregs.S new file mode 100644 index 000000000000..d7c91161c34a --- /dev/null +++ b/kernel/arch/sh3/h_execregs.S @@ -0,0 +1,86 @@ +/* $NetBSD: h_execregs.S,v 1.1 2025/04/27 02:24:07 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE +#include <machine/asm.h> +#include <machine/mcontext.h> +#include <sys/syscall.h> + + +// ELF entry point +ENTRY(execregs_start) + // __gregset_t r; // mcontext (but general regs only) + mov.l sp, @-sp + mov.l r0, @-sp + mov.l r1, @-sp + mov.l r2, @-sp + mov.l r3, @-sp + mov.l r4, @-sp + mov.l r5, @-sp + mov.l r6, @-sp + mov.l r7, @-sp + mov.l r8, @-sp + mov.l r9, @-sp + mov.l r10, @-sp + mov.l r11, @-sp + mov.l r12, @-sp + mov.l r13, @-sp + mov.l r14, @-sp + sts.l pr, @-sp + sts.l mach, @-sp + sts.l macl, @-sp + mov #0, r0 + mov.l r0, @-sp // _REG_SR is privileged + mova .Lend, r0 // _REG_PC + mov.l @r0, r1 + sub r1, r0 + mov.l r0, @-sp + stc.l gbr, @-sp + + // write(STDOUT_FILENO, &r, sizeof(__gregset_t)) + mov #1, r4 + mov sp, r5 + mov #(_NGREG * 4), r6 + mov #SYS_write, r0 + trapa #0x80 + + // _exit(0) + mov #0, r4 + mov #SYS_exit, r0 + trapa #0x80 + + .p2align 2 +.Lend: .long .Lend - execregs_start + SET_ENTRY_SIZE(execregs_start) + + +// main stub to simplify linking +ENTRY(main) + rts + mov #0, r0 + SET_ENTRY_SIZE(main) diff --git a/kernel/arch/sh3/signalsphandler.S b/kernel/arch/sh3/signalsphandler.S new file mode 100644 index 000000000000..e0a86ae40558 --- /dev/null +++ b/kernel/arch/sh3/signalsphandler.S @@ -0,0 +1,61 @@ +/* $NetBSD: signalsphandler.S,v 1.2 2025/04/26 23:49:55 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "asm.h" +RCSID("$NetBSD: signalsphandler.S,v 1.2 2025/04/26 23:49:55 uwe Exp $") + + +/* + * void signalsphandler(int signo) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + mov sp, r1 +#ifdef __PIC__ + // PR kern/59327: don't touch stack as SP may be misaligned + // and as SuperH is a strict alignment architecture, we will + // get SIGBUS if we try to save registers on the stack + mov r12, r2 +#endif + PIC_PROLOGUE_NOSAVE(.L_GOT) + + MOVL_VAR(.L_signalsp, r0) + mov.l r1, @r0 + +#ifdef __PIC__ + mov r2, r12 +#endif + rts + nop + + .p2align 2 +.L_GOT: PIC_GOT_DATUM +.L_signalsp: VAR_DATUM(signalsp) + SET_ENTRY_SIZE(signalsphandler) diff --git a/kernel/arch/sh3/stack_pointer.h b/kernel/arch/sh3/stack_pointer.h new file mode 100644 index 000000000000..ed3366602f56 --- /dev/null +++ b/kernel/arch/sh3/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/26 22:34:52 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_SH3_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_SH3_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("add #-1, sp" ::: "memory") +#define FIX_SP __asm __volatile("add #+1, sp" ::: "memory") + +#endif /* TESTS_KERNEL_ARCH_SH3_STACK_POINTER_H */ diff --git a/kernel/arch/sh3/threadspfunc.S b/kernel/arch/sh3/threadspfunc.S new file mode 100644 index 000000000000..de065e54191b --- /dev/null +++ b/kernel/arch/sh3/threadspfunc.S @@ -0,0 +1,41 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/26 22:34:52 uwe Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "asm.h" +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/26 22:34:52 uwe Exp $") + + +/* + * void *threadspfunc(void *cookie) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + rts + mov sp, r0 + SET_ENTRY_SIZE(threadspfunc) diff --git a/kernel/arch/sparc/contextspfunc.S b/kernel/arch/sparc/contextspfunc.S new file mode 100644 index 000000000000..a24185cabd73 --- /dev/null +++ b/kernel/arch/sparc/contextspfunc.S @@ -0,0 +1,64 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $") + +#ifdef __PIC__ +#define SETHI(label, got, reg) \ + set label, reg; /* reg := &label - &GOT */ \ + ld [got + reg], reg /* reg := &label */ +#define LO(label, reg) \ + reg +#else +#define SETHI(label, got, reg) \ + sethi %hi(label), reg /* reg := &label - %lo(label) */ +#define LO(label, reg) \ + reg + %lo(label) +#endif + + .text + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + /* Reminder: o6 is frame pointer, o7 + 8 is return address. */ + PIC_PROLOGUE(%g1, %o5) /* g1 := &GOT, clobber o5 */ + SETHI(_C_LABEL(contextsp), %g1, %o5) /* o5 := &contextsp */ + call _C_LABEL(contextdone) /* jump to contextdone */ + st %sp, [LO(_C_LABEL(contextsp), %o5)] /* contextsp := sp */ + /* don't care what happens here, caller must never return */ + ta 1 /* Tcc, trap always */ +END(contextspfunc) diff --git a/kernel/arch/sparc/execsp.S b/kernel/arch/sparc/execsp.S new file mode 100644 index 000000000000..4b225dd6d550 --- /dev/null +++ b/kernel/arch/sparc/execsp.S @@ -0,0 +1,123 @@ +/* $NetBSD: execsp.S,v 1.1 2025/04/20 22:33:41 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.1 2025/04/20 22:33:41 riastradh Exp $") + +#ifdef __PIC__ +#define SETHI(label, got, reg) \ + set label, reg; /* reg := &label - &GOT */ \ + ld [got + reg], reg /* reg := &label */ +#define LO(label, reg) \ + reg +#else +#define SETHI(label, got, reg) \ + sethi %hi(label), reg /* reg := &label - %lo(label) */ +#define LO(label, reg) \ + reg + %lo(label) +#endif + + .text + +/* + * void execsp_start(struct ps_strings *ps_strings@g1, + * void *obj_main@g2, void (*cleanup@g3)(void)) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) + PIC_PROLOGUE(%o1, %o2) /* o1 := GOT, clobber o2 */ + SETHI(_C_LABEL(startsp), %o1, %o2) /* o2 := &startup */ + call _C_LABEL(__start) /* jump to start via PLT */ + st %sp, [LO(_C_LABEL(startsp), %o2)] /* startsp := sp */ + /* don't care what happens here, caller must never return */ + ta 1 /* Tcc, trap always */ +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + /* Reminder: o6 is frame pointer, o7 + 8 is return address. */ + PIC_PROLOGUE(%g1, %o5) /* g1 := &GOT, clobber o5 */ + SETHI(_C_LABEL(ctorsp), %g1, %o5) /* o5 := &ctorsp */ + retl /* return to caller */ + st %sp, [LO(_C_LABEL(ctorsp), %o5)] /* ctorsp := sp */ +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .pushsection .ctors,"aw",@progbits + .p2align 2 + .long _C_LABEL(execsp_ctor) + .popsection + +/* + * int main(int argc@a0, char **argv@a1, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + /* Reminder: o6 is frame pointer, o7 + 8 is return address. */ + PIC_PROLOGUE(%g1, %o5) /* g1 := &GOT, clobber o5 */ + SETHI(_C_LABEL(mainsp), %g1, %o5) /* o5 := &mainsp */ + st %sp, [LO(_C_LABEL(mainsp), %o5)] /* mainsp := sp */ + retl /* return to caller */ + mov 0, %o0 /* return 0 */ +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + /* Reminder: o6 is frame pointer, o7 + 8 is return address. */ + PIC_PROLOGUE(%g1, %o5) /* g1 := &GOT, clobber o5 */ + SETHI(_C_LABEL(dtorsp), %g1, %o5) /* o5 := &dtorsp - &GOT */ + st %sp, [LO(_C_LABEL(dtorsp), %o5)] /* dtorsp := sp */ + mov %o7, %o5 /* save return address */ + call _C_LABEL(execsp_main) /* tail call to execsp_main */ + mov %o5, %o7 /* restore return address */ +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .pushsection .dtors,"aw",@progbits + .p2align 2 + .long _C_LABEL(execsp_dtor) + .popsection diff --git a/kernel/arch/sparc/signalsphandler.S b/kernel/arch/sparc/signalsphandler.S new file mode 100644 index 000000000000..187091d23c01 --- /dev/null +++ b/kernel/arch/sparc/signalsphandler.S @@ -0,0 +1,62 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:33:41 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:33:41 riastradh Exp $") + +#ifdef __PIC__ +#define SETHI(label, got, reg) \ + set label, reg; /* reg := &label - &GOT */ \ + ld [got + reg], reg /* reg := &label */ +#define LO(label, reg) \ + reg +#else +#define SETHI(label, got, reg) \ + sethi %hi(label), reg /* reg := &label - %lo(label) */ +#define LO(label, reg) \ + reg + %lo(label) +#endif + + .text + +/* + * signalsphandler(signo@o0) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + /* Reminder: o6 is frame pointer, o7 + 8 is return address. */ + PIC_PROLOGUE(%g1, %o5) /* g1 := &GOT, clobber o5 */ + SETHI(_C_LABEL(signalsp), %g1, %o5) /* o5 := &signalsp */ + retl /* return to caller */ + st %sp, [LO(_C_LABEL(signalsp), %o5)] /* signalsp := sp */ +END(signalsphandler) diff --git a/kernel/arch/sparc/stack_pointer.h b/kernel/arch/sparc/stack_pointer.h new file mode 100644 index 000000000000..20c06bec77cd --- /dev/null +++ b/kernel/arch/sparc/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:33:41 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_SPARC_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_SPARC_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("dec %%sp" ::: "memory") +#define FIX_SP __asm __volatile("inc %%sp" ::: "memory") + +#endif /* TESTS_KERNEL_ARCH_SPARC_STACK_POINTER_H */ diff --git a/kernel/arch/sparc/threadspfunc.S b/kernel/arch/sparc/threadspfunc.S new file mode 100644 index 000000000000..794804d85741 --- /dev/null +++ b/kernel/arch/sparc/threadspfunc.S @@ -0,0 +1,45 @@ +/* $NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $") + + .text + +/* + * void *threadspfunc(void *cookie@o0) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + retl /* return to caller */ + mov %sp, %o0 /* return sp */ +END(threadspfunc) diff --git a/kernel/arch/vax/execregs.c b/kernel/arch/vax/execregs.c new file mode 100644 index 000000000000..414b810336d8 --- /dev/null +++ b/kernel/arch/vax/execregs.c @@ -0,0 +1,166 @@ +/* $NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $"); + +#include "execregs.h" + +#include <errno.h> +#include <spawn.h> +#include <stddef.h> +#include <unistd.h> + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + return x; +} + +int +execregschild(char *path) +{ + /* fp: frame pointer, nonnull */ + /* ap: argument pointer, on user stack, nonnull */ + /* sp: stack pointer, nonnull */ + register long r0 __asm("r0") = nonnull(0x10); + register long r1 __asm("r1") = nonnull(1); + register long r2 __asm("r2") = nonnull(2); + register long r3 __asm("r3") = nonnull(3); + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + /* pc: user PC, will be nonnull */ + /* psl: processor status longword, will be nonnull */ + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r0), + "+r"(r1), + "+r"(r2), + "+r"(r3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + /* fp: frame pointer, nonnull */ + /* ap: argument pointer, on user stack, nonnull */ + /* sp: stack pointer, nonnull */ + register long r0 __asm("r0") = nonnull(0x10); + register long r1 __asm("r1") = nonnull(1); + register long r2 __asm("r2") = nonnull(2); + register long r3 __asm("r3") = nonnull(3); + register long r4 __asm("r4") = nonnull(4); + register long r5 __asm("r5") = nonnull(5); + register long r6 __asm("r6") = nonnull(6); + register long r7 __asm("r7") = nonnull(7); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long r10 __asm("r10") = nonnull(10); + register long r11 __asm("r11") = nonnull(11); + /* pc: user PC, will be nonnull */ + /* psl: processor status longword, will be nonnull */ + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r0), + "+r"(r1), + "+r"(r2), + "+r"(r3), + "+r"(r4), + "+r"(r5), + "+r"(r6), + "+r"(r7), + "+r"(r8), + "+r"(r9), + "+r"(r10), + "+r"(r11) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff --git a/kernel/arch/vax/execregs.h b/kernel/arch/vax/execregs.h new file mode 100644 index 000000000000..882bcd1b6702 --- /dev/null +++ b/kernel/arch/vax/execregs.h @@ -0,0 +1,77 @@ +/* $NetBSD: execregs.h,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_VAX_EXECREGS_H +#define TESTS_KERNEL_ARCH_VAX_EXECREGS_H + +#include <sys/cdefs.h> + +#define NEXECREGS 12 + +#ifndef _LOCORE + +#include <unistd.h> + +/* + * The order matches that in struct trapframe in + * sys/arch/vax/include/trap.h + * + * Must match h_execregs.S. + * + * See also sys/arch/vax/vax/trap.c:setregs() + */ +static const char *const regname[] = { + "fp", /* Stack frame pointer */ + "ap", /* Argument pointer on user stack */ + /* sp: stack pointer */ + "r0", /* General registers saved upon trap/syscall */ + "r1", + "r2", + "r3", + "r4", + "r5", + /* r6: initial stack pointer */ + "r7", + "r8", + /* r9: ps_strings */ + "r10", + "r11", + /* trap: type of trap, not a register */ + /* code: trap specific code, not a register */ + /* pc: user PC */ + /* psl: processor status longword */ +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_VAX_EXECREGS_H */ diff --git a/kernel/arch/vax/h_execregs.S b/kernel/arch/vax/h_execregs.S new file mode 100644 index 000000000000..27c5c2052867 --- /dev/null +++ b/kernel/arch/vax/h_execregs.S @@ -0,0 +1,87 @@ +/* $NetBSD: h_execregs.S,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <sys/syscall.h> + +#include <machine/asm.h> + +#include "execregs.h" + +#define REGSIZE 4 +#define BUFSIZE (NEXECREGS * REGSIZE) +#define SLOT(n) (n)*REGSIZE(%sp) + +ENTRY(execregs_start, 0) + /* store registers to a buffer on stack */ + subl2 $BUFSIZE,%sp /* space for NEXECREGS registers */ + movl %fp,SLOT(0) /* order matches execregs.h */ + movl %ap,SLOT(1) + /* sp: stack pointer */ + movl %r0,SLOT(2) + movl %r1,SLOT(3) + movl %r2,SLOT(4) + movl %r3,SLOT(5) + movl %r4,SLOT(6) + movl %r5,SLOT(7) + /* r6: initial stack pointer */ + movl %r7,SLOT(8) + movl %r8,SLOT(9) + /* r9: ps_strings */ + movl %r10,SLOT(10) + movl %r11,SLOT(11) + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + pushl $BUFSIZE /* arg2 := sizeof(regs) */ + pushal 4(%sp) /* arg1 := regs */ + pushl $1 /* arg0 := STDOUT_FILENO */ + pushl $3 /* number of arguments */ + movl %sp,%ap /* argument pointer */ + chmk $SYS_write + + bcs 2f /* bail if write failed */ + cmpl $BUFSIZE,%r0 /* bail if wrote wrong # of bytes */ + bneq 2f + + /* call exit(0) */ + pushl $0 /* arg0 := 0 */ +1: pushl $1 /* number of arguments */ + movl %sp,%ap /* argument pointer */ + chmk $SYS_exit + .word 0xffff /* paranoia -- illegal opcode */ + +2: /* call exit(127) */ + pushl $127 /* arg0 := 127 */ + jmp 1b +END(execregs_start) + +/* main stub to simplify linking */ +ENTRY(main, 0) + .word 0xffff /* illegal opcode */ +END(main) diff --git a/kernel/arch/x86_64/contextspfunc.S b/kernel/arch/x86_64/contextspfunc.S new file mode 100644 index 000000000000..d01e1dcdcaf3 --- /dev/null +++ b/kernel/arch/x86_64/contextspfunc.S @@ -0,0 +1,55 @@ +/* $NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: contextspfunc.S,v 1.1 2025/04/21 02:33:45 riastradh Exp $") + +/* + * contextspfunc() + * + * makecontext(3) function. Store the stack pointer on entry at + * the global variable contextsp and call contextdone. + */ +ENTRY(contextspfunc) + /* + * `The end of the input argument area shall be aligned on a + * [16-byte] boundary. In other words, the value of (%rsp + 8) + * is always a multiple of 16 when control is transferred to + * the function entry point.' + * + * To make it convenient for t_signal_and_sp.c, we subtract 8 + * from %rsp in order to get something congruent to zero modulo + * the stack alignemnt. + */ + movq %rsp,_C_LABEL(contextsp)(%rip) + addq $-8,_C_LABEL(contextsp)(%rip) + call _C_LABEL(contextdone) +END(contextspfunc) diff --git a/kernel/arch/x86_64/execregs.c b/kernel/arch/x86_64/execregs.c new file mode 100644 index 000000000000..fad1b40daa5e --- /dev/null +++ b/kernel/arch/x86_64/execregs.c @@ -0,0 +1,156 @@ +/* $NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: execregs.c,v 1.1 2025/02/27 00:55:32 riastradh Exp $"); + +#include "execregs.h" + +#include <errno.h> +#include <spawn.h> +#include <stddef.h> +#include <unistd.h> + +extern char **environ; + +static unsigned long +nonnull(unsigned long x) +{ + + x |= x << 8; + x |= x << 16; + x |= x << 32; + return x; +} + +int +execregschild(char *path) +{ + /* rdi: used to pass exec arg0, nonnull anyway (path) */ + /* rsi: used to pass exec arg1, nonnull anyway (argv) */ + /* rdx: used to pass exec arg2, nonnull anyway (environ) */ + register long r10 __asm("r10") = nonnull(10); + register long r8 __asm("r8") = nonnull(8); + register long r9 __asm("r9") = nonnull(9); + register long rcx __asm("rcx") = nonnull('c'); + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + /* rbp: frame pointer, can't touch that here, but it'll be nonnull */ + /* rbx: ps_strings, passed to child */ + register long rax __asm("rax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r10), + "+r"(r8), + "+r"(r9), + "+r"(rcx), + "+r"(r11), + "+r"(r12), + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(rax) + :: "memory"); + + return execve(path, argv, envp); +} + +pid_t +spawnregschild(char *path, int fd) +{ + /* rdi: used to pass posix_spawn arg0, nonnull anyway (&pid) */ + /* rsi: used to pass posix_spawn arg1, nonnull anyway (path) */ + /* rdx: used to pass posix_spawn arg2, nonnull anyway (&fileacts) */ + register long r10 __asm("r10") = nonnull(10); + /* r8: used to pass posix_spawn arg4, nonnull anyway (argv) */ + /* r9: used to pass posix_spawn arg5, nonnull anyway (environ) */ + /* rcx: used to pass posix_spawn arg3, nonnull anyway (&attr) */ + register long r11 __asm("r11") = nonnull(11); + register long r12 __asm("r12") = nonnull(12); + register long r13 __asm("r13") = nonnull(13); + register long r14 __asm("r14") = nonnull(14); + register long r15 __asm("r15") = nonnull(15); + /* rbp: frame pointer, can't touch that here, but it'll be nonnull */ + /* rbx: ps_strings, passed to child */ + register long rax __asm("rax") = nonnull('a'); + + char *argv[] = {path, NULL}; + char **envp = environ; + posix_spawn_file_actions_t fileacts; + posix_spawnattr_t attr; + pid_t pid; + int error; + + error = posix_spawn_file_actions_init(&fileacts); + if (error) + goto out; + error = posix_spawn_file_actions_adddup2(&fileacts, fd, STDOUT_FILENO); + if (error) + goto out; + error = posix_spawnattr_init(&attr); + if (error) + goto out; + + /* + * Not perfect -- compiler might use some registers for + * stack/argument transfers, but all the arguments are nonnull + * so this is probably a good test anyway. + */ + __asm volatile("" : + "+r"(r10), + "+r"(r11), + "+r"(r12), + "+r"(r13), + "+r"(r14), + "+r"(r15), + "+r"(rax) + :: "memory"); + + error = posix_spawn(&pid, path, &fileacts, &attr, argv, envp); + if (error) + goto out; + +out: posix_spawnattr_destroy(&attr); + posix_spawn_file_actions_destroy(&fileacts); + if (error) { + errno = error; + return -1; + } + return 0; +} diff --git a/kernel/arch/x86_64/execregs.h b/kernel/arch/x86_64/execregs.h new file mode 100644 index 000000000000..904991777483 --- /dev/null +++ b/kernel/arch/x86_64/execregs.h @@ -0,0 +1,81 @@ +/* $NetBSD: execregs.h,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_X86_64_EXECREGS_H +#define TESTS_KERNEL_ARCH_X86_64_EXECREGS_H + +#include <sys/cdefs.h> + +#define NEXECREGS 14 + +#ifndef _LOCORE + +#include <unistd.h> + +/* + * Ordered by _FRAME_REG in sys/arch/amd64/include/frame_regs.h for + * convenience of auditing. Must match h_execregs.S. + */ +static const char *const regname[] = { + "rdi", + "rsi", + "rdx", + "r10", + "r8", + "r9", + /* arg6: syscall arg from stack, not a real register */ + /* arg7: syscall arg from stack, not a real register */ + /* arg8: syscall arg from stack, not a real register */ + /* arg9: syscall arg from stack, not a real register */ + "rcx", + "r11", + "r12", + "r13", + "r14", + "r15", + "rbp", + /* rbx: ps_strings */ + "rax", + /* gs/fs/es/ds: segment registers, not really registers */ + /* trapno: not a register */ + /* err: not a register */ + /* rip: instruction pointer */ + /* cs: segment register */ + /* rflags */ + /* rsp: stack pointer */ + /* ss: stack selector */ +}; + +__CTASSERT(NEXECREGS == __arraycount(regname)); + +int execregschild(char *); +pid_t spawnregschild(char *, int); + +#endif /* _LOCORE */ + +#endif /* TESTS_KERNEL_ARCH_X86_64_EXECREGS_H */ diff --git a/kernel/arch/x86_64/execsp.S b/kernel/arch/x86_64/execsp.S new file mode 100644 index 000000000000..d351dfb2d9e8 --- /dev/null +++ b/kernel/arch/x86_64/execsp.S @@ -0,0 +1,111 @@ +/* $NetBSD: execsp.S,v 1.2 2025/04/20 22:31:25 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: execsp.S,v 1.2 2025/04/20 22:31:25 riastradh Exp $") + +/* + * void execsp_start(void (*cleanup@rbx)(void), void *obj_main@rcx, + * struct ps_strings *ps_strings@rbx) + * + * ELF entry point. Saves the stack pointer in startsp and defers + * to the usual csu __start routine. + */ +ENTRY(execsp_start) + movq %rsp,_C_LABEL(startsp)(%rip) + /* + * No adjustment like in main because entry point is special + * and the amd64 csu __start routine takes care of it. + * + * XXX Why don't we just arrange to align it in the kernel + * anyway? + */ + jmp _C_LABEL(__start) +END(execsp_start) + +/* + * void execsp_ctor(void) + * + * ELF constructor. Saves the stack pointer in ctorsp and + * returns. + */ +ENTRY(execsp_ctor) + /* + * `The end of the input argument area shall be aligned on a + * [16-byte] boundary. In other words, the value of (%rsp + 8) + * is always a multiple of 16 when control is transferred to + * the function entry point.' + * + * To make it convenient for t_signal_and_sp.c, we subtract 8 + * from %rsp in order to get something congruent to zero modulo + * the stack alignemnt. + */ + movq %rsp,_C_LABEL(ctorsp)(%rip) + addq $-8,_C_LABEL(ctorsp)(%rip) + ret +END(execsp_ctor) + + /* Make execsp_ctor a constructor. */ + .section .ctors,"aw",@progbits + .p2align 3 + .quad _C_LABEL(execsp_ctor) + +/* + * int main(int argc@rdi, char **argv@rsi, ...) + * + * Main function. Saves the stack pointer in mainsp and returns + * zero. We will call execsp_main in execsp_dtor once dtorsp has + * been initialized. + */ +ENTRY(main) + movq %rsp,_C_LABEL(mainsp)(%rip) + addq $-8,_C_LABEL(mainsp)(%rip) + xorl %eax,%eax + ret +END(main) + +/* + * void execsp_dtor(void) + * + * ELF destructor. Saves the stack pointer in dtorsp and defers + * to the C execsp_main in h_execsp.c to report the stack pointers + * back to the t_signal_and_sp parent. + */ +ENTRY(execsp_dtor) + movq %rsp,_C_LABEL(dtorsp)(%rip) + addq $-8,_C_LABEL(dtorsp)(%rip) + jmp _C_LABEL(execsp_main) +END(execsp_dtor) + + /* Make execsp_ctor a destructor. */ + .section .dtors,"aw",@progbits + .p2align 3 + .quad _C_LABEL(execsp_dtor) diff --git a/kernel/arch/x86_64/h_execregs.S b/kernel/arch/x86_64/h_execregs.S new file mode 100644 index 000000000000..638f73940f06 --- /dev/null +++ b/kernel/arch/x86_64/h_execregs.S @@ -0,0 +1,82 @@ +/* $NetBSD: h_execregs.S,v 1.1 2025/02/27 00:55:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <sys/syscall.h> + +#include <machine/asm.h> + +#include "execregs.h" + +ENTRY(execregs_start) + andq $-0x10,%rsp /* align stack to 16-byte boundary */ + + /* store registers to a buffer on stack */ + subq $(NEXECREGS*8),%rsp /* space for NEXECREGS registers */ + movq %rdi,0*8(%rsp) /* order matches execregs.h */ + movq %rsi,1*8(%rsp) + movq %rdx,2*8(%rsp) + movq %r10,3*8(%rsp) + movq %r8,4*8(%rsp) + movq %r9,5*8(%rsp) + movq %rcx,6*8(%rsp) + movq %r11,7*8(%rsp) + movq %r12,8*8(%rsp) + movq %r13,9*8(%rsp) + movq %r14,10*8(%rsp) + movq %r15,11*8(%rsp) + movq %rbp,12*8(%rsp) + movq %rax,13*8(%rsp) + + /* call write(STDOUT_FILENO, regs, sizeof(regs)) */ + movl $0x1,%edi /* arg0 := STDOUT_FILENO */ + movq %rsp,%rsi /* arg1 := regs */ + movl $(NEXECREGS*8),%edx /* arg2 := sizeof(regs) */ + movl $SYS_write,%eax /* syscall number */ + syscall + + jb 2f /* bail if write failed */ + cmpq $(NEXECREGS*8),%rax /* bail if wrote wrong # of bytes */ + jne 2f + + /* call exit(0) */ + xorl %edi,%edi /* arg0 := 0 */ +1: movl $SYS_exit,%eax /* syscall number */ + syscall + hlt /* paranoia */ + +2: /* call exit(127) */ + movl $127,%edi /* arg0 := 127 */ + jmp 1b +END(execregs_start) + +/* main stub to simplify linking */ +ENTRY(main) + hlt +END(main) diff --git a/kernel/arch/x86_64/signalsphandler.S b/kernel/arch/x86_64/signalsphandler.S new file mode 100644 index 000000000000..b53cb005d0b0 --- /dev/null +++ b/kernel/arch/x86_64/signalsphandler.S @@ -0,0 +1,55 @@ +/* $NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:31:01 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: signalsphandler.S,v 1.1 2025/04/20 22:31:01 riastradh Exp $") + +/* + * signalsphandler(signo@rdi) + * + * Signal handler. Store the stack pointer on entry at the global + * variable signalsp and return. + */ +ENTRY(signalsphandler) + /* + * `The end of the input argument area shall be aligned on a + * [16-byte] boundary. In other words, the value of (%rsp + 8) + * is always a multiple of 16 when control is transferred to + * the function entry point.' + * + * To make it convenient for t_signal_and_sp.c, we subtract 8 + * from %rsp in order to get something congruent to zero modulo + * the stack alignemnt. + */ + movq %rsp,_C_LABEL(signalsp)(%rip) + addq $-8,_C_LABEL(signalsp)(%rip) + ret +END(signalsphandler) diff --git a/kernel/arch/x86_64/stack_pointer.h b/kernel/arch/x86_64/stack_pointer.h new file mode 100644 index 000000000000..6ea297cf97d9 --- /dev/null +++ b/kernel/arch/x86_64/stack_pointer.h @@ -0,0 +1,35 @@ +/* $NetBSD: stack_pointer.h,v 1.1 2025/04/20 22:31:01 riastradh Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_ARCH_X86_64_STACK_POINTER_H +#define TESTS_KERNEL_ARCH_X86_64_STACK_POINTER_H + +#define MISALIGN_SP __asm __volatile("addq $-1,%rsp") +#define FIX_SP __asm __volatile("addq $1,%rsp") + +#endif /* TESTS_KERNEL_ARCH_X86_64_STACK_POINTER_H */ diff --git a/kernel/arch/x86_64/threadspfunc.S b/kernel/arch/x86_64/threadspfunc.S new file mode 100644 index 000000000000..c939f36b408a --- /dev/null +++ b/kernel/arch/x86_64/threadspfunc.S @@ -0,0 +1,54 @@ +/* $NetBSD: threadspfunc.S,v 1.2 2025/04/21 12:06:08 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _LOCORE + +#include <machine/asm.h> + +RCSID("$NetBSD: threadspfunc.S,v 1.2 2025/04/21 12:06:08 riastradh Exp $") + +/* + * void *threadspfunc(void *cookie@rdi) + * + * pthread_create(3) function. Return the stack pointer on entry. + */ +ENTRY(threadspfunc) + /* + * `The end of the input argument area shall be aligned on a + * [16-byte] boundary. In other words, the value of (%rsp + 8) + * is always a multiple of 16 when control is transferred to + * the function entry point.' + * + * To make it convenient for t_signal_and_sp.c, we subtract 8 + * from %rsp in order to get something congruent to zero modulo + * the stack alignemnt. + */ + movq %rsp,%rax + addq $-8,%rax + ret +END(threadspfunc) diff --git a/kernel/h_cloexec.c b/kernel/h_cloexec.c new file mode 100644 index 000000000000..55ca4978497f --- /dev/null +++ b/kernel/h_cloexec.c @@ -0,0 +1,48 @@ +/* $NetBSD: h_cloexec.c,v 1.1 2024/11/10 15:57:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_cloexec.c,v 1.1 2024/11/10 15:57:32 riastradh Exp $"); + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> + +int +main(int argc, char **argv) +{ + int fd = atoi(argv[1]); + int flags; + + if (fcntl(fd, F_GETFL, &flags) == 0) + return 1; + if (errno != EBADF) + return 2; + return 0; +} diff --git a/kernel/h_execregs_unimpl.c b/kernel/h_execregs_unimpl.c new file mode 100644 index 000000000000..606781a2f745 --- /dev/null +++ b/kernel/h_execregs_unimpl.c @@ -0,0 +1,37 @@ +/* $NetBSD: h_execregs_unimpl.c,v 1.1 2025/02/27 00:55:31 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_execregs_unimpl.c,v 1.1 2025/02/27 00:55:31 riastradh Exp $"); + +int +main(void) +{ + + return 127; +} diff --git a/kernel/h_execsp.c b/kernel/h_execsp.c new file mode 100644 index 000000000000..dac1919e4417 --- /dev/null +++ b/kernel/h_execsp.c @@ -0,0 +1,68 @@ +/* $NetBSD: h_execsp.c,v 1.2 2025/04/20 22:31:25 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_execsp.c,v 1.2 2025/04/20 22:31:25 riastradh Exp $"); + +#include <err.h> +#include <string.h> +#include <unistd.h> + +#include "h_execsp.h" + +/* + * The machine-dependent execsp.S assembly routines will initialize + * startsp, ctorsp, mainsp, and dtorsp, and then call execsp_main on + * program startup. + */ +void *startsp; +void *ctorsp; +void *mainsp; +void *dtorsp; + +int execsp_main(void); +int +execsp_main(void) +{ + struct execsp execsp; + ssize_t nwrit; + + memset(&execsp, 0, sizeof(execsp)); + execsp.startsp = startsp; + execsp.ctorsp = ctorsp; + execsp.mainsp = mainsp; + execsp.dtorsp = dtorsp; + + nwrit = write(STDOUT_FILENO, &execsp, sizeof(execsp)); + if (nwrit == -1) + err(1, "write"); + if ((size_t)nwrit != sizeof(execsp)) + errx(1, "wrote %zu != %zu", (size_t)nwrit, sizeof(execsp)); + + return 0; +} diff --git a/kernel/h_execsp.h b/kernel/h_execsp.h new file mode 100644 index 000000000000..e94ceaab9c1b --- /dev/null +++ b/kernel/h_execsp.h @@ -0,0 +1,47 @@ +/* $NetBSD: h_execsp.h,v 1.2 2025/04/20 22:31:25 riastradh Exp $ */ + +/* + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_KERNEL_H_EXECSP_H +#define TESTS_KERNEL_H_EXECSP_H + +/* + * struct execsp + * + * Structure passed from the h_execsp_* programs to the + * t_signal_and_sp test, giving the stack pointer as it was at the + * ELF entry point, an ELF constructor, the main function, and an + * ELF destructor. + */ +struct execsp { + void *startsp; + void *ctorsp; + void *mainsp; + void *dtorsp; +}; + +#endif /* TESTS_KERNEL_H_EXECSP_H */ diff --git a/kernel/setjmp_tester/Makefile b/kernel/setjmp_tester/Makefile new file mode 100644 index 000000000000..18492f35fd4a --- /dev/null +++ b/kernel/setjmp_tester/Makefile @@ -0,0 +1,12 @@ +# $NetBSD: Makefile,v 1.1 2025/04/27 16:22:26 riastradh Exp $ + +KMOD= setjmp_tester +KMODULEDIR= ${TESTSBASE}/kernel/${KMOD} + +SRCS= setjmp_tester.c + +ATFFILE= no +NOMAN= # defined + +.include <bsd.test.mk> +.include <bsd.kmodule.mk> diff --git a/kernel/setjmp_tester/setjmp_tester.c b/kernel/setjmp_tester/setjmp_tester.c new file mode 100644 index 000000000000..8b15b840effe --- /dev/null +++ b/kernel/setjmp_tester/setjmp_tester.c @@ -0,0 +1,147 @@ +/* $NetBSD: setjmp_tester.c,v 1.1 2025/04/27 16:22:26 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: setjmp_tester.c,v 1.1 2025/04/27 16:22:26 riastradh Exp $"); + +#include <sys/module.h> +#include <sys/sysctl.h> +#include <sys/systm.h> + +MODULE(MODULE_CLASS_MISC, setjmp_tester, NULL); + +static struct sysctllog *setjmp_tester_sysctllog; +static const struct sysctlnode *setjmp_tester_sysctlnode; +static kmutex_t setjmp_tester_lock; +static bool setjmp_tester_done; +static label_t setjmp_tester_label; + +__noinline +static void +setjmp_tester_subroutine(void) +{ + + printf("%s: call longjmp\n", __func__); + setjmp_tester_done = true; + longjmp(&setjmp_tester_label); + printf("%s: unreachable\n", __func__); +} + +static int +setjmp_tester_test(void) +{ + int result; + + mutex_enter(&setjmp_tester_lock); + + setjmp_tester_done = false; + result = setjmp(&setjmp_tester_label); + if (!setjmp_tester_done) { + printf("%s: setjmp returned %d at first\n", __func__, result); + if (result != 0) { + result = -1; + goto out; + } + setjmp_tester_subroutine(); + /*NOTREACHED*/ + printf("%s: setjmp_tester_subroutine returned\n", __func__); + result = -1; + } else { + printf("%s: setjmp returned %d at second\n", __func__, result); + if (result == 0) { + result = -2; + goto out; + } + } + +out: mutex_exit(&setjmp_tester_lock); + return result; +} + +static int +setjmp_tester_test_sysctl(SYSCTLFN_ARGS) +{ + struct sysctlnode node = *rnode; + int v = 0; + int error; + + if (newp == NULL) { + error = ENOENT; + goto out; + } + error = sysctl_copyin(curlwp, newp, &v, sizeof(v)); + if (error) + goto out; + switch (v) { + case 1: + v = setjmp_tester_test(); + break; + default: + error = EINVAL; + break; + } + node.sysctl_data = &v; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + +out: return error; +} + +static int +setjmp_tester_modcmd(modcmd_t cmd, void *arg) +{ + int error = 0; + + switch (cmd) { + case MODULE_CMD_INIT: + mutex_init(&setjmp_tester_lock, MUTEX_DEFAULT, IPL_NONE); + error = sysctl_createv(&setjmp_tester_sysctllog, 0, + NULL, &setjmp_tester_sysctlnode, + CTLFLAG_PERMANENT, CTLTYPE_NODE, "setjmp_tester", + SYSCTL_DESCR("setjmp/longjmp testing interface"), + NULL, 0, NULL, 0, + CTL_KERN, CTL_CREATE, CTL_EOL); + if (error) + goto fini; + error = sysctl_createv(&setjmp_tester_sysctllog, 0, + &setjmp_tester_sysctlnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "test", + SYSCTL_DESCR("setjmp/longjmp test trigger"), + &setjmp_tester_test_sysctl, 0, NULL, 0, + CTL_CREATE, CTL_EOL); + if (error) + goto fini; + return error; + case MODULE_CMD_FINI: + fini: + sysctl_teardown(&setjmp_tester_sysctllog); + mutex_destroy(&setjmp_tester_lock); + return error; + default: + return ENOTTY; + } +} diff --git a/kernel/t_cloexec.c b/kernel/t_cloexec.c new file mode 100644 index 000000000000..c0150af8ca38 --- /dev/null +++ b/kernel/t_cloexec.c @@ -0,0 +1,457 @@ +/* $NetBSD: t_cloexec.c,v 1.1 2024/11/10 15:57:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_cloexec.c,v 1.1 2024/11/10 15:57:32 riastradh Exp $"); + +#include <sys/types.h> + +#include <sys/bitops.h> +#include <sys/event.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <limits.h> +#include <spawn.h> +#include <stdio.h> +#include <unistd.h> + +#include "h_macros.h" + +/* + * Test close-on-exec as set in various ways + */ + +static int +open_via_accept4(void) +{ + static const union { + struct sockaddr sa; + struct sockaddr_un sun; + } name = { .sun = { + .sun_family = AF_LOCAL, + .sun_path = "socket", + } }; + int slisten, saccept, c; + + /* + * Create a listening server socket and bind it to the path. + */ + RL(slisten = socket(PF_LOCAL, SOCK_STREAM, 0)); + RL(bind(slisten, &name.sa, sizeof(name))); + RL(listen(slisten, SOMAXCONN)); + + /* + * Create an active client socket and connect it to the path -- + * nonblocking, so we don't deadlock here. If connect doesn't + * succeed immediately, it had better fail immediately with + * EINPROGRESS. + */ + RL(c = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0)); + if (connect(c, &name.sa, sizeof(name)) == -1) { + ATF_CHECK_EQ_MSG(errno, EINPROGRESS, "connect failed %d: %s", + errno, strerror(errno)); + } + + /* + * Accept a socket on the server side with SOCK_CLOEXEC. + */ + RL(saccept = accept4(slisten, /*addr*/NULL, /*addrlen*/NULL, + SOCK_CLOEXEC)); + return saccept; +} + +static int +open_via_clonedev(void) +{ + int fd; + + RL(fd = open("/dev/drvctl", O_RDONLY|O_CLOEXEC)); + + return fd; +} + +static int +open_via_dup3(void) +{ + int fd3; + + RL(fd3 = dup3(STDIN_FILENO, 3, O_CLOEXEC)); + ATF_REQUIRE_EQ_MSG(fd3, 3, "dup3(STDIN_FILENO, 3, ...)" + " failed to return 3: %d", fd3); + + return fd3; +} + +static int +open_via_fcntldupfd(void) +{ + int fd; + + RL(fd = fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC, 0)); + + return fd; +} + +static int +open_via_kqueue(void) +{ + int fd; + + RL(fd = kqueue1(O_CLOEXEC)); + + return fd; +} + +static int +open_via_opencloexec(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT|O_CLOEXEC, 0644)); + + return fd; +} + +static int +open_via_openfcntlcloexec(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT, 0644)); + RL(fcntl(fd, F_SETFD, FD_CLOEXEC)); + + return fd; +} + +static int +open_via_openioctlfioclex(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT, 0644)); + RL(ioctl(fd, FIOCLEX)); + + return fd; +} + +static int +open_via_pipe2rd(void) +{ + int fd[2]; + + RL(pipe2(fd, O_CLOEXEC)); + + return fd[0]; +} + +static int +open_via_pipe2wr(void) +{ + int fd[2]; + + RL(pipe2(fd, O_CLOEXEC)); + + return fd[1]; +} + +static int +open_via_paccept(void) +{ + static const union { + struct sockaddr sa; + struct sockaddr_un sun; + } name = { .sun = { + .sun_family = AF_LOCAL, + .sun_path = "socket", + } }; + int slisten, saccept, c; + + /* + * Create a listening server socket and bind it to the path. + */ + RL(slisten = socket(PF_LOCAL, SOCK_STREAM, 0)); + RL(bind(slisten, &name.sa, sizeof(name))); + RL(listen(slisten, SOMAXCONN)); + + /* + * Create an active client socket and connect it to the path -- + * nonblocking, so we don't deadlock here. If connect doesn't + * succeed immediately, it had better fail immediately with + * EINPROGRESS. + */ + RL(c = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0)); + if (connect(c, &name.sa, sizeof(name)) == -1) { + ATF_CHECK_EQ_MSG(errno, EINPROGRESS, "connect failed %d: %s", + errno, strerror(errno)); + } + + /* + * Accept a socket on the server side with SOCK_CLOEXEC. + */ + RL(saccept = paccept(slisten, /*addr*/NULL, /*addrlen*/NULL, + /*sigmask*/NULL, SOCK_CLOEXEC)); + return saccept; +} + +static int +open_via_socket(void) +{ + int fd; + + RL(fd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0)); + + return fd; +} + +static int +open_via_socketpair0(void) +{ + int fd[2]; + + RL(socketpair(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0, fd)); + + return fd[0]; +} + +static int +open_via_socketpair1(void) +{ + int fd[2]; + + RL(socketpair(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0, fd)); + + return fd[1]; +} + +/* + * XXX Close-on-exec paths still missing: + * XXX + * XXX compat_linux inotify + * XXX compat_linux close_range + * XXX drm i915_perf_open_ioctl + * XXX drm dma_buf + * XXX eventfd(2) + * XXX memfd(2) + * XXX timerfd(2) + * XXX recvmsg/recvmmsg with MSG_CMSG_CLOEXEC + */ + +static void +check_cloexec(const struct atf_tc *tc, int fd, + pid_t (*execfn)(char *, char *const[])) +{ + char h_cloexec[PATH_MAX]; + char fdstr[(ilog2(INT_MAX) + 1)/(ilog2(10) - 1) + 1]; + char *const argv[] = {__UNCONST("h_cloexec"), fdstr, NULL}; + pid_t child, waitedpid; + int status; + + /* + * Format the h_cloexec helper executable path, which lives in + * the test's directory (typically /usr/tests/kernel), and the + * argument of a file descriptor in decimal. + */ + snprintf(h_cloexec, sizeof(h_cloexec), "%s/h_cloexec", + atf_tc_get_config_var(tc, "srcdir")); + snprintf(fdstr, sizeof(fdstr), "%d", fd); + + /* + * Execute h_cloexec as a subprocess. + */ + child = (*execfn)(h_cloexec, argv); + + /* + * Wait for the child to complete. + */ + RL(waitedpid = waitpid(child, &status, 0)); + ATF_CHECK_EQ_MSG(child, waitedpid, "waited for %jd, got %jd", + (intmax_t)child, (intmax_t)waitedpid); + + /* + * Verify the child exited normally. + */ + if (WIFSIGNALED(status)) { + atf_tc_fail("subprocess terminated on signal %d", + WTERMSIG(status)); + return; + } else if (!WIFEXITED(status)) { + atf_tc_fail("subprocess failed to exit normally: status=0x%x", + status); + return; + } + + /* + * h_cloexec is supposed to exit status 0 if an operation on + * the fd failed with EBADFD, 1 if it unexpectedly succeeded, + * 127 if exec returned, or something else if anything else + * happened. + */ + switch (WEXITSTATUS(status)) { + case 0: /* success -- closed on exec */ + return; + case 1: /* fail -- not closed on exec */ + atf_tc_fail("fd was not closed on exec"); + return; + case 127: /* exec failed */ + atf_tc_fail("failed to exec h_cloexec"); + return; + default: /* something else went wong */ + atf_tc_fail("h_cloexec failed unexpectedly: %d", + WEXITSTATUS(status)); + return; + } +} + +static pid_t +exec_via_forkexecve(char *prog, char *const argv[]) +{ + pid_t pid; + + RL(pid = fork()); + if (pid == 0) { /* child */ + if (execve(prog, argv, /*envp*/NULL) == -1) + _exit(127); + abort(); + } + + /* parent */ + return pid; +} + +static pid_t +exec_via_vforkexecve(char *prog, char *const argv[]) +{ + pid_t pid; + + RL(pid = vfork()); + if (pid == 0) { /* child */ + if (execve(prog, argv, /*envp*/NULL) == -1) + _exit(127); + abort(); + } + + /* parent */ + return pid; +} + +static pid_t +exec_via_posixspawn(char *prog, char *const argv[]) +{ + pid_t pid; + + RZ(posix_spawn(&pid, prog, /*file_actions*/NULL, /*attrp*/NULL, argv, + /*envp*/NULL)); + + return pid; +} + +/* + * Full cartesian product is not really important here -- the paths for + * open and the paths for exec are independent. So we try + * pipe2(O_CLOEXEC) with each exec path, and we try each open path with + * posix_spawn. + */ + +#define CLOEXEC_TEST(test, openvia, execvia, descr) \ +ATF_TC(test); \ +ATF_TC_HEAD(test, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", descr); \ +} \ +ATF_TC_BODY(test, tc) \ +{ \ + check_cloexec(tc, openvia(), &execvia); \ +} + +CLOEXEC_TEST(pipe2rd_forkexecve, open_via_pipe2rd, exec_via_forkexecve, + "pipe2(O_CLOEXEC) reader is closed in child on fork/exec") +CLOEXEC_TEST(pipe2rd_vforkexecve, open_via_pipe2rd, exec_via_vforkexecve, + "pipe2(O_CLOEXEC) reader is closed in child on vfork/exec") +CLOEXEC_TEST(pipe2rd_posixspawn, open_via_pipe2rd, exec_via_posixspawn, + "pipe2(O_CLOEXEC) reader is closed in child on posix_spawn") + +CLOEXEC_TEST(accept4_posixspawn, open_via_accept4, exec_via_posixspawn, + "accept4(SOCK_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(clonedev_posixspawn, open_via_clonedev, exec_via_posixspawn, + "open(\"/dev/drvctl\") is closed in child on posix_spawn"); +CLOEXEC_TEST(dup3_posixspawn, open_via_dup3, exec_via_posixspawn, + "dup3(..., O_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(fcntldupfd_posixspawn, open_via_fcntldupfd, exec_via_posixspawn, + "fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(kqueue_posixspawn, open_via_kqueue, exec_via_posixspawn, + "kqueue1(O_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(opencloexec_posixspawn, open_via_opencloexec, exec_via_posixspawn, + "open(O_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(openfcntlcloexec_posixspawn, open_via_openfcntlcloexec, + exec_via_posixspawn, + "fcntl(open(...), F_SETFD, O_CLOEXEC) is closed in child on posix_spawn"); +CLOEXEC_TEST(openioctlfioclex_posixspawn, open_via_openioctlfioclex, + exec_via_posixspawn, + "ioctl(open(...), FIOCLEX) is closed in child on posix_spawn"); +#if 0 /* already done above */ +CLOEXEC_TEST(pipe2rd_posixspawn, open_via_pipe2rd, exec_via_posixspawn, + "pipe2(O_CLOEXEC) reader is closed in child on posix_spawn") +#endif +CLOEXEC_TEST(pipe2wr_posixspawn, open_via_pipe2wr, exec_via_posixspawn, + "pipe2(O_CLOEXEC) writer is closed in child on posix_spawn") +CLOEXEC_TEST(paccept_posixspawn, open_via_paccept, exec_via_posixspawn, + "paccept(..., SOCK_CLOEXEC) is closed in child on posix_spawn") +CLOEXEC_TEST(socket_posixspawn, open_via_socket, exec_via_posixspawn, + "socket(SOCK_CLOEXEC) is closed in child on posix_spawn") +CLOEXEC_TEST(socketpair0_posixspawn, open_via_socketpair0, exec_via_posixspawn, + "socketpair(SOCK_CLOEXEC) side 0 is closed in child on posix_spawn") +CLOEXEC_TEST(socketpair1_posixspawn, open_via_socketpair1, exec_via_posixspawn, + "socketpair(SOCK_CLOEXEC) side 1 is closed in child on posix_spawn") + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, accept4_posixspawn); + ATF_TP_ADD_TC(tp, clonedev_posixspawn); + ATF_TP_ADD_TC(tp, dup3_posixspawn); + ATF_TP_ADD_TC(tp, fcntldupfd_posixspawn); + ATF_TP_ADD_TC(tp, kqueue_posixspawn); + ATF_TP_ADD_TC(tp, opencloexec_posixspawn); + ATF_TP_ADD_TC(tp, openfcntlcloexec_posixspawn); + ATF_TP_ADD_TC(tp, openioctlfioclex_posixspawn); + ATF_TP_ADD_TC(tp, paccept_posixspawn); + ATF_TP_ADD_TC(tp, pipe2rd_forkexecve); + ATF_TP_ADD_TC(tp, pipe2rd_posixspawn); + ATF_TP_ADD_TC(tp, pipe2rd_vforkexecve); + ATF_TP_ADD_TC(tp, pipe2wr_posixspawn); + ATF_TP_ADD_TC(tp, socket_posixspawn); + ATF_TP_ADD_TC(tp, socketpair0_posixspawn); + ATF_TP_ADD_TC(tp, socketpair1_posixspawn); + + return atf_no_error(); +} diff --git a/kernel/t_clofork.c b/kernel/t_clofork.c new file mode 100644 index 000000000000..9c1ba81c733a --- /dev/null +++ b/kernel/t_clofork.c @@ -0,0 +1,445 @@ +/* $NetBSD: t_clofork.c,v 1.1 2025/07/17 19:50:40 kre Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* Adapted from t_cloexec.c */ + +#include <sys/cdefs.h> + +#include <sys/types.h> + +#include <sys/bitops.h> +#include <sys/event.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <limits.h> +#include <spawn.h> +#include <stdio.h> +#include <unistd.h> + +#include "h_macros.h" + +#if defined(O_CLOFORK) && O_CLOFORK != 0 +/* + * Test close-on-fork as set in various ways + */ + +static int +open_via_accept4(void) +{ + static const union { + struct sockaddr sa; + struct sockaddr_un sun; + } name = { .sun = { + .sun_family = AF_LOCAL, + .sun_path = "socket", + } }; + int slisten, saccept, c; + + /* + * Create a listening server socket and bind it to the path. + */ + RL(slisten = socket(PF_LOCAL, SOCK_STREAM, 0)); + RL(bind(slisten, &name.sa, sizeof(name))); + RL(listen(slisten, SOMAXCONN)); + + /* + * Create an active client socket and connect it to the path -- + * nonblocking, so we don't deadlock here. If connect doesn't + * succeed immediately, it had better fail immediately with + * EINPROGRESS. + */ + RL(c = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0)); + if (connect(c, &name.sa, sizeof(name)) == -1) { + ATF_CHECK_EQ_MSG(errno, EINPROGRESS, "connect failed %d: %s", + errno, strerror(errno)); + } + + /* + * Accept a socket on the server side with SOCK_CLOFORK. + */ + RL(saccept = accept4(slisten, /*addr*/NULL, /*addrlen*/NULL, + SOCK_CLOFORK)); + return saccept; +} + +static int +open_via_clonedev(void) +{ + int fd; + + RL(fd = open("/dev/drvctl", O_RDONLY|O_CLOFORK)); + + return fd; +} + +static int +open_via_dup3(void) +{ + int fd3; + + RL(fd3 = dup3(STDIN_FILENO, 3, O_CLOFORK)); + ATF_REQUIRE_EQ_MSG(fd3, 3, "dup3(STDIN_FILENO, 3, ...)" + " failed to return 3: %d", fd3); + + return fd3; +} + +static int +open_via_fcntldupfd(void) +{ + int fd; + + RL(fd = fcntl(STDIN_FILENO, F_DUPFD_CLOFORK, 0)); + + return fd; +} + +static int +open_via_kqueue(void) +{ + int fd; + + RL(fd = kqueue1(O_CLOFORK)); + + return fd; +} + +static int +open_via_openclofork(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT|O_CLOFORK, 0644)); + + return fd; +} + +static int +open_via_openfcntlclofork(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT, 0644)); + RL(fcntl(fd, F_SETFD, FD_CLOFORK)); + + return fd; +} + +static int +open_via_pipe2rd(void) +{ + int fd[2]; + + RL(pipe2(fd, O_CLOFORK)); + + return fd[0]; +} + +static int +open_via_pipe2wr(void) +{ + int fd[2]; + + RL(pipe2(fd, O_CLOFORK)); + + return fd[1]; +} + +static int +open_via_paccept(void) +{ + static const union { + struct sockaddr sa; + struct sockaddr_un sun; + } name = { .sun = { + .sun_family = AF_LOCAL, + .sun_path = "socket", + } }; + int slisten, saccept, c; + + /* + * Create a listening server socket and bind it to the path. + */ + RL(slisten = socket(PF_LOCAL, SOCK_STREAM, 0)); + RL(bind(slisten, &name.sa, sizeof(name))); + RL(listen(slisten, SOMAXCONN)); + + /* + * Create an active client socket and connect it to the path -- + * nonblocking, so we don't deadlock here. If connect doesn't + * succeed immediately, it had better fail immediately with + * EINPROGRESS. + */ + RL(c = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0)); + if (connect(c, &name.sa, sizeof(name)) == -1) { + ATF_CHECK_EQ_MSG(errno, EINPROGRESS, "connect failed %d: %s", + errno, strerror(errno)); + } + + /* + * Accept a socket on the server side with SOCK_CLOFORK. + */ + RL(saccept = paccept(slisten, /*addr*/NULL, /*addrlen*/NULL, + /*sigmask*/NULL, SOCK_CLOFORK)); + return saccept; +} + +static int +open_via_socket(void) +{ + int fd; + + RL(fd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOFORK, 0)); + + return fd; +} + +static int +open_via_socketpair0(void) +{ + int fd[2]; + + RL(socketpair(PF_LOCAL, SOCK_STREAM|SOCK_CLOFORK, 0, fd)); + + return fd[0]; +} + +static int +open_via_socketpair1(void) +{ + int fd[2]; + + RL(socketpair(PF_LOCAL, SOCK_STREAM|SOCK_CLOFORK, 0, fd)); + + return fd[1]; +} + +static void +check_clofork(const struct atf_tc *tc, int fd, + pid_t (*execfn)(char *, char *const[])) +{ + char h_clofork[PATH_MAX]; + char fdstr[(ilog2(INT_MAX) + 1)/(ilog2(10) - 1) + 1]; + char *const argv[] = {__UNCONST("h_cloexec"), fdstr, NULL}; + pid_t child, waitedpid; + int status; + + /* + * Format the h_clofork helper executable path, which lives in + * the test's directory (typically /usr/tests/kernel), and the + * argument of a file descriptor in decimal. + */ + snprintf(h_clofork, sizeof(h_clofork), "%s/h_cloexec", + atf_tc_get_config_var(tc, "srcdir")); + snprintf(fdstr, sizeof(fdstr), "%d", fd); + + /* + * Execute h_clofork as a subprocess. + */ + child = (*execfn)(h_clofork, argv); + + /* + * Wait for the child to complete. + */ + RL(waitedpid = waitpid(child, &status, 0)); + ATF_CHECK_EQ_MSG(child, waitedpid, "waited for %jd, got %jd", + (intmax_t)child, (intmax_t)waitedpid); + + /* + * Verify the child exited normally. + */ + if (WIFSIGNALED(status)) { + atf_tc_fail("subprocess terminated on signal %d", + WTERMSIG(status)); + return; + } else if (!WIFEXITED(status)) { + atf_tc_fail("subprocess failed to exit normally: status=0x%x", + status); + return; + } + + /* + * h_clofork is supposed to exit status 0 if an operation on + * the fd failed with EBADFD, 1 if it unexpectedly succeeded, + * 127 if exec returned, or something else if anything else + * happened. + */ + switch (WEXITSTATUS(status)) { + case 0: /* success -- closed on exec */ + return; + case 1: /* fail -- not closed on exec */ + atf_tc_fail("fd was not closed on exec"); + return; + case 127: /* exec failed */ + atf_tc_fail("failed to exec h_cloexec"); + return; + default: /* something else went wong */ + atf_tc_fail("h_cloexec failed unexpectedly: %d", + WEXITSTATUS(status)); + return; + } +} + +static pid_t +exec_via_forkexecve(char *prog, char *const argv[]) +{ + pid_t pid; + + RL(pid = fork()); + if (pid == 0) { /* child */ + if (execve(prog, argv, /*envp*/NULL) == -1) + _exit(127); + abort(); + } + + /* parent */ + return pid; +} + +static pid_t +exec_via_vforkexecve(char *prog, char *const argv[]) +{ + pid_t pid; + + RL(pid = vfork()); + if (pid == 0) { /* child */ + if (execve(prog, argv, /*envp*/NULL) == -1) + _exit(127); + abort(); + } + + /* parent */ + return pid; +} + +static pid_t +exec_via_posixspawn(char *prog, char *const argv[]) +{ + pid_t pid; + + RZ(posix_spawn(&pid, prog, /*file_actions*/NULL, /*attrp*/NULL, argv, + /*envp*/NULL)); + + return pid; +} + +/* + * Full cartesian product is not really important here -- the paths for + * open and the paths for exec are independent. So we try + * pipe2(O_CLOFORK) with each exec path, and we try each open path with + * posix_spawn. + */ + +#define CLOFORK_TEST(test, openvia, execvia, descr) \ +ATF_TC(test); \ +ATF_TC_HEAD(test, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", descr); \ +} \ +ATF_TC_BODY(test, tc) \ +{ \ + check_clofork(tc, openvia(), &execvia); \ +} + +CLOFORK_TEST(pipe2rd_forkexecve, open_via_pipe2rd, exec_via_forkexecve, + "pipe2(O_CLOFORK) reader is closed in child on fork/exec") +CLOFORK_TEST(pipe2rd_vforkexecve, open_via_pipe2rd, exec_via_vforkexecve, + "pipe2(O_CLOFORK) reader is closed in child on vfork/exec") +CLOFORK_TEST(pipe2rd_posixspawn, open_via_pipe2rd, exec_via_posixspawn, + "pipe2(O_CLOFORK) reader is closed in child on posix_spawn") + +CLOFORK_TEST(accept4_posixspawn, open_via_accept4, exec_via_posixspawn, + "accept4(SOCK_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(clonedev_posixspawn, open_via_clonedev, exec_via_posixspawn, + "open(\"/dev/drvctl\") is closed in child on posix_spawn"); +CLOFORK_TEST(dup3_posixspawn, open_via_dup3, exec_via_posixspawn, + "dup3(..., O_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(fcntldupfd_posixspawn, open_via_fcntldupfd, exec_via_posixspawn, + "fcntl(STDIN_FILENO, F_DUPFD_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(kqueue_posixspawn, open_via_kqueue, exec_via_posixspawn, + "kqueue1(O_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(openclofork_posixspawn, open_via_openclofork, exec_via_posixspawn, + "open(O_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(openfcntlclofork_posixspawn, open_via_openfcntlclofork, + exec_via_posixspawn, + "fcntl(open(...), F_SETFD, O_CLOFORK) is closed in child on posix_spawn"); +CLOFORK_TEST(pipe2wr_posixspawn, open_via_pipe2wr, exec_via_posixspawn, + "pipe2(O_CLOFORK) writer is closed in child on posix_spawn") +CLOFORK_TEST(paccept_posixspawn, open_via_paccept, exec_via_posixspawn, + "paccept(..., SOCK_CLOFORK) is closed in child on posix_spawn") +CLOFORK_TEST(socket_posixspawn, open_via_socket, exec_via_posixspawn, + "socket(SOCK_CLOFORK) is closed in child on posix_spawn") +CLOFORK_TEST(socketpair0_posixspawn, open_via_socketpair0, exec_via_posixspawn, + "socketpair(SOCK_CLOFORK) side 0 is closed in child on posix_spawn") +CLOFORK_TEST(socketpair1_posixspawn, open_via_socketpair1, exec_via_posixspawn, + "socketpair(SOCK_CLOFORK) side 1 is closed in child on posix_spawn") + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, accept4_posixspawn); + ATF_TP_ADD_TC(tp, clonedev_posixspawn); + ATF_TP_ADD_TC(tp, dup3_posixspawn); + ATF_TP_ADD_TC(tp, fcntldupfd_posixspawn); + ATF_TP_ADD_TC(tp, kqueue_posixspawn); + ATF_TP_ADD_TC(tp, openclofork_posixspawn); + ATF_TP_ADD_TC(tp, openfcntlclofork_posixspawn); + ATF_TP_ADD_TC(tp, paccept_posixspawn); + ATF_TP_ADD_TC(tp, pipe2rd_forkexecve); + ATF_TP_ADD_TC(tp, pipe2rd_posixspawn); + ATF_TP_ADD_TC(tp, pipe2rd_vforkexecve); + ATF_TP_ADD_TC(tp, pipe2wr_posixspawn); + ATF_TP_ADD_TC(tp, socket_posixspawn); + ATF_TP_ADD_TC(tp, socketpair0_posixspawn); + ATF_TP_ADD_TC(tp, socketpair1_posixspawn); + + return atf_no_error(); +} + +#else /* No O_CLOFORK */ + +ATF_TC(not_implemented); +ATF_TC_HEAD(not_implemented, tc) +{ + atf_tc_set_md_var(tc, "descr", "Unimplemented O_CLOFORK"); +} +ATF_TC_BODY(not_implemented, tc) +{ + atf_tc_skip("close-on-fork not yet available"); +} +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, not_implemented); + + return atf_no_error(); +} +#endif diff --git a/kernel/t_execregs.c b/kernel/t_execregs.c new file mode 100644 index 000000000000..076a8de9547c --- /dev/null +++ b/kernel/t_execregs.c @@ -0,0 +1,197 @@ +/* $NetBSD: t_execregs.c,v 1.7 2025/04/27 14:30:03 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_execregs.c,v 1.7 2025/04/27 14:30:03 riastradh Exp $"); + +#include <sys/wait.h> + +#include <atf-c.h> +#include <err.h> +#include <inttypes.h> +#include <limits.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#ifdef HAVE_EXECREGS_TEST + +#include "execregs.h" +#include "isqemu.h" +#include "h_macros.h" + +static void +readregs(int rfd, register_t regs[static NEXECREGS]) +{ + uint8_t *p; + size_t n; + ssize_t nread; + + p = (void *)regs; + n = NEXECREGS*sizeof(regs[0]); + while (n) { + RL(nread = read(rfd, p, n)); + ATF_CHECK_MSG((size_t)nread <= n, + "overlong read: %zu > %zu", (size_t)nread, n); + if (nread == 0) + break; + p += (size_t)nread; + n -= (size_t)nread; + } + ATF_CHECK_EQ_MSG(n, 0, + "truncated read, missing %zu of %zu bytes", + n, NEXECREGS*sizeof(regs[0])); +} + +static void +checkregs(const register_t regs[static NEXECREGS]) +{ + unsigned i; + +#ifdef __hppa__ + if (isQEMU()) { + atf_tc_expect_fail("PR port-hppa/59114: hppa:" + " eager fpu switching for qemu and/or spectre mitigation"); + } +#endif + + for (i = 0; i < NEXECREGS; i++) { + if (regs[i] != 0) { + for (i = 0; i < NEXECREGS; i++) { + fprintf(stderr, "[%s] %"PRIxREGISTER"\n", + regname[i], regs[i]); + } + fprintf(stderr, "\n"); + atf_tc_fail("registers not zeroed"); + } + } +} + +static void +testregs(int child, const int pipefd[static 2], + register_t regs[static NEXECREGS]) +{ + int status; + + RL(close(pipefd[1])); + + readregs(pipefd[0], regs); + + RL(waitpid(child, &status, 0)); + if (WIFSIGNALED(status)) { + atf_tc_fail_nonfatal("child terminated on signal %d (%s)", + WTERMSIG(status), strsignal(WTERMSIG(status))); + } else if (!WIFEXITED(status)) { + atf_tc_fail_nonfatal("child terminated mysteriously," + " status=0x%x", + status); + } else { + ATF_CHECK_MSG(WEXITSTATUS(status) == 0, + "child exited with code %d", WEXITSTATUS(status)); + } + + checkregs(regs); +} + +#endif + +ATF_TC(execregszero); +ATF_TC_HEAD(execregszero, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test execve(2) zeroes registers"); +} +ATF_TC_BODY(execregszero, tc) +{ +#ifdef HAVE_EXECREGS_TEST + char h_execregs[PATH_MAX]; + int pipefd[2]; + register_t regs[NEXECREGS]; + pid_t child; + + RL(snprintf(h_execregs, sizeof(h_execregs), "%s/h_execregs", + atf_tc_get_config_var(tc, "srcdir"))); + + RL(pipe(pipefd)); + memset(regs, 0x5a, sizeof(regs)); + + RL(child = fork()); + if (child == 0) { + if (dup2(pipefd[1], STDOUT_FILENO) == -1) + err(1, "dup2"); + if (closefrom(STDERR_FILENO + 1) == -1) + err(1, "closefrom"); + if (execregschild(h_execregs) == -1) + err(1, "execve"); + _exit(2); + } + + testregs(child, pipefd, regs); +#else + atf_tc_skip("missing test for PR kern/59084:" + " exec/spawn leaks register content"); +#endif +} + +ATF_TC(spawnregszero); +ATF_TC_HEAD(spawnregszero, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test posix_spawn(2) zeroes registers"); +} +ATF_TC_BODY(spawnregszero, tc) +{ +#ifdef HAVE_EXECREGS_TEST + char h_execregs[PATH_MAX]; + int pipefd[2]; + register_t regs[NEXECREGS]; + pid_t child; + + RL(snprintf(h_execregs, sizeof(h_execregs), "%s/h_execregs", + atf_tc_get_config_var(tc, "srcdir"))); + + RL(pipe(pipefd)); + memset(regs, 0x5a, sizeof(regs)); + + RL(child = spawnregschild(h_execregs, pipefd[1])); + + testregs(child, pipefd, regs); +#else + atf_tc_skip("missing test for PR kern/59084:" + " exec/spawn leaks register content"); +#endif +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, execregszero); + ATF_TP_ADD_TC(tp, spawnregszero); + + return atf_no_error(); +} diff --git a/kernel/t_fdrestart.c b/kernel/t_fdrestart.c new file mode 100644 index 000000000000..5449fcdaf18d --- /dev/null +++ b/kernel/t_fdrestart.c @@ -0,0 +1,274 @@ +/* $NetBSD: t_fdrestart.c,v 1.4 2023/11/18 19:46:55 riastradh Exp $ */ + +/*- + * Copyright (c) 2023 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _KMEMUSER /* ERESTART */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_fdrestart.c,v 1.4 2023/11/18 19:46:55 riastradh Exp $"); + +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <atf-c.h> +#include <errno.h> +#include <pthread.h> +#include <unistd.h> + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +#include "h_macros.h" + +struct fdrestart { + void (*op)(struct fdrestart *); + int fd; + pthread_barrier_t barrier; +}; + +static void +waitforbarrier(struct fdrestart *F, const char *caller) +{ + int error; + + error = pthread_barrier_wait(&F->barrier); + switch (error) { + case 0: + case PTHREAD_BARRIER_SERIAL_THREAD: + break; + default: + atf_tc_fail("%s: pthread_barrier_wait: %d, %s", caller, error, + strerror(error)); + } +} + +static void +doread(struct fdrestart *F) +{ + char c; + ssize_t nread; + int error; + + /* + * Wait for the other thread to be ready. + */ + waitforbarrier(F, "reader"); + + /* + * Start a read. This should block, and then, when the other + * thread closes the fd, should be woken to fail with ERESTART. + */ + nread = rump_sys_read(F->fd, &c, sizeof(c)); + ATF_REQUIRE_EQ_MSG(nread, -1, "nread=%zd", nread); + error = errno; + ATF_REQUIRE_EQ_MSG(error, ERESTART, "errno=%d (%s)", error, + strerror(error)); + + /* + * Now further attempts at I/O should fail with EBADF because + * the fd has been closed. + */ + nread = rump_sys_read(F->fd, &c, sizeof(c)); + ATF_REQUIRE_EQ_MSG(nread, -1, "nread=%zd", nread); + error = errno; + ATF_REQUIRE_EQ_MSG(error, EBADF, "errno=%d (%s)", error, + strerror(error)); +} + +static void +dowrite(struct fdrestart *F) +{ + static const char buf[1024*1024]; /* XXX >BIG_PIPE_SIZE */ + ssize_t nwrit; + int error; + + /* + * Make sure the pipe's buffer is full first. + */ + for (;;) { + int nspace; + + RL(rump_sys_ioctl(F->fd, FIONSPACE, &nspace)); + ATF_REQUIRE_MSG(nspace >= 0, "nspace=%d", nspace); + if (nspace == 0) + break; + RL(rump_sys_write(F->fd, buf, (size_t)nspace)); + } + + /* + * Wait for the other thread to be ready. + */ + waitforbarrier(F, "writer"); + + /* + * Start a write. This should block, and then, when the other + * thread closes the fd, should be woken to fail with ERESTART. + */ + nwrit = rump_sys_write(F->fd, buf, sizeof(buf)); + ATF_REQUIRE_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit); + error = errno; + ATF_REQUIRE_EQ_MSG(error, ERESTART, "errno=%d (%s)", error, + strerror(error)); + + /* + * Now further attempts at I/O should fail with EBADF because + * the fd has been closed. + */ + nwrit = rump_sys_write(F->fd, buf, sizeof(buf)); + ATF_REQUIRE_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit); + error = errno; + ATF_REQUIRE_EQ_MSG(error, EBADF, "errno=%d (%s)", error, + strerror(error)); +} + +static void * +doit(void *cookie) +{ + struct fdrestart *F = cookie; + + (*F->op)(F); + + return NULL; +} + +static void +on_sigalrm(int signo) +{ + + atf_tc_fail("timed out"); +} + +static void +testfdrestart(struct fdrestart *F) +{ + pthread_t t; + + ATF_REQUIRE_MSG(signal(SIGALRM, &on_sigalrm) != SIG_ERR, + "errno=%d (%s)", errno, strerror(errno)); + + RZ(pthread_barrier_init(&F->barrier, NULL, 2)); + RZ(pthread_create(&t, NULL, &doit, F)); + waitforbarrier(F, "closer"); /* wait for thread to start */ + (void)sleep(1); /* wait for op to start */ + (void)alarm(1); /* set a deadline */ + RL(rump_sys_close(F->fd)); /* wake op in other thread */ + RZ(pthread_join(t, NULL)); /* wait for op to wake and fail */ + (void)alarm(0); /* clear the deadline */ +} + +ATF_TC(pipe_read); +ATF_TC_HEAD(pipe_read, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test pipe read fails on close"); +} +ATF_TC_BODY(pipe_read, tc) +{ + struct fdrestart fdrestart, *F = &fdrestart; + int fd[2]; + + rump_init(); + + RL(rump_sys_pipe(fd)); + + memset(F, 0, sizeof(*F)); + F->op = &doread; + F->fd = fd[0]; + testfdrestart(F); +} + +ATF_TC(pipe_write); +ATF_TC_HEAD(pipe_write, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test pipe write fails on close"); +} +ATF_TC_BODY(pipe_write, tc) +{ + struct fdrestart fdrestart, *F = &fdrestart; + int fd[2]; + + rump_init(); + + RL(rump_sys_pipe(fd)); + + memset(F, 0, sizeof(*F)); + F->op = &dowrite; + F->fd = fd[1]; + atf_tc_expect_fail("PR kern/57659"); + testfdrestart(F); +} + +ATF_TC(socketpair_read); +ATF_TC_HEAD(socketpair_read, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test socketpair read fails on close"); +} +ATF_TC_BODY(socketpair_read, tc) +{ + struct fdrestart fdrestart, *F = &fdrestart; + int fd[2]; + + rump_init(); + + RL(rump_sys_socketpair(AF_LOCAL, SOCK_STREAM, 0, fd)); + + memset(F, 0, sizeof(*F)); + F->op = &doread; + F->fd = fd[0]; + testfdrestart(F); +} + +ATF_TC(socketpair_write); +ATF_TC_HEAD(socketpair_write, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test socketpair write fails on close"); +} +ATF_TC_BODY(socketpair_write, tc) +{ + struct fdrestart fdrestart, *F = &fdrestart; + int fd[2]; + + rump_init(); + + RL(rump_sys_socketpair(AF_LOCAL, SOCK_STREAM, 0, fd)); + + memset(F, 0, sizeof(*F)); + F->op = &dowrite; + F->fd = fd[0]; + testfdrestart(F); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, pipe_read); + ATF_TP_ADD_TC(tp, pipe_write); + ATF_TP_ADD_TC(tp, socketpair_read); + ATF_TP_ADD_TC(tp, socketpair_write); + + return atf_no_error(); +} diff --git a/kernel/t_nanosleep.c b/kernel/t_nanosleep.c new file mode 100644 index 000000000000..9ef752b37e60 --- /dev/null +++ b/kernel/t_nanosleep.c @@ -0,0 +1,246 @@ +/* $NetBSD: t_nanosleep.c,v 1.2 2025/10/07 20:09:27 andvar Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2024\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_nanosleep.c,v 1.2 2025/10/07 20:09:27 andvar Exp $"); + +#include <sys/types.h> +#include <sys/wait.h> + +#include <atf-c.h> + +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +static void +sacrifice(void) +{ + pause(); +} + +static void +tester(pid_t victim, clockid_t clock, int flags) +{ + /* + * we need this sleep to be long enough that we + * can accurately detect when the sleep finishes + * early, but not so long that when there's no + * bug and things actually sleep this long, that + * the execution of a sleep this long, several + * times, won't slow down the overall testing + * process too much. Trial and error... + */ + struct timespec to_sleep = { 4, 0 }; + + struct timespec before, after; + struct timespec *ts; + int e; + + if (clock_gettime(clock, &before) != 0) + exit(1); + + if (flags & TIMER_ABSTIME) { + timespecadd(&to_sleep, &before, &after); + ts = &after; + } else + ts = &to_sleep; + + printf("Test: Clock=%d Flags=%x, starting at %jd.%.9ld\n", + (int)clock, flags, (intmax_t)before.tv_sec, before.tv_nsec); + if (flags & TIMER_ABSTIME) + printf("Sleeping until %jd.%.9ld\n", + (intmax_t)ts->tv_sec, ts->tv_nsec); + else + printf("Sleeping for %jd.%.9ld\n", + (intmax_t)ts->tv_sec, ts->tv_nsec); + + /* OK, we're ready */ + + /* these next two steps need to be as close together as possible */ + if (kill(victim, SIGKILL) == -1) + exit(2); + if ((e = clock_nanosleep(clock, flags, ts, &after)) != 0) + exit(20 + e); + + if (!(flags & TIMER_ABSTIME)) { + printf("Remaining to sleep: %jd.%.9ld\n", + (intmax_t)after.tv_sec, after.tv_nsec); + + if (after.tv_sec != 0 || after.tv_nsec != 0) + exit(3); + } + + if (clock_gettime(clock, &after) != 0) + exit(4); + + printf("Sleep ended at: %jd.%.9ld\n", + (intmax_t)after.tv_sec, after.tv_nsec); + + timespecadd(&before, &to_sleep, &before); + if (timespeccmp(&before, &after, >)) + exit(5); + + exit(0); +} + +/* + * The parent of the masochist/victim above, controls everything. + */ +static void +runit(clockid_t clock, int flags) +{ + pid_t v, m, x; + int status; + struct timespec brief = { 0, 3 * 100 * 1000 * 1000 }; /* 300 ms */ + + ATF_REQUIRE((v = fork()) != -1); + if (v == 0) + sacrifice(); + + ATF_REQUIRE((m = fork()) != -1); + if (m == 0) + tester(v, clock, flags); + + ATF_REQUIRE((x = wait(&status)) != -1); + + if (x == m) { + /* + * This is bad, the murderer shouldn't die first + */ + fprintf(stderr, "M exited first, status %#x\n", status); + (void)kill(v, SIGKILL); /* just in case */ + atf_tc_fail("2nd child predeceased first"); + } + if (x != v) { + fprintf(stderr, "Unknown exit from %d (status: %#x)" + "(M=%d V=%d)\n", x, status, m, v); + (void)kill(m, SIGKILL); + (void)kill(v, SIGKILL); + atf_tc_fail("Strange child died"); + } + + /* + * OK, the victim died, we don't really care why, + * (it should have been because of a SIGKILL, maybe + * test for that someday). + * + * Now we get to proceed to the real test. + * + * But we want to wait a short while to try and be sure + * that m (the child still running) has a chance to + * fall asleep. + */ + (void) clock_nanosleep(CLOCK_MONOTONIC, TIMER_RELTIME, &brief, NULL); + + /* + * This is the test, for PR kern/58733 + * - stop a process while in clock_nanosleep() + * - resume it again + * - see if it still sleeps as long as was requested (or longer) + */ + ATF_REQUIRE(kill(m, SIGSTOP) == 0); + (void) clock_nanosleep(CLOCK_MONOTONIC, TIMER_RELTIME, &brief, NULL); + ATF_REQUIRE(kill(m, SIGCONT) == 0); + + ATF_REQUIRE((x = wait(&status)) != -1); + + if (x != m) { + fprintf(stderr, "Unknown exit from %d (status: %#x)" + "(M=%d V=%d)\n", x, status, m, v); + (void) kill(m, SIGKILL); + atf_tc_fail("Strange child died"); + } + + if (status == 0) + atf_tc_pass(); + + /* + * Here we should decode the status, and give a better + * clue what really went wrong. Later... + */ + fprintf(stderr, "Test failed: status from M: %#x\n", status); + atf_tc_fail("M exited with non-zero status. PR kern/58733"); +} + + +ATF_TC(nanosleep_monotonic_absolute); +ATF_TC_HEAD(nanosleep_monotonic_absolute, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(MONO, ABS)"); +} +ATF_TC_BODY(nanosleep_monotonic_absolute, tc) +{ + runit(CLOCK_MONOTONIC, TIMER_ABSTIME); +} + +ATF_TC(nanosleep_monotonic_relative); +ATF_TC_HEAD(nanosleep_monotonic_relative, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(MONO, REL)"); +} +ATF_TC_BODY(nanosleep_monotonic_relative, tc) +{ + runit(CLOCK_MONOTONIC, TIMER_RELTIME); +} + +ATF_TC(nanosleep_realtime_absolute); +ATF_TC_HEAD(nanosleep_realtime_absolute, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(REAL, ABS)"); +} +ATF_TC_BODY(nanosleep_realtime_absolute, tc) +{ + runit(CLOCK_REALTIME, TIMER_ABSTIME); +} + +ATF_TC(nanosleep_realtime_relative); +ATF_TC_HEAD(nanosleep_realtime_relative, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks clock_nanosleep(REAL, REL)"); +} +ATF_TC_BODY(nanosleep_realtime_relative, tc) +{ + runit(CLOCK_REALTIME, TIMER_RELTIME); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, nanosleep_monotonic_absolute); + ATF_TP_ADD_TC(tp, nanosleep_monotonic_relative); + ATF_TP_ADD_TC(tp, nanosleep_realtime_absolute); + ATF_TP_ADD_TC(tp, nanosleep_realtime_relative); + + return atf_no_error(); +} diff --git a/kernel/t_semtimedop.c b/kernel/t_semtimedop.c new file mode 100644 index 000000000000..daeaac6b3dab --- /dev/null +++ b/kernel/t_semtimedop.c @@ -0,0 +1,279 @@ +/* $NetBSD: t_semtimedop.c,v 1.2 2024/10/10 07:45:02 martin Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_semtimedop.c,v 1.2 2024/10/10 07:45:02 martin Exp $"); + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <errno.h> +#include <string.h> +#include <time.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <atf-c.h> +#include <sys/wait.h> + +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */ + u_short *array; /* array for GETALL & SETALL */ +}; + +ATF_TC(semtimedop_basic); +ATF_TC_HEAD(semtimedop_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "Basic semtimedop functionality"); +} + +ATF_TC_BODY(semtimedop_basic, tc) +{ + key_t key = IPC_PRIVATE; + int semid; + struct sembuf sops; + union semun sun; + struct timespec timeout; + + /* Create semaphore set with 1 semaphore */ + semid = semget(key, 1, IPC_CREAT | 0600); + ATF_REQUIRE_MSG(semid != -1, "semget failed: %s", strerror(errno)); + + /* Initialize semaphore to 0 */ + sun.val = 0; + if (semctl(semid, 0, SETVAL, sun) == -1) { + ATF_REQUIRE_MSG(0, "semctl SETVAL failed: %s", + strerror(errno)); + } + + /* Define semtimedop operation: increment semaphore */ + sops.sem_num = 0; + sops.sem_op = 1; + sops.sem_flg = 0; + + /* Define timeout */ + timeout.tv_sec = 1; + timeout.tv_nsec = 0; + + /* Perform semtimedop */ + if (semtimedop(semid, &sops, 1, &timeout) == -1) { + ATF_REQUIRE_MSG(0, "semtimedop failed: %s", strerror(errno)); + } + + /* Check semaphore value */ + int val = semctl(semid, 0, GETVAL); + ATF_REQUIRE_MSG(val == 1, + "Semaphore value incorrect: got %d, expected 1", val); + + /* Clean up */ + ATF_REQUIRE_MSG(semctl(semid, 0, IPC_RMID) != -1, + "semctl IPC_RMID failed: %s", strerror(errno)); +} + +/* semtimedop blocks until timeout expires */ +ATF_TC(semtimedop_timeout); +ATF_TC_HEAD(semtimedop_timeout, tc) +{ + atf_tc_set_md_var(tc, "descr", + "semtimedop blocks until timeout expires"); +} + +ATF_TC_BODY(semtimedop_timeout, tc) +{ + key_t key = IPC_PRIVATE; + int semid; + struct sembuf sops; + union semun sun; + struct timespec timeout; + pid_t pid; + int status; + + /* Create semaphore set with 1 semaphore */ + semid = semget(key, 1, IPC_CREAT | 0600); + ATF_REQUIRE_MSG(semid != -1, "semget failed: %s", strerror(errno)); + + /* Initialize semaphore to 0 */ + sun.val = 0; + if (semctl(semid, 0, SETVAL, sun) == -1) { + ATF_REQUIRE_MSG(0, "semctl SETVAL failed: %s", strerror(errno)); + } + + pid = fork(); + ATF_REQUIRE_MSG(pid != -1, "fork failed: %s", strerror(errno)); + + if (pid == 0) { + /* + * Child: perform semtimedop with negative sem_op, should + * block until timeout + */ + sops.sem_num = 0; + sops.sem_op = -1; + sops.sem_flg = 0; + + timeout.tv_sec = 2; + timeout.tv_nsec = 0; + + if (semtimedop(semid, &sops, 1, &timeout) == -1) { + if (errno == EAGAIN || errno == EINTR) { + exit(0); /* Expected */ + } + } + exit(1); /* Unexpected failure/success */ + } + + /* Parent: wait for child to finish */ + waitpid(pid, &status, 0); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE_EQ(WEXITSTATUS(status), 0); + + /* Clean up */ + ATF_REQUIRE_MSG(semctl(semid, 0, IPC_RMID) != -1, + "semctl IPC_RMID failed: %s", strerror(errno)); +} + +/* semtimedop with SEM_UNDO adjusts semaphore on exit */ +ATF_TC(semtimedop_semundo); +ATF_TC_HEAD(semtimedop_semundo, tc) +{ + atf_tc_set_md_var(tc, "descr", + "semtimedop with SEM_UNDO adjusts semaphore on exit"); +} + +ATF_TC_BODY(semtimedop_semundo, tc) +{ + key_t key = IPC_PRIVATE; + int semid; + struct sembuf sops; + union semun sun; + struct timespec timeout; + pid_t pid; + int val; + + /* Create semaphore set with 1 semaphore */ + semid = semget(key, 1, IPC_CREAT | 0600); + ATF_REQUIRE_MSG(semid != -1, "semget failed: %s", strerror(errno)); + + /* Initialize semaphore to 0 */ + sun.val = 0; + if (semctl(semid, 0, SETVAL, sun) == -1) { + ATF_REQUIRE_MSG(0, "semctl SETVAL failed: %s", strerror(errno)); + } + + pid = fork(); + ATF_REQUIRE_MSG(pid != -1, "fork failed: %s", strerror(errno)); + + if (pid == 0) { + /* Child: perform semtimedop with SEM_UNDO */ + sops.sem_num = 0; + sops.sem_op = 1; + sops.sem_flg = SEM_UNDO; + + timeout.tv_sec = 1; + timeout.tv_nsec = 0; + + if (semtimedop(semid, &sops, 1, &timeout) == -1) { + exit(1); /* Unexpected failure */ + } + + exit(0); /* Exit normally, SEM_UNDO should be triggered */ + } + + /* Parent: wait for child to exit */ + waitpid(pid, NULL, 0); + + /* Check semaphore value; should be 0 after SEM_UNDO */ + val = semctl(semid, 0, GETVAL); + ATF_REQUIRE_MSG(val == 0, + "Semaphore value incorrect after SEM_UNDO: got %d, " + "expected 0", val); + + /* Clean up */ + ATF_REQUIRE_MSG(semctl(semid, 0, IPC_RMID) != -1, + "semctl IPC_RMID failed: %s", strerror(errno)); +} + +/* semtimedop handles invalid parameters correctly */ +ATF_TC(semtimedop_invalid); +ATF_TC_HEAD(semtimedop_invalid, tc) +{ + atf_tc_set_md_var(tc, "descr", + "semtimedop handles invalid parameters correctly"); +} + +ATF_TC_BODY(semtimedop_invalid, tc) +{ + struct sembuf sops; + union semun sun; + struct timespec timeout; + + /* Invalid semaphore id */ + sops.sem_num = 0; + sops.sem_op = -1; + sops.sem_flg = 0; + + timeout.tv_sec = 1; + timeout.tv_nsec = 0; + + /* Attempt to perform semtimedop on invalid semid */ + ATF_REQUIRE_MSG(semtimedop(-1, &sops, 1, &timeout) == -1 + && errno == EINVAL, "semtimedop did not fail on invalid semid"); + + /* Create semaphore set */ + key_t key = IPC_PRIVATE; + int semid = semget(key, 1, IPC_CREAT | 0600); + ATF_REQUIRE_MSG(semid != -1, "semget failed: %s", strerror(errno)); + + /* Initialize semaphore to 0 */ + sun.val = 0; + if (semctl(semid, 0, SETVAL, sun) == -1) { + ATF_REQUIRE_MSG(0, "semctl SETVAL failed: %s", strerror(errno)); + } + + /* Set an invalid semaphore number */ + sops.sem_num = 1; /* Only 1 semaphore in set, index 0 */ + sops.sem_op = 1; + sops.sem_flg = 0; + + /* Attempt semtimedop with invalid sem_num */ + ATF_REQUIRE_MSG(semtimedop(semid, &sops, 1, &timeout) == -1 + && errno == EFBIG, "semtimedop did not fail on invalid sem_num"); + + /* Clean up */ + ATF_REQUIRE_MSG(semctl(semid, 0, IPC_RMID) != -1, + "semctl IPC_RMID failed: %s", strerror(errno)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, semtimedop_basic); + ATF_TP_ADD_TC(tp, semtimedop_timeout); + ATF_TP_ADD_TC(tp, semtimedop_semundo); + ATF_TP_ADD_TC(tp, semtimedop_invalid); + + return atf_no_error(); +} diff --git a/kernel/t_setjmp.sh b/kernel/t_setjmp.sh new file mode 100644 index 000000000000..1dbbd8504234 --- /dev/null +++ b/kernel/t_setjmp.sh @@ -0,0 +1,63 @@ +# $NetBSD: t_setjmp.sh,v 1.5 2025/04/29 10:57:17 martin Exp $ +# +# Copyright (c) 2025 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +module_loaded=no +atf_test_case setjmp cleanup +setjmp_head() +{ + atf_set "descr" "Test setjmp(9)/longjmp(9)" +} +setjmp_body() +{ + case `uname -p` in + vax) + atf_expect_fail "PR port-vax/59308:" \ + " kernel longjmp(9) fails to make setjmp(9) return 1" + ;; + esac + + err=$( modstat -e 2>&1 ) + if [ $? -gt 0 ]; then + atf_skip "${err##modstat:}" + fi + + module_loaded="yes" + modload "$(atf_get_srcdir)/setjmp_tester/setjmp_tester.kmod" + atf_check -s exit:0 -o inline:'1\n' \ + sysctl -n -w kern.setjmp_tester.test=1 +} +setjmp_cleanup() +{ + if [ "${module_loaded}" != "no" ]; then + modunload setjmp_tester + fi +} + +atf_init_test_cases() +{ + atf_add_test_case setjmp +} diff --git a/kernel/t_signal_and_sp.c b/kernel/t_signal_and_sp.c new file mode 100644 index 000000000000..1cef56cd3041 --- /dev/null +++ b/kernel/t_signal_and_sp.c @@ -0,0 +1,628 @@ +/* $NetBSD: t_signal_and_sp.c,v 1.21 2025/04/26 23:49:55 uwe Exp $ */ + +/* + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define __EXPOSE_STACK /* <sys/param.h>: expose STACK_ALIGNBYTES */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_signal_and_sp.c,v 1.21 2025/04/26 23:49:55 uwe Exp $"); + +#include <sys/param.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <limits.h> +#include <poll.h> +#include <pthread.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <ucontext.h> +#include <unistd.h> + +#include "h_execsp.h" +#include "h_macros.h" + +#ifdef HAVE_STACK_POINTER_H +# include "stack_pointer.h" +#endif + +#define PR_59327 "PR kern/59327: user stack pointer is not aligned properly" + +#ifdef HAVE_SIGNALSPHANDLER +void signalsphandler(int); /* signalsphandler.S assembly routine */ +#endif + +void *volatile signalsp; + +static void +test_execsp(const struct atf_tc *tc, const char *prog) +{ +#ifdef STACK_ALIGNBYTES + char h_execsp[PATH_MAX]; + struct execsp execsp; + int fd[2]; + pid_t pid; + struct pollfd pollfd; + int nfds; + ssize_t nread; + int status; + + /* + * Determine the full path to the helper program. + */ + RL(snprintf(h_execsp, sizeof(h_execsp), "%s/%s", + atf_tc_get_config_var(tc, "srcdir"), prog)); + + /* + * Create a pipe to read a bundle of stack pointer samples from + * the child, and fork the child. + */ + RL(pipe(fd)); + RL(pid = vfork()); + if (pid == 0) { /* child */ + char *const argv[] = {h_execsp, NULL}; + + if (dup2(fd[1], STDOUT_FILENO) == -1) + _exit(1); + if (closefrom(STDERR_FILENO + 1) == -1) + _exit(2); + if (execve(argv[0], argv, NULL) == -1) + _exit(3); + _exit(4); + } + + /* + * Close the writing end so, if something goes wrong in the + * child, we don't hang indefinitely waiting for output. + */ + RL(close(fd[1])); + + /* + * Wait up to 5sec for the child to return an answer. Any more + * than that, and we kill it. The child is mostly hand-written + * assembly routines where lots can go wrong, so don't bother + * waiting if it gets stuck in a loop. + */ + pollfd.fd = fd[0]; + pollfd.events = POLLIN; + RL(nfds = poll(&pollfd, 1, 5*1000/*ms*/)); + if (nfds == 0) { + fprintf(stderr, "child hung, killing\n"); + RL(kill(pid, SIGKILL)); + } + + /* + * Read a bundle of stack pointer samples from the child. + */ + RL(nread = read(fd[0], &execsp, sizeof(execsp))); + ATF_CHECK_MSG((size_t)nread == sizeof(execsp), + "nread=%zu sizeof(execsp)=%zu", + (size_t)nread, sizeof(execsp)); + + /* + * Wait for the child to terminate and report failure if it + * didn't exit cleanly. + */ + RL(waitpid(pid, &status, 0)); + if (WIFSIGNALED(status)) { + atf_tc_fail_nonfatal("child exited on signal %d (%s)", + WTERMSIG(status), strsignal(WTERMSIG(status))); + } else if (!WIFEXITED(status)) { + atf_tc_fail_nonfatal("child exited status=0x%x", status); + } else { + ATF_CHECK_MSG(WEXITSTATUS(status) == 0, + "child exited with code %d", + WEXITSTATUS(status)); + } + + /* + * Now that we have reaped the child, stop here if the stack + * pointer samples are bogus; otherwise verify they are all + * aligned. + */ + if ((size_t)nread != sizeof(execsp)) + return; /* failed already */ + + printf("start sp @ %p\n", execsp.startsp); + printf("ctor sp @ %p\n", execsp.ctorsp); + printf("main sp @ %p\n", execsp.mainsp); + printf("dtor sp @ %p\n", execsp.dtorsp); + + ATF_CHECK_MSG(((uintptr_t)execsp.startsp & STACK_ALIGNBYTES) == 0, + "elf entry point was called with misaligned sp: %p", + execsp.startsp); + + ATF_CHECK_MSG(((uintptr_t)execsp.ctorsp & STACK_ALIGNBYTES) == 0, + "elf constructor was called with misaligned sp: %p", + execsp.ctorsp); + + ATF_CHECK_MSG(((uintptr_t)execsp.mainsp & STACK_ALIGNBYTES) == 0, + "main function was called with misaligned sp: %p", + execsp.mainsp); + + ATF_CHECK_MSG(((uintptr_t)execsp.dtorsp & STACK_ALIGNBYTES) == 0, + "elf destructor was called with misaligned sp: %p", + execsp.dtorsp); + + /* + * Leave a reminder on architectures for which we haven't + * implemented execsp_start.S. + */ + if (execsp.startsp == NULL || + execsp.ctorsp == NULL || + execsp.mainsp == NULL || + execsp.dtorsp == NULL) + atf_tc_skip("Not fully supported on this architecture"); +#else + atf_tc_skip("Unknown STACK_ALIGNBYTES on this architecture"); +#endif +} + +ATF_TC(execsp_dynamic); +ATF_TC_HEAD(execsp_dynamic, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on dynamic program start"); +} +ATF_TC_BODY(execsp_dynamic, tc) +{ + test_execsp(tc, "h_execsp_dynamic"); +} + +ATF_TC(execsp_static); +ATF_TC_HEAD(execsp_static, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on static program start"); +} +ATF_TC_BODY(execsp_static, tc) +{ + test_execsp(tc, "h_execsp_static"); +} + +#if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC +void *volatile contextsp; /* set by contextspfunc.S */ +static ucontext_t return_context; +static volatile bool test_context_done; + +void contextspfunc(void); /* contextspfunc.S assembly routine */ + +static void +contextnoop(void) +{ + + fprintf(stderr, "contextnoop\n"); + /* control will return to contextspfunc via uc_link */ +} + +void contextdone(void); /* called by contextspfunc.S */ +void +contextdone(void) +{ + + fprintf(stderr, "contextdone\n"); + ATF_REQUIRE(!test_context_done); + test_context_done = true; + RL(setcontext(&return_context)); + atf_tc_fail("setcontext returned"); +} +#endif + +ATF_TC(contextsp); +ATF_TC_HEAD(contextsp, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on makecontext entry"); +} +ATF_TC_BODY(contextsp, tc) +{ +#if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC + ucontext_t uc; + char *stack; + unsigned i; + + REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); + fprintf(stderr, "stack @ [%p,%p)\n", stack, + stack + SIGSTKSZ + STACK_ALIGNBYTES); + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + contextsp = NULL; + test_context_done = false; + + RL(getcontext(&uc)); + uc.uc_stack.ss_sp = stack; + uc.uc_stack.ss_size = SIGSTKSZ + i; + makecontext(&uc, &contextspfunc, 0); + + fprintf(stderr, "[%u] swapcontext\n", i); + RL(swapcontext(&return_context, &uc)); + + ATF_CHECK(contextsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)contextsp && + (uintptr_t)contextsp <= (uintptr_t)stack + SIGSTKSZ + i, + "contextsp=%p", contextsp); + ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, + "[%u] makecontext function called with misaligned sp %p", + i, contextsp); + } + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + contextsp = NULL; + test_context_done = false; + + RL(getcontext(&uc)); + uc.uc_stack.ss_sp = stack + i; + uc.uc_stack.ss_size = SIGSTKSZ; + makecontext(&uc, &contextspfunc, 0); + + fprintf(stderr, "[%u] swapcontext\n", i); + RL(swapcontext(&return_context, &uc)); + + ATF_CHECK(contextsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)contextsp && + (uintptr_t)contextsp <= (uintptr_t)stack + i + SIGSTKSZ, + "contextsp=%p", contextsp); + ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, + "[%u] makecontext function called with misaligned sp %p", + i, contextsp); + } +#else + atf_tc_skip("Not implemented on this platform"); +#endif +} + +ATF_TC(contextsplink); +ATF_TC_HEAD(contextsplink, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on makecontext link entry"); +} +ATF_TC_BODY(contextsplink, tc) +{ +#if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC + ucontext_t uc1, uc2; + char *stack1, *stack2; + unsigned i; + + REQUIRE_LIBC(stack1 = malloc(SIGSTKSZ), NULL); + fprintf(stderr, "stack1 @ [%p,%p)\n", stack1, stack1 + SIGSTKSZ); + REQUIRE_LIBC(stack2 = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); + fprintf(stderr, "stack2 @ [%p,%p)\n", + stack2, stack2 + SIGSTKSZ + STACK_ALIGNBYTES); + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + contextsp = NULL; + test_context_done = false; + + RL(getcontext(&uc1)); + uc1.uc_stack.ss_sp = stack1; + uc1.uc_stack.ss_size = SIGSTKSZ; + uc1.uc_link = &uc2; + makecontext(&uc1, &contextnoop, 0); + + RL(getcontext(&uc2)); + uc2.uc_stack.ss_sp = stack2; + uc2.uc_stack.ss_size = SIGSTKSZ + i; + makecontext(&uc2, &contextspfunc, 0); + + fprintf(stderr, "[%u] swapcontext\n", i); + RL(swapcontext(&return_context, &uc1)); + + ATF_CHECK(contextsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack2 <= (uintptr_t)contextsp && + (uintptr_t)contextsp <= (uintptr_t)stack2 + SIGSTKSZ + i, + "contextsp=%p", contextsp); + ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, + "[%u] makecontext function called with misaligned sp %p", + i, contextsp); + } + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + contextsp = NULL; + test_context_done = false; + + RL(getcontext(&uc1)); + uc1.uc_stack.ss_sp = stack1; + uc1.uc_stack.ss_size = SIGSTKSZ; + uc1.uc_link = &uc2; + makecontext(&uc1, &contextnoop, 0); + + RL(getcontext(&uc2)); + uc2.uc_stack.ss_sp = stack2 + i; + uc2.uc_stack.ss_size = SIGSTKSZ; + makecontext(&uc2, &contextspfunc, 0); + + fprintf(stderr, "[%u] swapcontext\n", i); + RL(swapcontext(&return_context, &uc1)); + + ATF_CHECK(contextsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack2 + i <= (uintptr_t)contextsp && + (uintptr_t)contextsp <= (uintptr_t)stack2 + SIGSTKSZ + i, + "contextsp=%p", contextsp); + ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, + "[%u] makecontext function called with misaligned sp %p", + i, contextsp); + } +#else + atf_tc_skip("Not implemented on this platform"); +#endif +} + +ATF_TC(signalsp); +ATF_TC_HEAD(signalsp, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on entry to signal handler"); +} +ATF_TC_BODY(signalsp, tc) +{ +#if defined STACK_ALIGNBYTES && defined HAVE_SIGNALSPHANDLER + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signalsphandler; + RL(sigaction(SIGUSR1, &sa, NULL)); + RL(raise(SIGUSR1)); + + ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, + "signal handler was called with a misaligned sp: %p", + signalsp); +#else + atf_tc_skip("Not implemented on this platform"); +#endif +} + +ATF_TC(signalsp_sigaltstack); +ATF_TC_HEAD(signalsp_sigaltstack, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on entry to signal handler" + " with maximally misaligned sigaltstack"); +} +ATF_TC_BODY(signalsp_sigaltstack, tc) +{ +#if defined STACK_ALIGNBYTES && HAVE_SIGNALSPHANDLER +#if defined(__sh__) + atf_tc_expect_fail(PR_59327); +#endif + char *stack; + struct sigaction sa; + struct sigaltstack ss; + unsigned i; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signalsphandler; + sa.sa_flags = SA_ONSTACK; + RL(sigaction(SIGUSR1, &sa, NULL)); + + /* + * Allocate a signal stack with enough slop to try all possible + * misalignments of the stack pointer. Print it to stderr so + * it always appears in atf output before shenanigans happen. + */ + REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); + fprintf(stderr, "stack @ [%p, %p)\n", + stack, stack + SIGSTKSZ + STACK_ALIGNBYTES); + + /* + * Try with all alignments of high addresses. + */ + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + ss.ss_sp = stack; + ss.ss_size = SIGSTKSZ + i; + ss.ss_flags = 0; + RL(sigaltstack(&ss, NULL)); + + signalsp = NULL; + RL(raise(SIGUSR1)); + ATF_CHECK(signalsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)signalsp && + (uintptr_t)signalsp <= (uintptr_t)stack + SIGSTKSZ + i, + "signalsp=%p", signalsp); + ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, + "[%u] signal handler was called with a misaligned sp: %p", + i, signalsp); + } + + /* + * Try with all alignments of low addresses. + */ + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + ss.ss_sp = stack + i; + ss.ss_size = SIGSTKSZ; + ss.ss_flags = 0; + RL(sigaltstack(&ss, NULL)); + + signalsp = NULL; + RL(raise(SIGUSR1)); + ATF_CHECK(signalsp != NULL); + ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)signalsp && + (uintptr_t)signalsp <= (uintptr_t)stack + i + SIGSTKSZ, + "signalsp=%p", signalsp); + ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, + "[%u] signal handler was called with a misaligned sp: %p", + i, signalsp); + } +#else + atf_tc_skip("Not implemented on this platform"); +#endif +} + +#if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC +void *threadspfunc(void *); /* threadspfunc.S assembly routine */ +#endif + +ATF_TC(threadsp); +ATF_TC_HEAD(threadsp, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify stack pointer is aligned on thread start"); +} +ATF_TC_BODY(threadsp, tc) +{ +#if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC + pthread_t t; + void *sp; + char *stack; + unsigned i; + + REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); + fprintf(stderr, "stack @ [%p,%p)\n", stack, + stack + SIGSTKSZ + STACK_ALIGNBYTES); + + RZ(pthread_create(&t, NULL, &threadspfunc, NULL)); + + alarm(1); + RZ(pthread_join(t, &sp)); + alarm(0); + + ATF_CHECK(sp != NULL); + ATF_CHECK_MSG(((uintptr_t)sp & STACK_ALIGNBYTES) == 0, + "thread called with misaligned sp: %p", sp); + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + pthread_attr_t attr; + + RZ(pthread_attr_init(&attr)); + RZ(pthread_attr_setstack(&attr, stack, SIGSTKSZ + i)); + RZ(pthread_create(&t, &attr, &threadspfunc, NULL)); + RZ(pthread_attr_destroy(&attr)); + + alarm(1); + RZ(pthread_join(t, &sp)); + alarm(0); + + ATF_CHECK(sp != NULL); + ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)sp && + (uintptr_t)sp <= (uintptr_t)stack + SIGSTKSZ + i, + "sp=%p", sp); + ATF_CHECK_MSG(((uintptr_t)sp & STACK_ALIGNBYTES) == 0, + "[%u] thread called with misaligned sp: %p", i, sp); + } + + for (i = 0; i <= STACK_ALIGNBYTES; i++) { + pthread_attr_t attr; + + RZ(pthread_attr_init(&attr)); + RZ(pthread_attr_setstack(&attr, stack + i, SIGSTKSZ)); + RZ(pthread_create(&t, &attr, &threadspfunc, NULL)); + RZ(pthread_attr_destroy(&attr)); + + alarm(1); + RZ(pthread_join(t, &sp)); + alarm(0); + + ATF_CHECK(sp != NULL); + ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)sp && + (uintptr_t)sp <= (uintptr_t)stack + i + SIGSTKSZ, + "sp=%p", sp); + ATF_CHECK_MSG(((uintptr_t)sp & STACK_ALIGNBYTES) == 0, + "[%u] thread called with misaligned sp: %p", i, sp); + } +#else + atf_tc_skip("Not implemented on this platform"); +#endif +} + +ATF_TC(misaligned_sp_and_signal); +ATF_TC_HEAD(misaligned_sp_and_signal, tc) +{ + atf_tc_set_md_var(tc, "descr", "process can return from a signal" + " handler even if the stack pointer is misaligned when a signal" + " arrives"); +} +ATF_TC_BODY(misaligned_sp_and_signal, tc) +{ +#if defined STACK_ALIGNBYTES && defined HAVE_STACK_POINTER_H +#if defined(__sh__) + atf_tc_expect_fail(PR_59327); +#endif + + /* + * Set up a handler for SIGALRM. + */ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = &signalsphandler; + RL(sigaction(SIGALRM, &sa, NULL)); + + /* + * Set up an interval timer so that we receive SIGALRM after 50 ms. + */ + struct itimerval itv; + memset(&itv, 0, sizeof(itv)); + itv.it_value.tv_usec = 1000 * 50; + RL(setitimer(ITIMER_MONOTONIC, &itv, NULL)); + + /* + * Now misalign the SP. Wait for the signal to arrive and see what + * happens. This should be fine as long as we don't use it to + * access memory. + */ + MISALIGN_SP; + while (signalsp == NULL) { + /* + * Make sure the compiler does not optimize this busy loop + * away. + */ + __asm__("" ::: "memory"); + } + /* + * We could successfully return from a signal handler. Now we + * should fix the SP before calling any functions. + */ + FIX_SP; + + /* + * But was the stack pointer aligned when we were on the signal + * handler? + */ + ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, + "signal handler was called with a misaligned sp: %p", + signalsp); +#else + atf_tc_skip("Not implemented for this platform"); +#endif +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, contextsp); + ATF_TP_ADD_TC(tp, contextsplink); + ATF_TP_ADD_TC(tp, execsp_dynamic); + ATF_TP_ADD_TC(tp, execsp_static); + ATF_TP_ADD_TC(tp, misaligned_sp_and_signal); + ATF_TP_ADD_TC(tp, signalsp); + ATF_TP_ADD_TC(tp, signalsp_sigaltstack); + ATF_TP_ADD_TC(tp, threadsp); + return atf_no_error(); +} diff --git a/kernel/t_time_arith.c b/kernel/t_time_arith.c new file mode 100644 index 000000000000..0f738bfbe19a --- /dev/null +++ b/kernel/t_time_arith.c @@ -0,0 +1,1224 @@ +/* $NetBSD: t_time_arith.c,v 1.7 2025/10/06 12:05:04 riastradh Exp $ */ + +/*- + * Copyright (c) 2024-2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_time_arith.c,v 1.7 2025/10/06 12:05:04 riastradh Exp $"); + +#include <sys/timearith.h> + +#include <atf-c.h> +#include <errno.h> +#include <limits.h> +#include <setjmp.h> +#include <signal.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <util.h> + +#include "h_macros.h" + +enum { HZ = 100 }; + +int hz = HZ; +int tick = 1000000/HZ; + +static sig_atomic_t jmp_en; +static int jmp_sig; +static jmp_buf jmp; + +static void +handle_signal(int signo) +{ + const int errno_save = errno; + char buf[32]; + + snprintf_ss(buf, sizeof(buf), "signal %d\n", signo); + (void)write(STDERR_FILENO, buf, strlen(buf)); + + errno = errno_save; + + if (jmp_en) { + jmp_sig = signo; + jmp_en = 0; + longjmp(jmp, 1); + } else { + raise_default_signal(signo); + } +} + +const struct itimer_transition { + struct itimerspec it_time; + struct timespec it_now; + struct timespec it_next; + int it_overruns; + const char *it_xfail; +} itimer_transitions[] = { + /* + * Fired more than one interval early -- treat clock as wound + * backwards, not counting overruns. Advance to the next + * integral multiple of it_interval starting from it_value. + */ + [0] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {0,1}, {1,0}, 0, + NULL}, + [1] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {0,500000000}, {1,0}, 0, + NULL}, + [2] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {0,999999999}, {1,0}, 0, + NULL}, + [3] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {1,0}, {2,0}, 0, + NULL}, + [4] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {1,1}, {2,0}, 0, + NULL}, + [5] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {1,500000000}, {2,0}, 0, + NULL}, + [6] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {1,999999999}, {2,0}, 0, + NULL}, + + /* + * Fired exactly one interval early. Treat this too as clock + * wound backwards. + */ + [7] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {2,0}, {3,0}, 0, + NULL}, + + /* + * Fired less than one interval early -- callouts and real-time + * clock might not be perfectly synced, counted as zero + * overruns. Advance by one interval from the scheduled time. + */ + [8] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {2,1}, {3,0}, 0, + NULL}, + [9] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {2,500000000}, {3,0}, 0, + NULL}, + [10] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {2,999999999}, {3,0}, 0, + NULL}, + + /* + * Fired exactly on time. Advance by one interval. + */ + [11] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {3,0}, {4,0}, 0, NULL}, + + /* + * Fired late by less than one interval -- callouts and + * real-time clock might not be prefectly synced, counted as + * zero overruns. Advance by one interval from the scheduled + * time (even if it's very close to a full interval). + */ + [12] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {3,1}, {4,0}, 0, NULL}, + [14] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {3,500000000}, {4,0}, 0, NULL}, + [15] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {3,999999999}, {4,0}, 0, NULL}, + + /* + * Fired late by exactly one interval -- treat it as overrun. + */ + [16] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {4,0}, {5,0}, 1, + NULL}, + + /* + * Fired late by more than one interval but less than two -- + * overrun. + */ + [17] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {4,1}, {5,0}, 1, + NULL}, + [18] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {4,500000000}, {5,0}, 1, + NULL}, + [19] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {4,999999999}, {5,0}, 1, + NULL}, + + /* + * Fired late by exactly two intervals -- two overruns. + */ + [20] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {5,0}, {6,0}, 2, + NULL}, + + /* + * Fired late by more intervals plus slop, up to 32. + * + * XXX Define DELAYTIMER_MAX so we can write it in terms of + * that. + */ + [21] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {13,123456789}, {14,0}, 10, + NULL}, + [22] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {34,999999999}, {35,0}, 31, + NULL}, + + /* + * Fired late by roughly INT_MAX intervals. + */ + [23] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {(time_t)3 + INT_MAX - 1, 0}, + {(time_t)3 + INT_MAX, 0}, + INT_MAX - 1, + NULL}, + [24] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {(time_t)3 + INT_MAX, 0}, + {(time_t)3 + INT_MAX + 1, 0}, + INT_MAX, + NULL}, + [25] = {{.it_value = {3,0}, .it_interval = {1,0}}, + {(time_t)3 + INT_MAX + 1, 0}, + {(time_t)3 + INT_MAX + 2, 0}, + INT_MAX, + NULL}, + + /* (2^63 - 1) ns */ + [26] = {{.it_value = {3,0}, .it_interval = {9223372036,854775807}}, + {3,1}, {9223372039,854775807}, 0, NULL}, + /* 2^63 ns */ + [27] = {{.it_value = {3,0}, .it_interval = {9223372036,854775808}}, + {3,1}, {9223372039,854775808}, 0, NULL}, + /* (2^63 + 1) ns */ + [28] = {{.it_value = {3,0}, .it_interval = {9223372036,854775809}}, + {3,1}, {9223372039,854775809}, 0, NULL}, + + /* + * Overflows -- we should (XXX but currently don't) reject + * intervals of at least 2^64 nanoseconds up front, since this + * is more time than it is reasonable to wait (more than 584 + * years). + */ + + /* (2^64 - 1) ns */ + [29] = {{.it_value = {3,0}, .it_interval = {18446744073,709551615}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* 2^64 ns */ + [30] = {{.it_value = {3,0}, .it_interval = {18446744073,709551616}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* (2^64 + 1) ns */ + [31] = {{.it_value = {3,0}, .it_interval = {18446744073,709551617}}, + {2,999999999}, {0,0}, 0, + NULL}, + + /* (2^63 - 1) us */ + [32] = {{.it_value = {3,0}, .it_interval = {9223372036854,775807}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* 2^63 us */ + [33] = {{.it_value = {3,0}, .it_interval = {9223372036854,775808}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* (2^63 + 1) us */ + [34] = {{.it_value = {3,0}, .it_interval = {9223372036854,775809}}, + {2,999999999}, {0,0}, 0, + NULL}, + + /* (2^64 - 1) us */ + [35] = {{.it_value = {3,0}, .it_interval = {18446744073709,551615}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* 2^64 us */ + [36] = {{.it_value = {3,0}, .it_interval = {18446744073709,551616}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* (2^64 + 1) us */ + [37] = {{.it_value = {3,0}, .it_interval = {18446744073709,551617}}, + {2,999999999}, {0,0}, 0, + NULL}, + + /* (2^63 - 1) ms */ + [38] = {{.it_value = {3,0}, .it_interval = {9223372036854775,807}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* 2^63 ms */ + [39] = {{.it_value = {3,0}, .it_interval = {9223372036854775,808}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* (2^63 + 1) ms */ + [40] = {{.it_value = {3,0}, .it_interval = {9223372036854775,809}}, + {2,999999999}, {0,0}, 0, + NULL}, + + /* (2^64 - 1) ms */ + [41] = {{.it_value = {3,0}, .it_interval = {18446744073709551,615}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* 2^64 ms */ + [42] = {{.it_value = {3,0}, .it_interval = {18446744073709551,616}}, + {2,999999999}, {0,0}, 0, + NULL}, + /* (2^64 + 1) ms */ + [43] = {{.it_value = {3,0}, .it_interval = {18446744073709551,617}}, + {2,999999999}, {0,0}, 0, + NULL}, + + /* invalid intervals */ + [44] = {{.it_value = {3,0}, .it_interval = {-1,0}}, + {3,1}, {0,0}, 0, NULL}, + [45] = {{.it_value = {3,0}, .it_interval = {0,-1}}, + {3,1}, {0,0}, 0, NULL}, + [46] = {{.it_value = {3,0}, .it_interval = {0,1000000000}}, + {3,1}, {0,0}, 0, NULL}, + + /* + * Overflow nanosecond arithmetic. The magic interval number + * here is ceiling(INT64_MAX/2) nanoseconds. The interval + * start value will be rounded to an integral number of ticks, + * so rather than write exactly `4611686018,427387905', just + * round up the `now' value to the next second. This forces an + * overrun _and_ triggers int64_t arithmetic overflow. + */ + [47] = {{.it_value = {0,1}, + .it_interval = {4611686018,427387904}}, + /* XXX needless overflow */ + {4611686019,0}, {0,0}, 1, + NULL}, + + /* interval ~ 1/4 * (2^63 - 1) ns, now ~ 3/4 * (2^63 - 1) ns */ + [48] = {{.it_value = {0,1}, + .it_interval = {2305843009,213693952}}, + /* XXX needless overflow */ + {6917529028,0}, {0,0}, 3, + NULL}, + [49] = {{.it_value = {6917529027,0}, + .it_interval = {2305843009,213693952}}, + {6917529028,0}, {9223372036,213693952}, 0, NULL}, + [50] = {{.it_value = {6917529029,0}, + .it_interval = {2305843009,213693952}}, + {6917529028,0}, {6917529029,0}, 0, + NULL}, + + /* interval ~ 1/2 * (2^63 - 1) ns, now ~ 3/4 * (2^63 - 1) ns */ + [51] = {{.it_value = {0,1}, + .it_interval = {4611686018,427387904}}, + /* XXX needless overflow */ + {6917529028,0}, {0,0}, 1, + NULL}, + [52] = {{.it_value = {2305843009,213693951}, /* ~1/4 * (2^63 - 1) */ + .it_interval = {4611686018,427387904}}, + /* XXX needless overflow */ + {6917529028,0}, {0,0}, 1, + NULL}, + [54] = {{.it_value = {6917529027,0}, + .it_interval = {4611686018,427387904}}, + {6917529028,0}, {11529215045,427387904}, 0, NULL}, + [55] = {{.it_value = {6917529029,0}, + .it_interval = {4611686018,427387904}}, + {6917529028,0}, {6917529029,0}, 0, + NULL}, + + [56] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + /* XXX needless overflow */ + {INT64_MAX - 2,999999999}, {0,0}, 0, + NULL}, + [57] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX - 1,0}, {INT64_MAX,0}, 0, NULL}, + [58] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX - 1,1}, {INT64_MAX,0}, 0, NULL}, + [59] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX - 1,999999999}, {INT64_MAX,0}, 0, NULL}, + [60] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX,0}, {0,0}, 0, + NULL}, + [61] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX,1}, {0,0}, 0, + NULL}, + [62] = {{.it_value = {INT64_MAX - 1,0}, .it_interval = {1,0}}, + {INT64_MAX,999999999}, {0,0}, 0, + NULL}, + + [63] = {{.it_value = {INT64_MAX,0}, .it_interval = {1,0}}, + {INT64_MAX - 1,1}, {0,0}, 0, + NULL}, + [64] = {{.it_value = {INT64_MAX,0}, .it_interval = {1,0}}, + {INT64_MAX - 1,999999999}, {0,0}, 0, + NULL}, + [65] = {{.it_value = {INT64_MAX,0}, .it_interval = {1,0}}, + {INT64_MAX,0}, {0,0}, 0, + NULL}, + [66] = {{.it_value = {INT64_MAX,0}, .it_interval = {1,0}}, + {INT64_MAX,1}, {0,0}, 0, + NULL}, + [67] = {{.it_value = {INT64_MAX,0}, .it_interval = {1,0}}, + {INT64_MAX,999999999}, {0,0}, 0, + NULL}, +}; + +ATF_TC(itimer_transitions); +ATF_TC_HEAD(itimer_transitions, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Tests interval timer transitions"); +} +ATF_TC_BODY(itimer_transitions, tc) +{ + volatile unsigned i; + + REQUIRE_LIBC(signal(SIGFPE, handle_signal), SIG_ERR); + REQUIRE_LIBC(signal(SIGABRT, handle_signal), SIG_ERR); + + for (i = 0; i < __arraycount(itimer_transitions); i++) { + struct itimer_transition it = itimer_transitions[i]; + struct timespec next; + int overruns; + volatile bool aborted = true; + volatile bool expect_abort = false; + + fprintf(stderr, "case %u\n", i); + + if (it.it_xfail) + atf_tc_expect_fail("%s", it.it_xfail); + + if (itimespecfix(&it.it_time.it_value) != 0 || + itimespecfix(&it.it_time.it_interval) != 0) { + fprintf(stderr, "rejected by itimerspecfix\n"); + expect_abort = true; + } + + if (setjmp(jmp) == 0) { + jmp_en = 1; + itimer_transition(&it.it_time, &it.it_now, + &next, &overruns); + jmp_en = 0; + aborted = false; + } + ATF_CHECK(!jmp_en); + jmp_en = 0; /* paranoia */ + if (expect_abort) { + fprintf(stderr, "expected abort\n"); + ATF_CHECK_MSG(aborted, + "[%u] missing invariant assertion", i); + ATF_CHECK_MSG(jmp_sig == SIGABRT, + "[%u] missing invariant assertion", i); + } else { + ATF_CHECK_MSG(!aborted, "[%u] raised signal %d: %s", i, + jmp_sig, strsignal(jmp_sig)); + } + + ATF_CHECK_MSG((next.tv_sec == it.it_next.tv_sec && + next.tv_nsec == it.it_next.tv_nsec), + "[%u] periodic intervals of %lld.%09d from %lld.%09d" + " last expired at %lld.%09d:" + " next expiry at %lld.%09d, expected %lld.%09d", i, + (long long)it.it_time.it_interval.tv_sec, + (int)it.it_time.it_interval.tv_nsec, + (long long)it.it_time.it_value.tv_sec, + (int)it.it_time.it_value.tv_nsec, + (long long)it.it_now.tv_sec, (int)it.it_now.tv_nsec, + (long long)next.tv_sec, (int)next.tv_nsec, + (long long)it.it_next.tv_sec, (int)it.it_next.tv_nsec); + ATF_CHECK_EQ_MSG(overruns, it.it_overruns, + "[%u] periodic intervals of %lld.%09d from %lld.%09d" + " last expired at %lld.%09d:" + " overruns %d, expected %d", i, + (long long)it.it_time.it_interval.tv_sec, + (int)it.it_time.it_interval.tv_nsec, + (long long)it.it_time.it_value.tv_sec, + (int)it.it_time.it_value.tv_nsec, + (long long)it.it_now.tv_sec, (int)it.it_now.tv_nsec, + overruns, it.it_overruns); + + if (it.it_xfail) + atf_tc_expect_pass(); + } +} + +/* + * { 0, if t <= 0; + * tstohz(t sec) @ f Hz = { ceil(t/(1/f)), if that's below INT_MAX; + * { INT_MAX, otherwise. + */ + +#define TSTOHZ_ROUND_XFAIL \ + "PR kern/59691: tstohz(9) rounding errors" + +const struct tstohz_case { + int ts_hz; + struct timespec ts_ts; + int ts_ticks; + const char *ts_xfail; +} tstohz_cases[] = { + /* + * hz = 10 + */ + + /* negative inputs yield 0 ticks */ + [0] = {10, {.tv_sec = -1, .tv_nsec = 0}, 0, NULL}, + [1] = {10, {.tv_sec = -1, .tv_nsec = 999999999}, 0, NULL}, + + /* zero input yields 0 ticks */ + [2] = {10, {.tv_sec = 0, .tv_nsec = 0}, 0, NULL}, + + /* + * Nonzero input always yields >=2 ticks, because the time from + * now until the next tick may be arbitrarily short, and we + * need to wait one full tick, so we have to wait for two + * ticks. + */ + [3] = {10, {.tv_sec = 0, .tv_nsec = 1}, 2, NULL}, + [4] = {10, {.tv_sec = 0, .tv_nsec = 2}, 2, NULL}, + [5] = {10, {.tv_sec = 0, .tv_nsec = 99999999}, 2, NULL}, + [6] = {10, {.tv_sec = 0, .tv_nsec = 100000000}, 2, NULL}, + [7] = {10, {.tv_sec = 0, .tv_nsec = 100000001}, 3, NULL}, + [8] = {10, {.tv_sec = 0, .tv_nsec = 100000002}, 3, NULL}, + [9] = {10, {.tv_sec = 0, .tv_nsec = 199999999}, 3, NULL}, + [10] = {10, {.tv_sec = 0, .tv_nsec = 200000000}, 3, NULL}, + [11] = {10, {.tv_sec = 0, .tv_nsec = 200000001}, 4, NULL}, + [12] = {10, {.tv_sec = 0, .tv_nsec = 200000002}, 4, NULL}, + [13] = {10, {.tv_sec = 0, .tv_nsec = 999999999}, 11, NULL}, + [14] = {10, {.tv_sec = 1, .tv_nsec = 0}, 11, NULL}, + [15] = {10, {.tv_sec = 1, .tv_nsec = 1}, 12, NULL}, + [16] = {10, {.tv_sec = 1, .tv_nsec = 2}, 12, NULL}, + /* .tv_sec ~ INT32_MAX/1000000 */ + [17] = {10, {.tv_sec = 2147, .tv_nsec = 999999999}, 21481, NULL}, + [18] = {10, {.tv_sec = 2148, .tv_nsec = 0}, 21481, NULL}, + [19] = {10, {.tv_sec = 2148, .tv_nsec = 1}, 21482, NULL}, + [20] = {10, {.tv_sec = 2148, .tv_nsec = 2}, 21482, NULL}, + /* .tv_sec ~ INT32_MAX/hz */ + [21] = {10, {.tv_sec = 214748364, .tv_nsec = 499999999}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [22] = {10, {.tv_sec = 214748364, .tv_nsec = 500000000}, 2147483646, + NULL}, + [23] = {10, {.tv_sec = 214748364, .tv_nsec = 500000001}, 2147483647, + NULL}, + [24] = {10, {.tv_sec = 214748364, .tv_nsec = 500000002}, 2147483647, + NULL}, + [25] = {10, {.tv_sec = 214748364, .tv_nsec = 599999999}, 2147483647, + NULL}, + [26] = {10, {.tv_sec = 214748364, .tv_nsec = 600000000}, 2147483647, + NULL}, + [27] = {10, {.tv_sec = 214748364, .tv_nsec = 999999999}, 2147483647, + NULL}, + [28] = {10, {.tv_sec = 214748365, .tv_nsec = 0}, 2147483647, + NULL}, + [29] = {10, {.tv_sec = 214748365, .tv_nsec = 1}, 2147483647, + NULL}, + [30] = {10, {.tv_sec = 214748365, .tv_nsec = 2}, 2147483647, + NULL}, + [31] = {10, {.tv_sec = (time_t)INT_MAX + 1, .tv_nsec = 123456789}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [32] = {10, {.tv_sec = 9223372036854, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [33] = {10, {.tv_sec = 9223372036855, .tv_nsec = 0}, + INT_MAX, NULL}, + [34] = {10, {.tv_sec = 9223372036855, .tv_nsec = 1}, + INT_MAX, NULL}, + [35] = {10, {.tv_sec = 9223372036855, .tv_nsec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [36] = {10, {.tv_sec = 922337203685477580, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [37] = {10, {.tv_sec = 922337203685477581, .tv_nsec = 0}, + INT_MAX, NULL}, + [38] = {10, {.tv_sec = 922337203685477581, .tv_nsec = 1}, + INT_MAX, NULL}, + [39] = {10, {.tv_sec = 922337203685477581, .tv_nsec = 2}, + INT_MAX, NULL}, + [40] = {10, {.tv_sec = (time_t)INT_MAX + 1, .tv_nsec = 123456789}, + INT_MAX, NULL}, + + /* + * hz = 100 + */ + + [41] = {100, {.tv_sec = -1, .tv_nsec = 0}, 0, NULL}, + [42] = {100, {.tv_sec = -1, .tv_nsec = 999999999}, 0, NULL}, + [43] = {100, {.tv_sec = 0, .tv_nsec = 0}, 0, NULL}, + [44] = {100, {.tv_sec = 0, .tv_nsec = 1}, 2, NULL}, + [45] = {100, {.tv_sec = 0, .tv_nsec = 2}, 2, NULL}, + [46] = {100, {.tv_sec = 0, .tv_nsec = 9999999}, 2, NULL}, + [47] = {100, {.tv_sec = 0, .tv_nsec = 10000000}, 2, NULL}, + [48] = {100, {.tv_sec = 0, .tv_nsec = 10000001}, 3, NULL}, + [49] = {100, {.tv_sec = 0, .tv_nsec = 10000002}, 3, NULL}, + [50] = {100, {.tv_sec = 0, .tv_nsec = 19999999}, 3, NULL}, + [51] = {100, {.tv_sec = 0, .tv_nsec = 20000000}, 3, NULL}, + [52] = {100, {.tv_sec = 0, .tv_nsec = 20000001}, 4, NULL}, + [53] = {100, {.tv_sec = 0, .tv_nsec = 20000002}, 4, NULL}, + [54] = {100, {.tv_sec = 0, .tv_nsec = 99999999}, 11, NULL}, + [55] = {100, {.tv_sec = 0, .tv_nsec = 100000000}, 11, NULL}, + [56] = {100, {.tv_sec = 0, .tv_nsec = 100000001}, 12, NULL}, + [57] = {100, {.tv_sec = 0, .tv_nsec = 100000002}, 12, NULL}, + [58] = {100, {.tv_sec = 0, .tv_nsec = 999999999}, 101, NULL}, + [59] = {100, {.tv_sec = 1, .tv_nsec = 0}, 101, NULL}, + [60] = {100, {.tv_sec = 1, .tv_nsec = 1}, 102, NULL}, + [61] = {100, {.tv_sec = 1, .tv_nsec = 2}, 102, NULL}, + /* .tv_sec ~ INT32_MAX/1000000 */ + [62] = {100, {.tv_sec = 2147, .tv_nsec = 999999999}, 214801, NULL}, + [63] = {100, {.tv_sec = 2148, .tv_nsec = 0}, 214801, NULL}, + [64] = {100, {.tv_sec = 2148, .tv_nsec = 1}, 214802, NULL}, + [65] = {100, {.tv_sec = 2148, .tv_nsec = 2}, 214802, NULL}, + /* .tv_sec ~ INT32_MAX/hz */ + [66] = {100, {.tv_sec = 21474836, .tv_nsec = 439999999}, 2147483645, + NULL}, + [67] = {100, {.tv_sec = 21474836, .tv_nsec = 440000000}, 2147483645, + NULL}, + [68] = {100, {.tv_sec = 21474836, .tv_nsec = 440000001}, 2147483646, + NULL}, + [69] = {100, {.tv_sec = 21474836, .tv_nsec = 440000002}, 2147483646, + NULL}, + [70] = {100, {.tv_sec = 21474836, .tv_nsec = 449999999}, 2147483646, + NULL}, + [71] = {100, {.tv_sec = 21474836, .tv_nsec = 450000000}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [72] = {100, {.tv_sec = 21474836, .tv_nsec = 450000001}, 2147483647, + NULL}, + [73] = {100, {.tv_sec = 21474836, .tv_nsec = 450000002}, 2147483647, + NULL}, + [74] = {100, {.tv_sec = 21474836, .tv_nsec = 459999999}, 2147483647, + NULL}, + [75] = {100, {.tv_sec = 21474836, .tv_nsec = 460000000}, 2147483647, + NULL}, + [76] = {100, {.tv_sec = 21474836, .tv_nsec = 460000001}, 2147483647, + NULL}, + [77] = {100, {.tv_sec = 21474836, .tv_nsec = 460000002}, 2147483647, + NULL}, + [78] = {100, {.tv_sec = 21474836, .tv_nsec = 999999999}, 2147483647, + NULL}, + [79] = {100, {.tv_sec = 21474837, .tv_nsec = 0}, 2147483647, + NULL}, + [80] = {100, {.tv_sec = 21474837, .tv_nsec = 1}, 2147483647, + NULL}, + [81] = {100, {.tv_sec = 21474837, .tv_nsec = 2}, 2147483647, + NULL}, + [82] = {100, {.tv_sec = 21474837, .tv_nsec = 2}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000 */ + [83] = {100, {.tv_sec = 9223372036854, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [84] = {100, {.tv_sec = 9223372036855, .tv_nsec = 0}, + INT_MAX, NULL}, + [85] = {100, {.tv_sec = 9223372036855, .tv_nsec = 1}, + INT_MAX, NULL}, + [86] = {100, {.tv_sec = 9223372036855, .tv_nsec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [87] = {100, {.tv_sec = 92233720368547758, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [88] = {100, {.tv_sec = 92233720368547758, .tv_nsec = 0}, + INT_MAX, NULL}, + [89] = {100, {.tv_sec = 92233720368547758, .tv_nsec = 1}, + INT_MAX, NULL}, + [90] = {100, {.tv_sec = 92233720368547758, .tv_nsec = 2}, + INT_MAX, NULL}, + [91] = {100, {.tv_sec = (time_t)INT_MAX + 1, .tv_nsec = 123456789}, + INT_MAX, NULL}, + + /* + * hz = 1000 + */ + + [92] = {1000, {.tv_sec = -1, .tv_nsec = 0}, 0, NULL}, + [93] = {1000, {.tv_sec = -1, .tv_nsec = 999999999}, 0, NULL}, + [94] = {1000, {.tv_sec = 0, .tv_nsec = 0}, 0, NULL}, + [95] = {1000, {.tv_sec = 0, .tv_nsec = 1}, 2, NULL}, + [96] = {1000, {.tv_sec = 0, .tv_nsec = 2}, 2, NULL}, + [97] = {1000, {.tv_sec = 0, .tv_nsec = 999999}, 2, NULL}, + [98] = {1000, {.tv_sec = 0, .tv_nsec = 1000000}, 2, NULL}, + [99] = {1000, {.tv_sec = 0, .tv_nsec = 1000001}, 3, NULL}, + [100] = {1000, {.tv_sec = 0, .tv_nsec = 1000002}, 3, NULL}, + [101] = {1000, {.tv_sec = 0, .tv_nsec = 1999999}, 3, NULL}, + [102] = {1000, {.tv_sec = 0, .tv_nsec = 2000000}, 3, NULL}, + [103] = {1000, {.tv_sec = 0, .tv_nsec = 2000001}, 4, NULL}, + [104] = {1000, {.tv_sec = 0, .tv_nsec = 2000002}, 4, NULL}, + [105] = {1000, {.tv_sec = 0, .tv_nsec = 999999999}, 1001, NULL}, + [106] = {1000, {.tv_sec = 1, .tv_nsec = 0}, 1001, NULL}, + [107] = {1000, {.tv_sec = 1, .tv_nsec = 1}, 1002, NULL}, + [108] = {1000, {.tv_sec = 1, .tv_nsec = 2}, 1002, NULL}, + /* .tv_sec ~ INT_MAX/1000000 */ + [109] = {1000, {.tv_sec = 2147, .tv_nsec = 999999999}, 2148001, NULL}, + [110] = {1000, {.tv_sec = 2148, .tv_nsec = 0}, 2148001, NULL}, + [111] = {1000, {.tv_sec = 2148, .tv_nsec = 1}, 2148002, NULL}, + [112] = {1000, {.tv_sec = 2148, .tv_nsec = 2}, 2148002, NULL}, + /* .tv_sec ~ INT_MAX/hz */ + [113] = {1000, {.tv_sec = 2147483, .tv_nsec = 643999999}, 2147483645, + NULL}, + [114] = {1000, {.tv_sec = 2147483, .tv_nsec = 644000000}, 2147483645, + NULL}, + [115] = {1000, {.tv_sec = 2147483, .tv_nsec = 644000001}, 2147483646, + NULL}, + [116] = {1000, {.tv_sec = 2147483, .tv_nsec = 644000002}, 2147483646, + NULL}, + [117] = {1000, {.tv_sec = 2147483, .tv_nsec = 644999999}, 2147483646, + NULL}, + [118] = {1000, {.tv_sec = 2147483, .tv_nsec = 645000000}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [119] = {1000, {.tv_sec = 2147483, .tv_nsec = 645000001}, 2147483647, + NULL}, + [120] = {1000, {.tv_sec = 2147483, .tv_nsec = 645000002}, 2147483647, + NULL}, + [121] = {1000, {.tv_sec = 2147483, .tv_nsec = 645999999}, 2147483647, + NULL}, + [122] = {1000, {.tv_sec = 2147483, .tv_nsec = 646000000}, 2147483647, + NULL}, + [123] = {1000, {.tv_sec = 2147483, .tv_nsec = 646000001}, 2147483647, + NULL}, + [124] = {1000, {.tv_sec = 2147483, .tv_nsec = 646000002}, 2147483647, + NULL}, + [125] = {1000, {.tv_sec = 2147483, .tv_nsec = 699999999}, 2147483647, + NULL}, + [126] = {1000, {.tv_sec = 2147484, .tv_nsec = 0}, 2147483647, + NULL}, + [127] = {1000, {.tv_sec = 2147484, .tv_nsec = 1}, 2147483647, + NULL}, + [128] = {1000, {.tv_sec = 2147484, .tv_nsec = 2}, 2147483647, + NULL}, + [129] = {1000, {.tv_sec = 2147484, .tv_nsec = 2}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [130] = {1000, {.tv_sec = 9223372036854, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [131] = {1000, {.tv_sec = 9223372036855, .tv_nsec = 0}, + INT_MAX, NULL}, + [132] = {1000, {.tv_sec = 9223372036855, .tv_nsec = 1}, + INT_MAX, NULL}, + [133] = {1000, {.tv_sec = 9223372036855, .tv_nsec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [134] = {1000, {.tv_sec = 92233720368547758, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [135] = {1000, {.tv_sec = 92233720368547758, .tv_nsec = 0}, + INT_MAX, NULL}, + [136] = {1000, {.tv_sec = 92233720368547758, .tv_nsec = 1}, + INT_MAX, NULL}, + [137] = {1000, {.tv_sec = 92233720368547758, .tv_nsec = 2}, + INT_MAX, NULL}, + [138] = {1000, {.tv_sec = (time_t)INT_MAX + 1, .tv_nsec = 123456789}, + INT_MAX, NULL}, + + /* + * hz = 8191, prime non-divisor of 10^k or 2^k + */ + + [139] = {8191, {.tv_sec = -1, .tv_nsec = 0}, 0, NULL}, + [140] = {8191, {.tv_sec = -1, .tv_nsec = 999999999}, 0, NULL}, + [141] = {8191, {.tv_sec = 0, .tv_nsec = 0}, 0, NULL}, + [142] = {8191, {.tv_sec = 0, .tv_nsec = 1}, 2, NULL}, + [143] = {8191, {.tv_sec = 0, .tv_nsec = 2}, 2, NULL}, + [144] = {8191, {.tv_sec = 0, .tv_nsec = 122084}, 2, + TSTOHZ_ROUND_XFAIL}, + [145] = {8191, {.tv_sec = 0, .tv_nsec = 122085}, 2, + TSTOHZ_ROUND_XFAIL}, + [146] = {8191, {.tv_sec = 0, .tv_nsec = 122086}, 3, NULL}, + [147] = {8191, {.tv_sec = 0, .tv_nsec = 244168}, 3, + TSTOHZ_ROUND_XFAIL}, + [148] = {8191, {.tv_sec = 0, .tv_nsec = 244169}, 3, + TSTOHZ_ROUND_XFAIL}, + [149] = {8191, {.tv_sec = 0, .tv_nsec = 244170}, 3, + TSTOHZ_ROUND_XFAIL}, + [150] = {8191, {.tv_sec = 0, .tv_nsec = 244171}, 4, NULL}, + [151] = {8191, {.tv_sec = 0, .tv_nsec = 244172}, 4, NULL}, + [152] = {8191, {.tv_sec = 0, .tv_nsec = 999999999}, 8192, NULL}, + [153] = {8191, {.tv_sec = 1, .tv_nsec = 0}, 8192, NULL}, + [154] = {8191, {.tv_sec = 1, .tv_nsec = 1}, 8193, NULL}, + [155] = {8191, {.tv_sec = 1, .tv_nsec = 2}, 8193, NULL}, + /* .tv_sec ~ INT_MAX/1000000 */ + [156] = {8191, {.tv_sec = 2147, .tv_nsec = 999999999}, 17594269, NULL}, + [157] = {8191, {.tv_sec = 2148, .tv_nsec = 0}, 17594269, NULL}, + [158] = {8191, {.tv_sec = 2148, .tv_nsec = 1}, 17594270, NULL}, + [159] = {8191, {.tv_sec = 2148, .tv_nsec = 2}, 17594270, NULL}, + /* .tv_sec ~ INT_MAX/hz */ + [160] = {8191, {.tv_sec = 262176, .tv_nsec = 3540471}, 2147483646, + NULL}, + [161] = {8191, {.tv_sec = 262176, .tv_nsec = 3540472}, 2147483647, + NULL}, + [162] = {8191, {.tv_sec = 262176, .tv_nsec = 3540473}, 2147483647, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [163] = {8191, {.tv_sec = 262176, .tv_nsec = 3662556}, 2147483647, + NULL}, + [164] = {8191, {.tv_sec = 262176, .tv_nsec = 3662557}, 2147483647, + NULL}, + [165] = {8191, {.tv_sec = 262176, .tv_nsec = 3662558}, 2147483647, + NULL}, + [166] = {8191, {.tv_sec = 262176, .tv_nsec = 999999999}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [167] = {8191, {.tv_sec = 9223372036854, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [168] = {8191, {.tv_sec = 9223372036855, .tv_nsec = 0}, + INT_MAX, NULL}, + [169] = {8191, {.tv_sec = 9223372036855, .tv_nsec = 1}, + INT_MAX, NULL}, + [170] = {8191, {.tv_sec = 9223372036855, .tv_nsec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [171] = {8191, {.tv_sec = 92233720368547758, .tv_nsec = 999999999}, + INT_MAX, NULL}, + [172] = {8191, {.tv_sec = 92233720368547758, .tv_nsec = 0}, + INT_MAX, NULL}, + [173] = {8191, {.tv_sec = 92233720368547758, .tv_nsec = 1}, + INT_MAX, NULL}, + [174] = {8191, {.tv_sec = 92233720368547758, .tv_nsec = 2}, + INT_MAX, NULL}, + [175] = {8191, {.tv_sec = (time_t)INT_MAX + 1, .tv_nsec = 123456789}, + INT_MAX, NULL}, +}; + +ATF_TC(tstohz); +ATF_TC_HEAD(tstohz, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test tstohz(9)"); +} +ATF_TC_BODY(tstohz, tc) +{ + size_t i; + + for (i = 0; i < __arraycount(tstohz_cases); i++) { + const struct tstohz_case *ts = &tstohz_cases[i]; + int ticks; + + /* set system parameters */ + hz = ts->ts_hz; + tick = 1000000/hz; + + ticks = tstohz(&ts->ts_ts); + if (ts->ts_xfail) + atf_tc_expect_fail("%s", ts->ts_xfail); + + /* + * Allow some slop of one part per thousand in the + * arithmetic, but ensure we round up, not down. + */ + ATF_CHECK_MSG(((unsigned)(ticks - ts->ts_ticks) <= + (unsigned)ts->ts_ticks/1000), + "[%zu] tstohz(%lld.%09ld sec) @ %d Hz:" + " expected %d, got %d", + i, + (long long)ts->ts_ts.tv_sec, + (long)ts->ts_ts.tv_nsec, + ts->ts_hz, + ts->ts_ticks, + ticks); + if (ts->ts_xfail) + atf_tc_expect_pass(); + } +} + +/* + * { 0, if t <= 0; + * tvtohz(t sec) @ f Hz = { ceil(t/(1/f)), if that's below INT_MAX; + * { INT_MAX, otherwise. + */ + +const struct tvtohz_case { + int tv_hz; + struct timeval tv_tv; + int tv_ticks; + const char *tv_xfail; +} tvtohz_cases[] = { + /* + * hz = 10 + */ + + /* negative inputs yield 0 ticks */ + [0] = {10, {.tv_sec = -1, .tv_usec = 0}, 0, NULL}, + [1] = {10, {.tv_sec = -1, .tv_usec = 999999}, 0, NULL}, + + /* zero input yields 0 ticks */ + [2] = {10, {.tv_sec = 0, .tv_usec = 0}, 0, NULL}, + + /* + * Nonzero input always yields >=2 ticks, because the time from + * now until the next tick may be arbitrarily short, and we + * need to wait one full tick, so we have to wait for two + * ticks. + */ + [3] = {10, {.tv_sec = 0, .tv_usec = 1}, 2, NULL}, + [4] = {10, {.tv_sec = 0, .tv_usec = 2}, 2, NULL}, + [5] = {10, {.tv_sec = 0, .tv_usec = 99999}, 2, NULL}, + [6] = {10, {.tv_sec = 0, .tv_usec = 100000}, 2, NULL}, + [7] = {10, {.tv_sec = 0, .tv_usec = 100001}, 3, NULL}, + [8] = {10, {.tv_sec = 0, .tv_usec = 100002}, 3, NULL}, + [9] = {10, {.tv_sec = 0, .tv_usec = 199999}, 3, NULL}, + [10] = {10, {.tv_sec = 0, .tv_usec = 200000}, 3, NULL}, + [11] = {10, {.tv_sec = 0, .tv_usec = 200001}, 4, NULL}, + [12] = {10, {.tv_sec = 0, .tv_usec = 200002}, 4, NULL}, + [13] = {10, {.tv_sec = 0, .tv_usec = 999999}, 11, NULL}, + [14] = {10, {.tv_sec = 1, .tv_usec = 0}, 11, NULL}, + [15] = {10, {.tv_sec = 1, .tv_usec = 1}, 12, NULL}, + [16] = {10, {.tv_sec = 1, .tv_usec = 2}, 12, NULL}, + /* .tv_sec ~ INT32_MAX/1000000 */ + [17] = {10, {.tv_sec = 2147, .tv_usec = 999999}, 21481, NULL}, + [18] = {10, {.tv_sec = 2148, .tv_usec = 0}, 21481, NULL}, + [19] = {10, {.tv_sec = 2148, .tv_usec = 1}, 21482, NULL}, + [20] = {10, {.tv_sec = 2148, .tv_usec = 2}, 21482, NULL}, + /* .tv_sec ~ INT32_MAX/hz */ + [21] = {10, {.tv_sec = 214748364, .tv_usec = 499999}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [22] = {10, {.tv_sec = 214748364, .tv_usec = 500000}, 2147483646, + NULL}, + [23] = {10, {.tv_sec = 214748364, .tv_usec = 500001}, 2147483647, + NULL}, + [24] = {10, {.tv_sec = 214748364, .tv_usec = 500002}, 2147483647, + NULL}, + [25] = {10, {.tv_sec = 214748364, .tv_usec = 599999}, 2147483647, + NULL}, + [26] = {10, {.tv_sec = 214748364, .tv_usec = 600000}, 2147483647, + NULL}, + [27] = {10, {.tv_sec = 214748364, .tv_usec = 999999}, 2147483647, + NULL}, + [28] = {10, {.tv_sec = 214748365, .tv_usec = 0}, 2147483647, + NULL}, + [29] = {10, {.tv_sec = 214748365, .tv_usec = 1}, 2147483647, + NULL}, + [30] = {10, {.tv_sec = 214748365, .tv_usec = 2}, 2147483647, + NULL}, + [31] = {10, {.tv_sec = (time_t)INT_MAX + 1, .tv_usec = 123456}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [32] = {10, {.tv_sec = 9223372036854, .tv_usec = 999999}, + INT_MAX, NULL}, + [33] = {10, {.tv_sec = 9223372036855, .tv_usec = 0}, + INT_MAX, NULL}, + [34] = {10, {.tv_sec = 9223372036855, .tv_usec = 1}, + INT_MAX, NULL}, + [35] = {10, {.tv_sec = 9223372036855, .tv_usec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [36] = {10, {.tv_sec = 922337203685477580, .tv_usec = 999999}, + INT_MAX, NULL}, + [37] = {10, {.tv_sec = 922337203685477581, .tv_usec = 0}, + INT_MAX, NULL}, + [38] = {10, {.tv_sec = 922337203685477581, .tv_usec = 1}, + INT_MAX, NULL}, + [39] = {10, {.tv_sec = 922337203685477581, .tv_usec = 2}, + INT_MAX, NULL}, + [40] = {10, {.tv_sec = (time_t)INT_MAX + 1, .tv_usec = 123456}, + INT_MAX, NULL}, + + /* + * hz = 100 + */ + + [41] = {100, {.tv_sec = -1, .tv_usec = 0}, 0, NULL}, + [42] = {100, {.tv_sec = -1, .tv_usec = 999999}, 0, NULL}, + [43] = {100, {.tv_sec = 0, .tv_usec = 0}, 0, NULL}, + [44] = {100, {.tv_sec = 0, .tv_usec = 1}, 2, NULL}, + [45] = {100, {.tv_sec = 0, .tv_usec = 2}, 2, NULL}, + [46] = {100, {.tv_sec = 0, .tv_usec = 9999}, 2, NULL}, + [47] = {100, {.tv_sec = 0, .tv_usec = 10000}, 2, NULL}, + [48] = {100, {.tv_sec = 0, .tv_usec = 10001}, 3, NULL}, + [49] = {100, {.tv_sec = 0, .tv_usec = 10002}, 3, NULL}, + [50] = {100, {.tv_sec = 0, .tv_usec = 19999}, 3, NULL}, + [51] = {100, {.tv_sec = 0, .tv_usec = 20000}, 3, NULL}, + [52] = {100, {.tv_sec = 0, .tv_usec = 20001}, 4, NULL}, + [53] = {100, {.tv_sec = 0, .tv_usec = 20002}, 4, NULL}, + [54] = {100, {.tv_sec = 0, .tv_usec = 99999}, 11, NULL}, + [55] = {100, {.tv_sec = 0, .tv_usec = 100000}, 11, NULL}, + [56] = {100, {.tv_sec = 0, .tv_usec = 100001}, 12, NULL}, + [57] = {100, {.tv_sec = 0, .tv_usec = 100002}, 12, NULL}, + [58] = {100, {.tv_sec = 0, .tv_usec = 999999}, 101, NULL}, + [59] = {100, {.tv_sec = 1, .tv_usec = 0}, 101, NULL}, + [60] = {100, {.tv_sec = 1, .tv_usec = 1}, 102, NULL}, + [61] = {100, {.tv_sec = 1, .tv_usec = 2}, 102, NULL}, + /* .tv_sec ~ INT32_MAX/1000000 */ + [62] = {100, {.tv_sec = 2147, .tv_usec = 999999}, 214801, NULL}, + [63] = {100, {.tv_sec = 2148, .tv_usec = 0}, 214801, NULL}, + [64] = {100, {.tv_sec = 2148, .tv_usec = 1}, 214802, NULL}, + [65] = {100, {.tv_sec = 2148, .tv_usec = 2}, 214802, NULL}, + /* .tv_sec ~ INT32_MAX/hz */ + [66] = {100, {.tv_sec = 21474836, .tv_usec = 439999}, 2147483645, + NULL}, + [67] = {100, {.tv_sec = 21474836, .tv_usec = 440000}, 2147483645, + NULL}, + [68] = {100, {.tv_sec = 21474836, .tv_usec = 440001}, 2147483646, + NULL}, + [69] = {100, {.tv_sec = 21474836, .tv_usec = 440002}, 2147483646, + NULL}, + [70] = {100, {.tv_sec = 21474836, .tv_usec = 449999}, 2147483646, + NULL}, + [71] = {100, {.tv_sec = 21474836, .tv_usec = 450000}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [72] = {100, {.tv_sec = 21474836, .tv_usec = 450001}, 2147483647, + NULL}, + [73] = {100, {.tv_sec = 21474836, .tv_usec = 450002}, 2147483647, + NULL}, + [74] = {100, {.tv_sec = 21474836, .tv_usec = 459999}, 2147483647, + NULL}, + [75] = {100, {.tv_sec = 21474836, .tv_usec = 460000}, 2147483647, + NULL}, + [76] = {100, {.tv_sec = 21474836, .tv_usec = 460001}, 2147483647, + NULL}, + [77] = {100, {.tv_sec = 21474836, .tv_usec = 460002}, 2147483647, + NULL}, + [78] = {100, {.tv_sec = 21474836, .tv_usec = 999999}, 2147483647, + NULL}, + [79] = {100, {.tv_sec = 21474837, .tv_usec = 0}, 2147483647, + NULL}, + [80] = {100, {.tv_sec = 21474837, .tv_usec = 1}, 2147483647, + NULL}, + [81] = {100, {.tv_sec = 21474837, .tv_usec = 2}, 2147483647, + NULL}, + [82] = {100, {.tv_sec = 21474837, .tv_usec = 2}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000 */ + [83] = {100, {.tv_sec = 9223372036854, .tv_usec = 999999}, + INT_MAX, NULL}, + [84] = {100, {.tv_sec = 9223372036855, .tv_usec = 0}, + INT_MAX, NULL}, + [85] = {100, {.tv_sec = 9223372036855, .tv_usec = 1}, + INT_MAX, NULL}, + [86] = {100, {.tv_sec = 9223372036855, .tv_usec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [87] = {100, {.tv_sec = 92233720368547758, .tv_usec = 999999}, + INT_MAX, NULL}, + [88] = {100, {.tv_sec = 92233720368547758, .tv_usec = 0}, + INT_MAX, NULL}, + [89] = {100, {.tv_sec = 92233720368547758, .tv_usec = 1}, + INT_MAX, NULL}, + [90] = {100, {.tv_sec = 92233720368547758, .tv_usec = 2}, + INT_MAX, NULL}, + [91] = {100, {.tv_sec = (time_t)INT_MAX + 1, .tv_usec = 123456}, + INT_MAX, NULL}, + + /* + * hz = 1000 + */ + + [92] = {1000, {.tv_sec = -1, .tv_usec = 0}, 0, NULL}, + [93] = {1000, {.tv_sec = -1, .tv_usec = 999999}, 0, NULL}, + [94] = {1000, {.tv_sec = 0, .tv_usec = 0}, 0, NULL}, + [95] = {1000, {.tv_sec = 0, .tv_usec = 1}, 2, NULL}, + [96] = {1000, {.tv_sec = 0, .tv_usec = 2}, 2, NULL}, + [97] = {1000, {.tv_sec = 0, .tv_usec = 999}, 2, NULL}, + [98] = {1000, {.tv_sec = 0, .tv_usec = 1000}, 2, NULL}, + [99] = {1000, {.tv_sec = 0, .tv_usec = 1001}, 3, NULL}, + [100] = {1000, {.tv_sec = 0, .tv_usec = 1002}, 3, NULL}, + [101] = {1000, {.tv_sec = 0, .tv_usec = 1999}, 3, NULL}, + [102] = {1000, {.tv_sec = 0, .tv_usec = 2000}, 3, NULL}, + [103] = {1000, {.tv_sec = 0, .tv_usec = 2001}, 4, NULL}, + [104] = {1000, {.tv_sec = 0, .tv_usec = 2002}, 4, NULL}, + [105] = {1000, {.tv_sec = 0, .tv_usec = 999999}, 1001, NULL}, + [106] = {1000, {.tv_sec = 1, .tv_usec = 0}, 1001, NULL}, + [107] = {1000, {.tv_sec = 1, .tv_usec = 1}, 1002, NULL}, + [108] = {1000, {.tv_sec = 1, .tv_usec = 2}, 1002, NULL}, + /* .tv_sec ~ INT_MAX/1000000 */ + [109] = {1000, {.tv_sec = 2147, .tv_usec = 999999}, 2148001, NULL}, + [110] = {1000, {.tv_sec = 2148, .tv_usec = 0}, 2148001, NULL}, + [111] = {1000, {.tv_sec = 2148, .tv_usec = 1}, 2148002, NULL}, + [112] = {1000, {.tv_sec = 2148, .tv_usec = 2}, 2148002, NULL}, + /* .tv_sec ~ INT_MAX/hz */ + [113] = {1000, {.tv_sec = 2147483, .tv_usec = 643999}, 2147483645, + NULL}, + [114] = {1000, {.tv_sec = 2147483, .tv_usec = 644000}, 2147483645, + NULL}, + [115] = {1000, {.tv_sec = 2147483, .tv_usec = 644001}, 2147483646, + NULL}, + [116] = {1000, {.tv_sec = 2147483, .tv_usec = 644002}, 2147483646, + NULL}, + [117] = {1000, {.tv_sec = 2147483, .tv_usec = 644999}, 2147483646, + NULL}, + [118] = {1000, {.tv_sec = 2147483, .tv_usec = 645000}, 2147483646, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [119] = {1000, {.tv_sec = 2147483, .tv_usec = 645001}, 2147483647, + NULL}, + [120] = {1000, {.tv_sec = 2147483, .tv_usec = 645002}, 2147483647, + NULL}, + [121] = {1000, {.tv_sec = 2147483, .tv_usec = 645999}, 2147483647, + NULL}, + [122] = {1000, {.tv_sec = 2147483, .tv_usec = 646000}, 2147483647, + NULL}, + [123] = {1000, {.tv_sec = 2147483, .tv_usec = 646001}, 2147483647, + NULL}, + [124] = {1000, {.tv_sec = 2147483, .tv_usec = 646002}, 2147483647, + NULL}, + [125] = {1000, {.tv_sec = 2147483, .tv_usec = 699999}, 2147483647, + NULL}, + [126] = {1000, {.tv_sec = 2147484, .tv_usec = 0}, 2147483647, + NULL}, + [127] = {1000, {.tv_sec = 2147484, .tv_usec = 1}, 2147483647, + NULL}, + [128] = {1000, {.tv_sec = 2147484, .tv_usec = 2}, 2147483647, + NULL}, + [129] = {1000, {.tv_sec = 2147484, .tv_usec = 2}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [130] = {1000, {.tv_sec = 9223372036854, .tv_usec = 999999}, + INT_MAX, NULL}, + [131] = {1000, {.tv_sec = 9223372036855, .tv_usec = 0}, + INT_MAX, NULL}, + [132] = {1000, {.tv_sec = 9223372036855, .tv_usec = 1}, + INT_MAX, NULL}, + [133] = {1000, {.tv_sec = 9223372036855, .tv_usec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [134] = {1000, {.tv_sec = 92233720368547758, .tv_usec = 999999}, + INT_MAX, NULL}, + [135] = {1000, {.tv_sec = 92233720368547758, .tv_usec = 0}, + INT_MAX, NULL}, + [136] = {1000, {.tv_sec = 92233720368547758, .tv_usec = 1}, + INT_MAX, NULL}, + [137] = {1000, {.tv_sec = 92233720368547758, .tv_usec = 2}, + INT_MAX, NULL}, + [138] = {1000, {.tv_sec = (time_t)INT_MAX + 1, .tv_usec = 123456}, + INT_MAX, NULL}, + + /* + * hz = 8191, prime non-divisor of 10^k or 2^k + */ + + [139] = {8191, {.tv_sec = -1, .tv_usec = 0}, 0, NULL}, + [140] = {8191, {.tv_sec = -1, .tv_usec = 999999}, 0, NULL}, + [141] = {8191, {.tv_sec = 0, .tv_usec = 0}, 0, NULL}, + [142] = {8191, {.tv_sec = 0, .tv_usec = 1}, 2, NULL}, + [143] = {8191, {.tv_sec = 0, .tv_usec = 2}, 2, NULL}, + [144] = {8191, {.tv_sec = 0, .tv_usec = 121}, 2, NULL}, + [145] = {8191, {.tv_sec = 0, .tv_usec = 122}, 2, NULL}, + [146] = {8191, {.tv_sec = 0, .tv_usec = 123}, 3, NULL}, + [147] = {8191, {.tv_sec = 0, .tv_usec = 242}, 3, NULL}, + [148] = {8191, {.tv_sec = 0, .tv_usec = 243}, 3, NULL}, + [149] = {8191, {.tv_sec = 0, .tv_usec = 244}, 3, NULL}, + [150] = {8191, {.tv_sec = 0, .tv_usec = 245}, 4, NULL}, + [151] = {8191, {.tv_sec = 0, .tv_usec = 246}, 4, NULL}, + [152] = {8191, {.tv_sec = 0, .tv_usec = 999999}, 8192, NULL}, + [153] = {8191, {.tv_sec = 1, .tv_usec = 0}, 8192, NULL}, + [154] = {8191, {.tv_sec = 1, .tv_usec = 1}, 8193, NULL}, + [155] = {8191, {.tv_sec = 1, .tv_usec = 2}, 8193, NULL}, + /* .tv_sec ~ INT_MAX/1000000 */ + [156] = {8191, {.tv_sec = 2147, .tv_usec = 999999}, 17594269, NULL}, + [157] = {8191, {.tv_sec = 2148, .tv_usec = 0}, 17594269, NULL}, + [158] = {8191, {.tv_sec = 2148, .tv_usec = 1}, 17594270, NULL}, + [159] = {8191, {.tv_sec = 2148, .tv_usec = 2}, 17594270, NULL}, + /* .tv_sec ~ INT_MAX/hz */ + [160] = {8191, {.tv_sec = 262176, .tv_usec = 3540}, 2147483646, + NULL}, + [161] = {8191, {.tv_sec = 262176, .tv_usec = 3541}, 2147483647, + NULL}, + [162] = {8191, {.tv_sec = 262176, .tv_usec = 3542}, 2147483647, + NULL}, + /* saturate at INT_MAX = 2^31 - 1 ticks */ + [163] = {8191, {.tv_sec = 262176, .tv_usec = 3662}, 2147483647, + NULL}, + [164] = {8191, {.tv_sec = 262176, .tv_usec = 3663}, 2147483647, + NULL}, + [165] = {8191, {.tv_sec = 262176, .tv_usec = 3664}, 2147483647, + NULL}, + [166] = {8191, {.tv_sec = 262176, .tv_usec = 999999}, 2147483647, + NULL}, + /* .tv_sec ~ INT64_MAX/1000000, overflows to INT_MAX ticks */ + [167] = {8191, {.tv_sec = 9223372036854, .tv_usec = 999999}, + INT_MAX, NULL}, + [168] = {8191, {.tv_sec = 9223372036855, .tv_usec = 0}, + INT_MAX, NULL}, + [169] = {8191, {.tv_sec = 9223372036855, .tv_usec = 1}, + INT_MAX, NULL}, + [170] = {8191, {.tv_sec = 9223372036855, .tv_usec = 2}, + INT_MAX, NULL}, + /* .tv_sec ~ INT64_MAX/hz, overflows to INT_MAX ticks */ + [171] = {8191, {.tv_sec = 92233720368547758, .tv_usec = 999999}, + INT_MAX, NULL}, + [172] = {8191, {.tv_sec = 92233720368547758, .tv_usec = 0}, + INT_MAX, NULL}, + [173] = {8191, {.tv_sec = 92233720368547758, .tv_usec = 1}, + INT_MAX, NULL}, + [174] = {8191, {.tv_sec = 92233720368547758, .tv_usec = 2}, + INT_MAX, NULL}, + [175] = {8191, {.tv_sec = (time_t)INT_MAX + 1, .tv_usec = 123456}, + INT_MAX, NULL}, +}; + +ATF_TC(tvtohz); +ATF_TC_HEAD(tvtohz, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test tvtohz(9)"); +} +ATF_TC_BODY(tvtohz, tc) +{ + size_t i; + + for (i = 0; i < __arraycount(tvtohz_cases); i++) { + const struct tvtohz_case *tv = &tvtohz_cases[i]; + int ticks; + + /* set system parameters */ + hz = tv->tv_hz; + tick = 1000000/hz; + + ticks = tvtohz(&tv->tv_tv); + if (tv->tv_xfail) + atf_tc_expect_fail("%s", tv->tv_xfail); + + /* + * Allow some slop of one part per thousand in the + * arithmetic, but ensure we round up, not down. + * + * XXX Analytically determine error bounds on the + * formulae we use and assess them. + */ + ATF_CHECK_MSG(((unsigned)(ticks - tv->tv_ticks) <= + (unsigned)tv->tv_ticks/1000), + "[%zu] tvtohz(%lld.%06ld sec) @ %d Hz:" + " expected %d, got %d", + i, + (long long)tv->tv_tv.tv_sec, + (long)tv->tv_tv.tv_usec, + tv->tv_hz, + tv->tv_ticks, + ticks); + if (tv->tv_xfail) + atf_tc_expect_pass(); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, itimer_transitions); + ATF_TP_ADD_TC(tp, tstohz); + ATF_TP_ADD_TC(tp, tvtohz); + + return atf_no_error(); +} + diff --git a/kernel/t_unmount.c b/kernel/t_unmount.c new file mode 100644 index 000000000000..41ed39082e61 --- /dev/null +++ b/kernel/t_unmount.c @@ -0,0 +1,106 @@ +/* $NetBSD: t_unmount.c,v 1.4 2024/10/02 17:16:32 bad Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2024\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_unmount.c,v 1.4 2024/10/02 17:16:32 bad Exp $"); + +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/vnode.h> + +#include <rump/rump.h> +#include <rump/rumpvnode_if.h> +#include <rump/rump_syscalls.h> + +#include <fs/tmpfs/tmpfs_args.h> + +#include <atf-c.h> +#include <errno.h> +#include <stdio.h> + +#include "h_macros.h" + +ATF_TC(async); +ATF_TC_HEAD(async, tc) +{ + atf_tc_set_md_var(tc, + "descr", "failed unmount of async fs should stay async"); +} + +#define MP "/mnt" + +ATF_TC_BODY(async, tc) +{ + struct tmpfs_args args; + struct vnode *vp; + extern struct vnode *rumpns_rootvnode; + + RZ(rump_init()); + + memset(&args, 0, sizeof(args)); + args.ta_version = TMPFS_ARGS_VERSION; + args.ta_root_mode = 0777; + + /* create mount point and mount a tmpfs on it */ + RL(rump_sys_mkdir(MP, 0777)); + RL(rump_sys_mount(MOUNT_TMPFS, MP, MNT_ASYNC, &args, sizeof(args))); + + /* make sure the tmpfs is busy */ + RL(rump_sys_chdir(MP)); + + /* need a stable lwp for componentname */ + RZ(rump_pub_lwproc_rfork(RUMP_RFCFDG)); + + /* get vnode of MP, unlocked */ + RZ(rump_pub_namei(RUMP_NAMEI_LOOKUP, 0, MP, NULL, &vp, NULL)); + + /* make sure we didn't just get the root vnode */ + ATF_REQUIRE_MSG((rumpns_rootvnode != vp), "drat! got the root vnode"); + + printf("mnt_iflag & IMNT_ONWORKLIST == %d\n", + (vp->v_mount->mnt_iflag & IMNT_ONWORKLIST) != 0); + + /* can't unmount a busy file system */ + ATF_REQUIRE_ERRNO(EBUSY, rump_sys_unmount(MP, 0) == -1); + + printf("mnt_iflag & IMNT_ONWORKLIST == %d\n", + (vp->v_mount->mnt_iflag & IMNT_ONWORKLIST) != 0); + + + ATF_REQUIRE_MSG(((vp->v_mount->mnt_iflag & IMNT_ONWORKLIST) == 0), + "mount point on syncer work list"); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, async); + + return atf_no_error(); +} diff --git a/lib/csu/h_hello.c b/lib/csu/h_hello.c new file mode 100644 index 000000000000..e39284c2f5c9 --- /dev/null +++ b/lib/csu/h_hello.c @@ -0,0 +1,48 @@ +/* $NetBSD: h_hello.c,v 1.1 2025/04/27 04:09:35 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_hello.c,v 1.1 2025/04/27 04:09:35 riastradh Exp $"); + +#include <stdio.h> +#include <stdlib.h> + +/* + * Force some R_*_RELATIVE-type relocations. + */ +static int foo = 42; +static int *volatile foop = &foo; + +int +main(void) +{ + + printf("%s: Hello, world! %d\n", getprogname(), *foop); + fflush(stdout); + return ferror(stdout); +} diff --git a/lib/csu/h_preinit_array.c b/lib/csu/h_preinit_array.c new file mode 100644 index 000000000000..36fa37ff340b --- /dev/null +++ b/lib/csu/h_preinit_array.c @@ -0,0 +1,16 @@ +static int x = 1; + +static void +foo(void) +{ + x--; +} + +static void (*fp) (void) __attribute__((__section__(".preinit_array"), __used__)) = + foo; + +int +main(void) +{ + return x; +} diff --git a/lib/csu/t_hello.sh b/lib/csu/t_hello.sh new file mode 100644 index 000000000000..b72f62885476 --- /dev/null +++ b/lib/csu/t_hello.sh @@ -0,0 +1,150 @@ +# $NetBSD: t_hello.sh,v 1.3 2025/05/02 23:04:06 riastradh Exp $ +# +# Copyright (c) 2025 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +checksupport() +{ + local prog + + prog=$1 + test -f "$(atf_get_srcdir)/${prog}" || atf_skip "not supported" +} + +checkrun() +{ + local prog + + prog=$1 + atf_check -o inline:"${prog}: Hello, world! 42\n" \ + "$(atf_get_srcdir)/${prog}" +} + +cleanup() +{ + local prog + + prog=$1 + test -f "${prog}.core" || return 0 + readelf -rs "$(atf_get_srcdir)/${prog}" + gdb -batch -ex bt -ex 'info registers' -ex disas \ + "$(atf_get_srcdir)/${prog}" "${prog}.core" +} + +atf_test_case dynamic cleanup +dynamic_head() +{ + atf_set "descr" "Test a dynamic executable" +} +dynamic_body() +{ + checksupport h_hello_dyn + checkrun h_hello_dyn +} +dynamic_cleanup() +{ + cleanup h_hello_dyn +} + +atf_test_case dynamicpie cleanup +dynamicpie_head() +{ + atf_set "descr" "Test a dynamic position-independent executable" +} +dynamicpie_body() +{ + checksupport h_hello_dynpie + checkrun h_hello_dynpie +} +dynamicpie_cleanup() +{ + cleanup h_hello_dynpie +} + +atf_test_case relr cleanup +relr_head() +{ + atf_set "descr" "Test a static PIE executable with RELR relocations" +} +relr_body() +{ + checksupport h_hello_relr + case `uname -p` in + i386|x86_64) + ;; + *) atf_expect_fail "PR lib/59359: static pies are broken" + ;; + esac + checkrun h_hello_relr +} +relr_cleanup() +{ + cleanup h_hello_relr +} + +atf_test_case static cleanup +static_head() +{ + atf_set "descr" "Test a static executable" +} +static_body() +{ + checksupport h_hello_sta + checkrun h_hello_sta +} +static_cleanup() +{ + cleanup h_hello_sta +} + +atf_test_case staticpie cleanup +staticpie_head() +{ + atf_set "descr" "Test a static position-independent executable" +} +staticpie_body() +{ + checksupport h_hello_stapie + case `uname -p` in + i386|x86_64) + ;; + *) atf_expect_fail "PR lib/59359: static pies are broken" + ;; + esac + checkrun h_hello_stapie +} +staticpie_cleanup() +{ + cleanup h_hello_stapie +} + +atf_init_test_cases() +{ + atf_add_test_case dynamic + atf_add_test_case dynamicpie + atf_add_test_case relr + atf_add_test_case static + atf_add_test_case staticpie +} diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc new file mode 100644 index 000000000000..01b5f23410c8 --- /dev/null +++ b/lib/libc/gen/Makefile.inc @@ -0,0 +1 @@ +.include "../Makefile.inc" diff --git a/lib/libc/gen/h_ctype_abuse.c b/lib/libc/gen/h_ctype_abuse.c new file mode 100644 index 000000000000..fdff8552f8f4 --- /dev/null +++ b/lib/libc/gen/h_ctype_abuse.c @@ -0,0 +1,138 @@ +/* $NetBSD: h_ctype_abuse.c,v 1.2 2025/09/15 17:32:01 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Helper program to verify effects of ctype(3) abuse. + * + * NOTE: This program intentionally triggers undefined behaviour by + * passing int values to the ctype(3) functions which are neither EOF + * nor representable by unsigned char. The purpose is to verify that + * NetBSD's ctype(3) _does not_ trap the undefined behaviour when the + * environment variable LIBC_ALLOWCTYPEABUSE. (It does not check + * anything about the results, which are perforce nonsense -- just that + * it gets a result without crashing.) + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_ctype_abuse.c,v 1.2 2025/09/15 17:32:01 riastradh Exp $"); + +#include <ctype.h> +#include <err.h> +#include <limits.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define FOREACHCTYPE(M) \ + M(ISALPHA, isalpha) \ + M(ISUPPER, isupper) \ + M(ISLOWER, islower) \ + M(ISDIGIT, isdigit) \ + M(ISXDIGIT, isxdigit) \ + M(ISALNUM, isalnum) \ + M(ISSPACE, isspace) \ + M(ISPUNCT, ispunct) \ + M(ISPRINT, isprint) \ + M(ISGRAPH, isgraph) \ + M(ISCNTRL, iscntrl) \ + M(ISBLANK, isblank) \ + M(TOUPPER, toupper) \ + M(TOLOWER, tolower) + +int +main(int argc, char **argv) +{ + enum { +#define M(upper, lower) upper, + FOREACHCTYPE(M) +#undef M + } fn; + enum { + MACRO, + FUNCTION, + } mode; + int ch; + volatile int result; + + setprogname(argv[0]); + if (argc != 3 && argc != 4) { + errx(1, "Usage: %s <function> <mode> [<locale>]", + getprogname()); + } + +#define M(upper, lower) \ + else if (strcmp(argv[1], #lower) == 0) \ + fn = upper; + + if (0) + ; + FOREACHCTYPE(M) + else + errx(1, "unknown ctype function"); +#undef M + + if (strcmp(argv[2], "macro") == 0) + mode = MACRO; + else if (strcmp(argv[2], "function") == 0) + mode = FUNCTION; + else + errx(1, "unknown usage mode"); + + if (argc == 4) { + if (setlocale(LC_CTYPE, argv[3]) == NULL) + err(1, "setlocale"); + } + + /* + * Make sure we cover EOF as well. + */ + __CTASSERT(CHAR_MIN == 0 || CHAR_MIN <= EOF); + __CTASSERT(EOF <= UCHAR_MAX); + + for (ch = (CHAR_MIN == 0 ? EOF : CHAR_MIN); ch <= UCHAR_MAX; ch++) { + switch (fn) { +#define M(upper, lower) \ + case upper: \ + switch (mode) { \ + case MACRO: \ + result = lower(ch); \ + break; \ + case FUNCTION: \ + result = (lower)(ch); \ + break; \ + } \ + break; + FOREACHCTYPE(M) +#undef M + } + (void)result; + } + + return 0; +} diff --git a/lib/libc/gen/h_execsig.c b/lib/libc/gen/h_execsig.c new file mode 100644 index 000000000000..a954ca071094 --- /dev/null +++ b/lib/libc/gen/h_execsig.c @@ -0,0 +1,55 @@ +/* $NetBSD: h_execsig.c,v 1.1 2025/03/13 01:27:27 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_execsig.c,v 1.1 2025/03/13 01:27:27 riastradh Exp $"); + +/* + * Helper program for testing signal delivery during execve(2) and + * posix_spawn(2). The caller will: + * + * 1. fork and exec, or spawn + * 2. kill the child + * 3. write a byte to be read from the child's stdin + * + * Since the caller issues syscalls in that order, the signal should be + * delivered to the child first, and it should be interrupted by a + * signal before it returnsa byte from read(2). + */ + +#include <err.h> +#include <unistd.h> + +int +main(void) +{ + + if (read(STDIN_FILENO, (char[]){0}, 1) == -1) + err(1, "read"); + return 0; +} diff --git a/lib/libc/gen/t_arc4random.c b/lib/libc/gen/t_arc4random.c new file mode 100644 index 000000000000..b26c1b8a931a --- /dev/null +++ b/lib/libc/gen/t_arc4random.c @@ -0,0 +1,670 @@ +/* $NetBSD: t_arc4random.c,v 1.5 2025/03/09 18:11:55 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _REENTRANT + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_arc4random.c,v 1.5 2025/03/09 18:11:55 riastradh Exp $"); + +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <err.h> +#include <fcntl.h> +#include <paths.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "arc4random.h" +#include "reentrant.h" +#include "h_macros.h" + +/* + * iszero(buf, len) + * + * True if len bytes at buf are all zero, false if any one of them + * is nonzero. + */ +static bool +iszero(const void *buf, size_t len) +{ + const unsigned char *p = buf; + size_t i; + + for (i = 0; i < len; i++) { + if (p[i] != 0) + return false; + } + return true; +} + +/* + * arc4random_prng() + * + * Get a pointer to the current arc4random state, without updating + * any of the state, not even lazy initialization. + */ +static struct arc4random_prng * +arc4random_prng(void) +{ + struct arc4random_prng *prng = NULL; + + /* + * If arc4random has been initialized and there is a thread key + * (i.e., libc was built with _REENTRANT), get the thread-local + * arc4random state if there is one. + */ + if (arc4random_global.per_thread) + prng = thr_getspecific(arc4random_global.thread_key); + + /* + * If we couldn't get the thread-local state, get the global + * state instead. + */ + if (prng == NULL) + prng = &arc4random_global.prng; + + return prng; +} + +/* + * arc4random_global_buf(buf, len) + * + * Same as arc4random_buf, but force use of the global state. + * Must happen before any other use of arc4random. + */ +static void +arc4random_global_buf(void *buf, size_t len) +{ + struct rlimit rlim, orlim; + struct arc4random_prng *prng; + + /* + * Save the address space limit. + */ + RL(getrlimit(RLIMIT_AS, &orlim)); + memcpy(&rlim, &orlim, sizeof(rlim)); + + /* + * Get a sample while the address space limit is zero. This + * should try, and fail, to allocate a thread-local arc4random + * state with mmap(2). + */ + rlim.rlim_cur = 0; + RL(setrlimit(RLIMIT_AS, &rlim)); + arc4random_buf(buf, len); + RL(setrlimit(RLIMIT_AS, &orlim)); + + /* + * Restore the address space limit. + */ + RL(setrlimit(RLIMIT_AS, &orlim)); + + /* + * Verify the PRNG is the global one, not the thread-local one, + * and that it was initialized. + */ + prng = arc4random_prng(); + ATF_CHECK_EQ(prng, &arc4random_global.prng); + ATF_CHECK(!iszero(&prng->arc4_prng, sizeof(prng->arc4_prng))); + ATF_CHECK(prng->arc4_epoch != 0); +} + +/* + * arc4random_global_thread(cookie) + * + * Start routine for a thread that just grabs an output from the + * global state. + */ +static void * +arc4random_global_thread(void *cookie) +{ + unsigned char buf[32]; + + arc4random_global_buf(buf, sizeof(buf)); + + return NULL; +} + +ATF_TC(addrandom); +ATF_TC_HEAD(addrandom, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test arc4random_addrandom updates the state"); +} +ATF_TC_BODY(addrandom, tc) +{ + unsigned char buf[32], zero32[32] = {0}; + struct arc4random_prng *prng, copy; + + /* + * Get a sample to start things off. + */ + arc4random_buf(buf, sizeof(buf)); + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + + /* + * By this point, the global state must be initialized -- if + * not, the process should have aborted. + */ + ATF_CHECK(arc4random_global.initialized); + + /* + * Get the PRNG, global or local. By this point, the PRNG + * state should be nonzero (with overwhelmingly high + * probability) and the epoch should also be nonzero. + */ + prng = arc4random_prng(); + ATF_CHECK(!iszero(&prng->arc4_prng, sizeof(prng->arc4_prng))); + ATF_CHECK(prng->arc4_epoch != 0); + + /* + * Save a copy and update the state with arc4random_addrandom. + */ + copy = *prng; + arc4random_addrandom(zero32, sizeof(zero32)); + + /* + * The state should have changed. (The epoch may or may not.) + */ + ATF_CHECK(memcmp(&prng->arc4_prng, ©.arc4_prng, + sizeof(copy.arc4_prng)) != 0); + + /* + * Save a copy and update the state with arc4random_stir. + */ + copy = *prng; + arc4random_stir(); + + /* + * The state should have changed. (The epoch may or may not.) + */ + ATF_CHECK(memcmp(&prng->arc4_prng, ©.arc4_prng, + sizeof(copy.arc4_prng)) != 0); +} + +ATF_TC(consolidate); +ATF_TC_HEAD(consolidate, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test consolidating entropy resets the epoch"); +} +ATF_TC_BODY(consolidate, tc) +{ + unsigned char buf[32]; + struct arc4random_prng *local, *global = &arc4random_global.prng; + unsigned localepoch, globalepoch; + const int consolidate = 1; + pthread_t thread; + + /* + * Get a sample from the global state to make sure the global + * state is initialized. Remember the epoch. + */ + arc4random_global_buf(buf, sizeof(buf)); + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + ATF_CHECK(!iszero(&global->arc4_prng, sizeof(global->arc4_prng))); + ATF_CHECK((globalepoch = global->arc4_epoch) != 0); + + /* + * Get a sample from the local state too to make sure the local + * state is initialized. Remember the epoch. + */ + arc4random_buf(buf, sizeof(buf)); + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + local = arc4random_prng(); + ATF_CHECK(!iszero(&local->arc4_prng, sizeof(local->arc4_prng))); + ATF_CHECK((localepoch = local->arc4_epoch) != 0); + + /* + * Trigger entropy consolidation. + */ + RL(sysctlbyname("kern.entropy.consolidate", /*oldp*/NULL, /*oldlen*/0, + &consolidate, sizeof(consolidate))); + + /* + * Verify the epoch cache isn't changed yet until we ask for + * more data. + */ + ATF_CHECK_EQ_MSG(globalepoch, global->arc4_epoch, + "global epoch was %u, now %u", globalepoch, global->arc4_epoch); + ATF_CHECK_EQ_MSG(localepoch, local->arc4_epoch, + "local epoch was %u, now %u", localepoch, local->arc4_epoch); + + /* + * Request new output and verify the local epoch cache has + * changed. + */ + arc4random_buf(buf, sizeof(buf)); + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + ATF_CHECK_MSG(localepoch != local->arc4_epoch, + "local epoch unchanged from %u", localepoch); + + /* + * Create a new thread to grab output from the global state, + * wait for it to complete, and verify the global epoch cache + * has changed. (Now that we have already used the local state + * in this thread, we can't use the global state any more.) + */ + RZ(pthread_create(&thread, NULL, &arc4random_global_thread, NULL)); + RZ(pthread_join(thread, NULL)); + ATF_CHECK_MSG(globalepoch != global->arc4_epoch, + "global epoch unchanged from %u", globalepoch); +} + +ATF_TC(chroot); +ATF_TC_HEAD(chroot, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test arc4random in an empty chroot"); + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(chroot, tc) +{ + pid_t pid; + int status; + + /* + * Create an empty chroot. + */ + RL(mkdir("root", 0500)); + + /* + * In a child process, enter the chroot and verify that we + * can't open /dev/urandom but we can use arc4random. + * + * (atf gets unhappy if we chroot in the same process, when it + * later tries to create a results file.) + */ + RL(pid = fork()); + if (pid == 0) { + unsigned char buf[32] = {0}; + + if (chroot("root") == -1) + err(1, "chroot"); + if (open(_PATH_URANDOM, O_RDONLY) != -1) + errx(1, "open /dev/urandom must fail in empty chroot"); + if (errno != ENOENT) { + err(1, "expected open to fail with %d=ENOENT, not %d", + ENOENT, errno); + } + arc4random_buf(buf, sizeof(buf)); + if (iszero(buf, sizeof(buf))) /* Pr[fail] = 1/2^256 */ + errx(1, "arc4random returned all-zero"); + if (arc4random_prng()->arc4_epoch == 0) + errx(1, "arc4random failed to observe entropy epoch"); + _exit(0); + } + + /* + * Wait for the child process to finish. + */ + RL(waitpid(pid, &status, 0)); + ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0, + "child exited status 0x%x", status); +} + +ATF_TC(fdlimit); +ATF_TC_HEAD(fdlimit, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test arc4random works even if we have hit the fd limit"); +} +ATF_TC_BODY(fdlimit, tc) +{ + pid_t pid; + int status; + + /* + * In a child process, clamp down on the file descriptor + * resource limit and verify that we can't open /dev/urandom + * but we can use arc4random. + * + * (atf gets unhappy if we chroot in the same process, when it + * later tries to create a results file.) + */ + RL(pid = fork()); + if (pid == 0) { + struct rlimit rlim = {.rlim_cur = 0, .rlim_max = 0}; + unsigned char buf[32] = {0}; + + if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) + err(1, "setrlimit(RLIMIT_NOFILE)"); + if (open(_PATH_URANDOM, O_RDONLY) != -1) + errx(1, "open must fail with zero RLIMIT_NOFILE"); + if (errno != EMFILE) { + err(1, "expected open to fail with %d=EMFILE, not %d", + EMFILE, errno); + } + arc4random_buf(buf, sizeof(buf)); + if (iszero(buf, sizeof(buf))) /* Pr[fail] = 1/2^256 */ + errx(1, "arc4random returned all-zero"); + if (arc4random_prng()->arc4_epoch == 0) + errx(1, "arc4random failed to observe entropy epoch"); + _exit(0); + } + + /* + * Wait for the child process to finish. + */ + RL(waitpid(pid, &status, 0)); + ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0, + "child exited status 0x%x", status); +} + +ATF_TC(fork); +ATF_TC_HEAD(fork, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test fork zeros the state and gets independent state"); +} +ATF_TC_BODY(fork, tc) +{ + unsigned char buf[32]; + struct arc4random_prng *local, *global = &arc4random_global.prng; + struct arc4random_prng childstate; + int fd[2]; + pid_t child, pid; + ssize_t nread; + int status; + + /* + * Get a sample from the global state to make sure the global + * state is initialized. + */ + arc4random_global_buf(buf, sizeof(buf)); + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + ATF_CHECK(!iszero(&global->arc4_prng, sizeof(global->arc4_prng))); + ATF_CHECK(global->arc4_epoch != 0); + + /* + * Get a sample from the local state too to make sure the local + * state is initialized. + */ + arc4random_buf(buf, sizeof(buf)); + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + local = arc4random_prng(); + ATF_CHECK(!iszero(&local->arc4_prng, sizeof(local->arc4_prng))); + ATF_CHECK(local->arc4_epoch != 0); + + /* + * Create a pipe to transfer the state from child to parent. + */ + RL(pipe(fd)); + + /* + * Fork a child. + */ + RL(child = fork()); + if (child == 0) { + status = 0; + + /* + * Verify the states have been zero'd on fork. + */ + if (!iszero(local, sizeof(*local))) { + fprintf(stderr, "failed to zero local state\n"); + status = 1; + } + if (!iszero(global, sizeof(*global))) { + fprintf(stderr, "failed to zero global state\n"); + status = 1; + } + + /* + * Verify we generate nonzero output. + */ + arc4random_buf(buf, sizeof(buf)); + if (iszero(buf, sizeof(buf))) { + fprintf(stderr, "failed to generate nonzero output\n"); + status = 1; + } + + /* + * Share the state to compare with parent. + */ + if ((size_t)write(fd[1], local, sizeof(*local)) != + sizeof(*local)) { + fprintf(stderr, "failed to share local state\n"); + status = 1; + } + _exit(status); + } + + /* + * Verify the global state has been zeroed as expected. (This + * way it is never available to the child, even shortly after + * the fork syscall returns before the atfork handler is + * called.) + */ + ATF_CHECK(iszero(global, sizeof(*global))); + + /* + * Read the state from the child. + */ + RL(nread = read(fd[0], &childstate, sizeof(childstate))); + ATF_CHECK_EQ_MSG(nread, sizeof(childstate), + "nread=%zu sizeof(childstate)=%zu", nread, sizeof(childstate)); + + /* + * Verify the child state is distinct. (The global state has + * been zero'd so it's OK it if coincides.) Check again after + * we grab another output. + */ + ATF_CHECK(memcmp(local, &childstate, sizeof(*local)) != 0); + arc4random_buf(buf, sizeof(buf)); + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + ATF_CHECK(memcmp(local, &childstate, sizeof(*local)) != 0); + + /* + * Wait for the child to complete and verify it passed. + */ + RL(pid = waitpid(child, &status, 0)); + ATF_CHECK_EQ_MSG(status, 0, "child exited with nonzero status=%d", + status); +} + +ATF_TC(global_aslimit); +ATF_TC_HEAD(global_aslimit, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test the global state is used when address space limit is hit"); +} +ATF_TC_BODY(global_aslimit, tc) +{ + unsigned char buf[32], buf1[32]; + + /* + * Get a sample from the global state (and verify it was using + * the global state). + */ + arc4random_global_buf(buf, sizeof(buf)); + + /* + * Verify we got a sample. + */ + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + + /* + * Get a sample from whatever state and make sure it wasn't + * repeated, which happens only with probability 1/2^256. + */ + arc4random_buf(buf1, sizeof(buf1)); + ATF_CHECK(!iszero(buf1, sizeof(buf1))); /* Pr[fail] = 1/2^256 */ + ATF_CHECK(memcmp(buf, buf1, sizeof(buf)) != 0); +} + +ATF_TC(global_threadkeylimit); +ATF_TC_HEAD(global_threadkeylimit, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test the global state is used we run out of thread keys"); +} +ATF_TC_BODY(global_threadkeylimit, tc) +{ + unsigned char buf[32], buf1[32]; + + /* + * Get a sample from the global state (and verify it was using + * the global state). + */ + arc4random_global_buf(buf, sizeof(buf)); + + /* + * Verify we got a sample. + */ + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + + /* + * Artificially disable the per-thread state, make it an + * invalid thread key altogether, and clear the epoch. Make + * sure we're using the global PRNG state now. + */ + arc4random_global.per_thread = false; + memset(&arc4random_global.thread_key, 0x5a, + sizeof(arc4random_global.thread_key)); + arc4random_global.prng.arc4_epoch = 0; + ATF_CHECK(arc4random_prng() == &arc4random_global.prng); + + /* + * Get a sample again and make sure it wasn't repeated, which + * happens only with probability 1/2^256. + */ + arc4random_buf(buf1, sizeof(buf1)); + ATF_CHECK(!iszero(buf1, sizeof(buf1))); /* Pr[fail] = 1/2^256 */ + ATF_CHECK(memcmp(buf, buf1, sizeof(buf)) != 0); + + /* + * Verify this had the effect of updating the global epoch, + * meaning we used the global state and not the per-thread + * state. + */ + ATF_CHECK(arc4random_global.prng.arc4_epoch != 0); +} + +ATF_TC(local); +ATF_TC_HEAD(local, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test arc4random uses thread-local state"); + /* XXX skip if libc was built without _REENTRANT */ +} +ATF_TC_BODY(local, tc) +{ + unsigned char buf[32], buf1[32]; + struct arc4random_prng *prng; + + /* + * Get a sample to start things off. + */ + arc4random_buf(buf, sizeof(buf)); + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + + /* + * Verify the arc4random state is _not_ the global state. + */ + prng = arc4random_prng(); + ATF_CHECK(prng != &arc4random_global.prng); + ATF_CHECK(!iszero(&prng->arc4_prng, sizeof(prng->arc4_prng))); + ATF_CHECK(prng->arc4_epoch != 0); + + /* + * Get another sample and make sure it wasn't repeated, which + * happens only with probability 1/2^256. + */ + arc4random_buf(buf1, sizeof(buf1)); + ATF_CHECK(!iszero(buf1, sizeof(buf1))); /* Pr[fail] = 1/2^256 */ + ATF_CHECK(memcmp(buf, buf1, sizeof(buf)) != 0); +} + +ATF_TC(stackfallback); +ATF_TC_HEAD(stackfallback, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test arc4random with pthread_atfork and thr_keycreate failure"); +} +ATF_TC_BODY(stackfallback, tc) +{ + unsigned char buf[32], buf1[32]; + struct arc4random_prng *local; + + /* + * Get a sample to start things off. This makes the library + * gets initialized. + */ + arc4random_buf(buf, sizeof(buf)); + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + + /* + * Clear the arc4random global state, and the local state if it + * exists, and pretend pthread_atfork and thr_keycreate had + * both failed. + */ + memset(&arc4random_global.prng, 0, sizeof(arc4random_global.prng)); + if ((local = arc4random_prng()) != NULL) + memset(local, 0, sizeof(*local)); + arc4random_global.forksafe = false; + arc4random_global.per_thread = false; + + /* + * Make sure it still works to get a sample. + */ + arc4random_buf(buf1, sizeof(buf1)); + ATF_CHECK(!iszero(buf, sizeof(buf))); /* Pr[fail] = 1/2^256 */ + ATF_CHECK(memcmp(buf, buf1, sizeof(buf)) != 0); + + /* + * Make sure the global and local epochs did not change. + */ + ATF_CHECK_EQ_MSG(arc4random_global.prng.arc4_epoch, 0, + "global epoch: %d", arc4random_global.prng.arc4_epoch); + if (local != NULL) { + ATF_CHECK_EQ_MSG(local->arc4_epoch, 0, + "local epoch: %d", local->arc4_epoch); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, addrandom); + ATF_TP_ADD_TC(tp, chroot); + ATF_TP_ADD_TC(tp, consolidate); + ATF_TP_ADD_TC(tp, fdlimit); + ATF_TP_ADD_TC(tp, fork); + ATF_TP_ADD_TC(tp, global_aslimit); + ATF_TP_ADD_TC(tp, global_threadkeylimit); + ATF_TP_ADD_TC(tp, local); + ATF_TP_ADD_TC(tp, stackfallback); + + return atf_no_error(); +} diff --git a/lib/libc/gen/t_ctype.c b/lib/libc/gen/t_ctype.c new file mode 100644 index 000000000000..ee4db34304b7 --- /dev/null +++ b/lib/libc/gen/t_ctype.c @@ -0,0 +1,1236 @@ +/* $NetBSD: t_ctype.c,v 1.12 2025/09/15 00:11:55 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Tests for the ctype(3) character classification macros. + * + * NOTE: These tests intentionally trigger undefined behaviour by + * passing int values to the ctype(3) functions which are neither EOF + * nor representable by unsigned char. The purpose is to verify + * NetBSD's intentional trapping of this undefined behaviour -- or + * intentional allowing of this undefined behaviour, when the + * environment variable LIBC_ALLOWCTYPEABUSE is set. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_ctype.c,v 1.12 2025/09/15 00:11:55 riastradh Exp $"); + +#include <sys/wait.h> + +#include <atf-c.h> +#include <ctype.h> +#include <locale.h> +#include <limits.h> +#include <setjmp.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + +#include "h_macros.h" + +#ifdef __CHAR_UNSIGNED__ +enum { CHAR_UNSIGNED = 1 }; +#else +enum { CHAR_UNSIGNED = 0 }; +#endif + +/* + * libc has a guard page for the LC_CTYPE=C ctype(3) tables only on + * some platforms. We skip it if char is unsigned (in which case the + * common kind of ctype(3) abuse is unlikely). We also skip it in + * static builds -- this is determined in the Makefile. + */ +#ifndef _CTYPE_GUARD_PAGE +# ifdef __CHAR_UNSIGNED__ +# define _CTYPE_GUARD_PAGE 0 +# else +# define _CTYPE_GUARD_PAGE 1 +# endif +#endif + +static const char *const locales[] = { "C.UTF-8", "fr_FR.ISO8859-1", "C" }; + +static int isalpha_wrapper(int ch) { return isalpha(ch); } +static int isupper_wrapper(int ch) { return isupper(ch); } +static int islower_wrapper(int ch) { return islower(ch); } +static int isdigit_wrapper(int ch) { return isdigit(ch); } +static int isxdigit_wrapper(int ch) { return isxdigit(ch); } +static int isalnum_wrapper(int ch) { return isalnum(ch); } +static int isspace_wrapper(int ch) { return isspace(ch); } +static int ispunct_wrapper(int ch) { return ispunct(ch); } +static int isprint_wrapper(int ch) { return isprint(ch); } +static int isgraph_wrapper(int ch) { return isgraph(ch); } +static int iscntrl_wrapper(int ch) { return iscntrl(ch); } +static int isblank_wrapper(int ch) { return isblank(ch); } +static int toupper_wrapper(int ch) { return toupper(ch); } +static int tolower_wrapper(int ch) { return tolower(ch); } + +jmp_buf env; + +static void +handle_signal(int signo) +{ + + longjmp(env, 1); +} + +static void +test_abuse(const char *name, int (*ctypefn)(int)) +{ + volatile int ch; /* for longjmp */ + + for (ch = CHAR_MIN; ch < 0; ch++) { + volatile int result; + + if (ch == EOF) + continue; + ATF_REQUIRE_MSG(ch != (int)(unsigned char)ch, "ch=%d", ch); + if (setjmp(env) == 0) { + REQUIRE_LIBC(signal(SIGABRT, &handle_signal), SIG_ERR); + REQUIRE_LIBC(signal(SIGSEGV, &handle_signal), SIG_ERR); + result = (*ctypefn)(ch); + REQUIRE_LIBC(signal(SIGABRT, SIG_DFL), SIG_ERR); + REQUIRE_LIBC(signal(SIGSEGV, SIG_DFL), SIG_ERR); + atf_tc_fail_nonfatal("%s failed to detect invalid %d," + " returned %d", + name, ch, result); + } else { + REQUIRE_LIBC(signal(SIGABRT, SIG_DFL), SIG_ERR); + REQUIRE_LIBC(signal(SIGSEGV, SIG_DFL), SIG_ERR); + } + } + + for (; ch <= CHAR_MAX; ch++) + ATF_REQUIRE_MSG(ch == (int)(unsigned char)ch, "ch=%d", ch); +} + +static void +test_abuse_in_locales(const char *name, int (*ctypefn)(int), bool macro) +{ + size_t i; + + for (i = 0; i < __arraycount(locales); i++) { + char buf[128]; + + if (!_CTYPE_GUARD_PAGE && macro && + strcmp(locales[i], "C") == 0) { + fprintf(stderr, "skip LC_CTYPE=C ctype(3) abuse --" + " no libc guard page on this platform\n"); + } + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, locales[i]) != NULL, + "locales[i]=%s", locales[i]); + snprintf(buf, sizeof(buf), "[%s]%s", locales[i], name); + test_abuse(buf, ctypefn); + } +} + +static void +test_use(const char *name, int (*ctypefn)(int)) +{ + volatile int ch; /* for longjmp */ + + for (ch = EOF; ch <= CHAR_MAX; ch = (ch == EOF ? 0 : ch + 1)) { + volatile int result; + + if (setjmp(env) == 0) { + REQUIRE_LIBC(signal(SIGABRT, &handle_signal), SIG_ERR); + REQUIRE_LIBC(signal(SIGSEGV, &handle_signal), SIG_ERR); + result = (*ctypefn)(ch); + REQUIRE_LIBC(signal(SIGABRT, SIG_DFL), SIG_ERR); + REQUIRE_LIBC(signal(SIGSEGV, SIG_DFL), SIG_ERR); + (void)result; + } else { + REQUIRE_LIBC(signal(SIGABRT, SIG_DFL), SIG_ERR); + REQUIRE_LIBC(signal(SIGSEGV, SIG_DFL), SIG_ERR); + atf_tc_fail_nonfatal("%s(%d) raised SIGSEGV", + name, ch); + } + } +} + +static void +test_isalpha_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isalpha", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isupper_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isupper", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_islower_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("islower", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isdigit_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isdigit", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isxdigit_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isxdigit", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isalnum_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isalnum", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isspace_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isspace", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_ispunct_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("ispunct", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isprint_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isprint", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isgraph_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isgraph", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_iscntrl_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("iscntrl", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_isblank_locale(const char *L, int (*ctypefn)(int)) +{ + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("isblank", ctypefn); + ATF_CHECK(!(*ctypefn)(EOF)); +} + +static void +test_toupper_locale(const char *L, int (*ctypefn)(int)) +{ + int result; + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("toupper", ctypefn); + ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF, + "result=%d, expected EOF=%d", result, EOF); +} + +static void +test_tolower_locale(const char *L, int (*ctypefn)(int)) +{ + int result; + + ATF_REQUIRE_MSG(setlocale(LC_CTYPE, L) != NULL, "L=%s", L); + test_use("tolower", ctypefn); + ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF, + "result=%d, expected EOF=%d", result, EOF); +} + +static void +test_isalpha_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case 'a': case 'A': + case 'b': case 'B': + case 'c': case 'C': + case 'd': case 'D': + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + case 'h': case 'H': + case 'i': case 'I': + case 'j': case 'J': + case 'k': case 'K': + case 'l': case 'L': + case 'm': case 'M': + case 'n': case 'N': + case 'o': case 'O': + case 'p': case 'P': + case 'q': case 'Q': + case 'r': case 'R': + case 's': case 'S': + case 't': case 'T': + case 'u': case 'U': + case 'v': case 'V': + case 'w': case 'W': + case 'x': case 'X': + case 'y': case 'Y': + case 'z': case 'Z': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isupper_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_islower_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isdigit_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isxdigit_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'a': case 'A': + case 'b': case 'B': + case 'c': case 'C': + case 'd': case 'D': + case 'e': case 'E': + case 'f': case 'F': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isalnum_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case 'a': case 'A': + case 'b': case 'B': + case 'c': case 'C': + case 'd': case 'D': + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + case 'h': case 'H': + case 'i': case 'I': + case 'j': case 'J': + case 'k': case 'K': + case 'l': case 'L': + case 'm': case 'M': + case 'n': case 'N': + case 'o': case 'O': + case 'p': case 'P': + case 'q': case 'Q': + case 'r': case 'R': + case 's': case 'S': + case 't': case 'T': + case 'u': case 'U': + case 'v': case 'V': + case 'w': case 'W': + case 'x': case 'X': + case 'y': case 'Y': + case 'z': case 'Z': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isspace_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case ' ': + case '\f': + case '\n': + case '\r': + case '\t': + case '\v': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_ispunct_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + default: + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + case 0 ... 0x1f: + case 0x20: /* space is printing but not punctuation */ + case 0x7f: + case 0x80 ... 0xff: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + case 'a': case 'A': + case 'b': case 'B': + case 'c': case 'C': + case 'd': case 'D': + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + case 'h': case 'H': + case 'i': case 'I': + case 'j': case 'J': + case 'k': case 'K': + case 'l': case 'L': + case 'm': case 'M': + case 'n': case 'N': + case 'o': case 'O': + case 'p': case 'P': + case 'q': case 'Q': + case 'r': case 'R': + case 's': case 'S': + case 't': case 'T': + case 'u': case 'U': + case 'v': case 'V': + case 'w': case 'W': + case 'x': case 'X': + case 'y': case 'Y': + case 'z': case 'Z': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isprint_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case 0x20: /* space is printing but not graphic */ + default: + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + case 0 ... 0x1f: + case 0x7f: + case 0x80 ... 0xff: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isgraph_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + default: + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + case 0 ... 0x1f: + case 0x20: /* space is printing but not graphic */ + case 0x7f: + case 0x80 ... 0xff: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_iscntrl_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case 0 ... 0x1f: + case 0x7f: + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_isblank_c(int (*ctypefn)(int)) +{ + int ch; + + ATF_CHECK(!(*ctypefn)(EOF)); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case ' ': + case '\t': + ATF_CHECK_MSG((*ctypefn)(ch), "ch=0x%x", ch); + break; + default: + ATF_CHECK_MSG(!(*ctypefn)(ch), "ch=0x%x", ch); + break; + } + } +} + +static void +test_toupper_c(int (*ctypefn)(int)) +{ + int ch, result, expected; + + ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF, + "result=%d, expected EOF=%d", result, EOF); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case 'a': case 'A': expected = 'A'; break; + case 'b': case 'B': expected = 'B'; break; + case 'c': case 'C': expected = 'C'; break; + case 'd': case 'D': expected = 'D'; break; + case 'e': case 'E': expected = 'E'; break; + case 'f': case 'F': expected = 'F'; break; + case 'g': case 'G': expected = 'G'; break; + case 'h': case 'H': expected = 'H'; break; + case 'i': case 'I': expected = 'I'; break; + case 'j': case 'J': expected = 'J'; break; + case 'k': case 'K': expected = 'K'; break; + case 'l': case 'L': expected = 'L'; break; + case 'm': case 'M': expected = 'M'; break; + case 'n': case 'N': expected = 'N'; break; + case 'o': case 'O': expected = 'O'; break; + case 'p': case 'P': expected = 'P'; break; + case 'q': case 'Q': expected = 'Q'; break; + case 'r': case 'R': expected = 'R'; break; + case 's': case 'S': expected = 'S'; break; + case 't': case 'T': expected = 'T'; break; + case 'u': case 'U': expected = 'U'; break; + case 'v': case 'V': expected = 'V'; break; + case 'w': case 'W': expected = 'W'; break; + case 'x': case 'X': expected = 'X'; break; + case 'y': case 'Y': expected = 'Y'; break; + case 'z': case 'Z': expected = 'Z'; break; + default: + expected = ch; + break; + } + ATF_CHECK_MSG((result = (*ctypefn)(ch)) == expected, + "result=%d expected=%d", result, expected); + } +} + +static void +test_tolower_c(int (*ctypefn)(int)) +{ + int ch, result, expected; + + ATF_CHECK_MSG((result = (*ctypefn)(EOF)) == EOF, + "result=%d, expected EOF=%d", result, EOF); + for (ch = 0; ch <= UCHAR_MAX; ch++) { + switch (ch) { + case 'a': case 'A': expected = 'a'; break; + case 'b': case 'B': expected = 'b'; break; + case 'c': case 'C': expected = 'c'; break; + case 'd': case 'D': expected = 'd'; break; + case 'e': case 'E': expected = 'e'; break; + case 'f': case 'F': expected = 'f'; break; + case 'g': case 'G': expected = 'g'; break; + case 'h': case 'H': expected = 'h'; break; + case 'i': case 'I': expected = 'i'; break; + case 'j': case 'J': expected = 'j'; break; + case 'k': case 'K': expected = 'k'; break; + case 'l': case 'L': expected = 'l'; break; + case 'm': case 'M': expected = 'm'; break; + case 'n': case 'N': expected = 'n'; break; + case 'o': case 'O': expected = 'o'; break; + case 'p': case 'P': expected = 'p'; break; + case 'q': case 'Q': expected = 'q'; break; + case 'r': case 'R': expected = 'r'; break; + case 's': case 'S': expected = 's'; break; + case 't': case 'T': expected = 't'; break; + case 'u': case 'U': expected = 'u'; break; + case 'v': case 'V': expected = 'v'; break; + case 'w': case 'W': expected = 'w'; break; + case 'x': case 'X': expected = 'x'; break; + case 'y': case 'Y': expected = 'y'; break; + case 'z': case 'Z': expected = 'z'; break; + default: + expected = ch; + break; + } + ATF_CHECK_MSG((result = (*ctypefn)(ch)) == expected, + "result=%d expected=%d", result, expected); + } +} + +extern char **environ; + +static void +test_abuse_override(const struct atf_tc *tc, const char *fn, const char *mode, + const char *locale) +{ + char h_ctype_abuse[PATH_MAX]; + pid_t pid; + int status; + + RL(snprintf(h_ctype_abuse, sizeof(h_ctype_abuse), "%s/h_ctype_abuse", + atf_tc_get_config_var(tc, "srcdir"))); + + RL(setenv("LIBC_ALLOWCTYPEABUSE", "", 1)); + + RL(pid = vfork()); + if (pid == 0) { /* child */ + char *const argv[] = { + h_ctype_abuse, + __UNCONST(fn), + __UNCONST(mode), + __UNCONST(locale), + NULL, + }; + + if (execve(argv[0], argv, environ) == -1) + _exit(1); + _exit(2); + } + + RL(waitpid(pid, &status, 0)); + if (WIFSIGNALED(status)) { + atf_tc_fail_nonfatal("child exited on signal %d (%s)", + WTERMSIG(status), strsignal(WTERMSIG(status))); + } else if (!WIFEXITED(status)) { + atf_tc_fail_nonfatal("child exited status=0x%x", status); + } else { + ATF_CHECK_MSG(WEXITSTATUS(status) == 0, + "child exited with code %d", + WEXITSTATUS(status)); + } +} + +static void +test_abuse_override_in_locales(const struct atf_tc *tc, const char *fn, + const char *mode) +{ + size_t i; + + for (i = 0; i < __arraycount(locales); i++) { + fprintf(stderr, "# locale %s\n", locales[i]); + test_abuse_override(tc, fn, mode, locales[i]); + } +} + +#define ADD_TEST_ABUSE(TP, FN) do \ +{ \ + ATF_TP_ADD_TC(TP, abuse_##FN##_macro_c); \ + ATF_TP_ADD_TC(TP, abuse_##FN##_function_c); \ + ATF_TP_ADD_TC(TP, abuse_##FN##_macro_locale); \ + ATF_TP_ADD_TC(TP, abuse_##FN##_function_locale); \ +} while (0) + +#define DEF_TEST_ABUSE(FN) \ +ATF_TC(abuse_##FN##_macro_c); \ +ATF_TC_HEAD(abuse_##FN##_macro_c, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test abusing "#FN" macro with default LC_CTYPE=C"); \ +} \ +ATF_TC_BODY(abuse_##FN##_macro_c, tc) \ +{ \ + if (CHAR_UNSIGNED) { \ + atf_tc_skip("runtime ctype(3) abuse is impossible with" \ + " unsigned char"); \ + } \ + if (!_CTYPE_GUARD_PAGE) \ + atf_tc_skip("no LC_CTYPE=C guard page on this platform"); \ + test_abuse(#FN, &FN##_wrapper); \ +} \ +ATF_TC(abuse_##FN##_function_c); \ +ATF_TC_HEAD(abuse_##FN##_function_c, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test abusing "#FN" function with default LC_CTYPE=C"); \ +} \ +ATF_TC_BODY(abuse_##FN##_function_c, tc) \ +{ \ + if (CHAR_UNSIGNED) { \ + atf_tc_skip("runtime ctype(3) abuse is impossible with" \ + " unsigned char"); \ + } \ + if (!_CTYPE_GUARD_PAGE) \ + atf_tc_skip("no LC_CTYPE=C guard page on this platform"); \ + test_abuse(#FN, &FN); \ +} \ +ATF_TC(abuse_##FN##_macro_locale); \ +ATF_TC_HEAD(abuse_##FN##_macro_locale, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test abusing "#FN" macro with locales"); \ +} \ +ATF_TC_BODY(abuse_##FN##_macro_locale, tc) \ +{ \ + if (CHAR_UNSIGNED) { \ + atf_tc_skip("runtime ctype(3) abuse is impossible with" \ + " unsigned char"); \ + } \ + test_abuse_in_locales(#FN, &FN##_wrapper, /*macro*/true); \ +} \ +ATF_TC(abuse_##FN##_function_locale); \ +ATF_TC_HEAD(abuse_##FN##_function_locale, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test abusing "#FN" function with locales"); \ +} \ +ATF_TC_BODY(abuse_##FN##_function_locale, tc) \ +{ \ + if (CHAR_UNSIGNED) { \ + atf_tc_skip("runtime ctype(3) abuse is impossible with" \ + " unsigned char"); \ + } \ + test_abuse_in_locales(#FN, &FN, /*macro*/false); \ +} + +#define ADD_TEST_ABUSE_OVERRIDE(TP, FN) do \ +{ \ + ATF_TP_ADD_TC(TP, abuse_override_##FN##_macro_c); \ + ATF_TP_ADD_TC(TP, abuse_override_##FN##_function_c); \ + ATF_TP_ADD_TC(TP, abuse_override_##FN##_macro_locale); \ + ATF_TP_ADD_TC(TP, abuse_override_##FN##_function_locale); \ +} while (0) + +#define DEF_TEST_ABUSE_OVERRIDE(FN) \ +ATF_TC(abuse_override_##FN##_macro_c); \ +ATF_TC_HEAD(abuse_override_##FN##_macro_c, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test allowing abuse of "#FN" macro with default LC_CTYPE=C"); \ +} \ +ATF_TC_BODY(abuse_override_##FN##_macro_c, tc) \ +{ \ + test_abuse_override(tc, #FN, "macro", NULL); \ +} \ +ATF_TC(abuse_override_##FN##_function_c); \ +ATF_TC_HEAD(abuse_override_##FN##_function_c, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test allowing abuse "#FN" function with default LC_CTYPE=C"); \ +} \ +ATF_TC_BODY(abuse_override_##FN##_function_c, tc) \ +{ \ + test_abuse_override(tc, #FN, "function", NULL); \ +} \ +ATF_TC(abuse_override_##FN##_macro_locale); \ +ATF_TC_HEAD(abuse_override_##FN##_macro_locale, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test allowing abuse of "#FN" macro with locales"); \ +} \ +ATF_TC_BODY(abuse_override_##FN##_macro_locale, tc) \ +{ \ + test_abuse_override_in_locales(tc, #FN, "macro"); \ +} \ +ATF_TC(abuse_override_##FN##_function_locale); \ +ATF_TC_HEAD(abuse_override_##FN##_function_locale, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test allowing abuse of "#FN" function with locales"); \ +} \ +ATF_TC_BODY(abuse_override_##FN##_function_locale, tc) \ +{ \ + test_abuse_override_in_locales(tc, #FN, "function"); \ +} + +#define ADD_TEST_USE(TP, FN) do \ +{ \ + ATF_TP_ADD_TC(TP, FN##_macro_c); \ + ATF_TP_ADD_TC(TP, FN##_function_c); \ + ATF_TP_ADD_TC(TP, FN##_macro_locale); \ + ATF_TP_ADD_TC(TP, FN##_function_locale); \ +} while (0) + +#define DEF_TEST_USE(FN) \ +ATF_TC(FN##_macro_c); \ +ATF_TC_HEAD(FN##_macro_c, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test "#FN" macro with default LC_CTYPE=C"); \ +} \ +ATF_TC_BODY(FN##_macro_c, tc) \ +{ \ + test_##FN##_c(&FN##_wrapper); \ +} \ +ATF_TC(FN##_function_c); \ +ATF_TC_HEAD(FN##_function_c, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test "#FN" function with default LC_CTYPE=C"); \ +} \ +ATF_TC_BODY(FN##_function_c, tc) \ +{ \ + test_##FN##_c(&FN); \ +} \ +ATF_TC(FN##_macro_locale); \ +ATF_TC_HEAD(FN##_macro_locale, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test "#FN" macro with locales"); \ +} \ +ATF_TC_BODY(FN##_macro_locale, tc) \ +{ \ + size_t i; \ + \ + for (i = 0; i < __arraycount(locales); i++) \ + test_##FN##_locale(locales[i], &FN##_wrapper); \ +} \ +ATF_TC(FN##_function_locale); \ +ATF_TC_HEAD(FN##_function_locale, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", \ + "Test "#FN" function with locales"); \ +} \ +ATF_TC_BODY(FN##_function_locale, tc) \ +{ \ + size_t i; \ + \ + for (i = 0; i < __arraycount(locales); i++) \ + test_##FN##_locale(locales[i], &FN); \ +} + +DEF_TEST_ABUSE(isalpha) +DEF_TEST_ABUSE(isupper) +DEF_TEST_ABUSE(islower) +DEF_TEST_ABUSE(isdigit) +DEF_TEST_ABUSE(isxdigit) +DEF_TEST_ABUSE(isalnum) +DEF_TEST_ABUSE(isspace) +DEF_TEST_ABUSE(ispunct) +DEF_TEST_ABUSE(isprint) +DEF_TEST_ABUSE(isgraph) +DEF_TEST_ABUSE(iscntrl) +DEF_TEST_ABUSE(isblank) +DEF_TEST_ABUSE(toupper) +DEF_TEST_ABUSE(tolower) + +DEF_TEST_ABUSE_OVERRIDE(isalpha) +DEF_TEST_ABUSE_OVERRIDE(isupper) +DEF_TEST_ABUSE_OVERRIDE(islower) +DEF_TEST_ABUSE_OVERRIDE(isdigit) +DEF_TEST_ABUSE_OVERRIDE(isxdigit) +DEF_TEST_ABUSE_OVERRIDE(isalnum) +DEF_TEST_ABUSE_OVERRIDE(isspace) +DEF_TEST_ABUSE_OVERRIDE(ispunct) +DEF_TEST_ABUSE_OVERRIDE(isprint) +DEF_TEST_ABUSE_OVERRIDE(isgraph) +DEF_TEST_ABUSE_OVERRIDE(iscntrl) +DEF_TEST_ABUSE_OVERRIDE(isblank) +DEF_TEST_ABUSE_OVERRIDE(toupper) +DEF_TEST_ABUSE_OVERRIDE(tolower) + +DEF_TEST_USE(isalpha) +DEF_TEST_USE(isupper) +DEF_TEST_USE(islower) +DEF_TEST_USE(isdigit) +DEF_TEST_USE(isxdigit) +DEF_TEST_USE(isalnum) +DEF_TEST_USE(isspace) +DEF_TEST_USE(ispunct) +DEF_TEST_USE(isprint) +DEF_TEST_USE(isgraph) +DEF_TEST_USE(iscntrl) +DEF_TEST_USE(isblank) +DEF_TEST_USE(toupper) +DEF_TEST_USE(tolower) + +ATF_TC(eof_confusion_iso8859_1); +ATF_TC_HEAD(eof_confusion_iso8859_1, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test potential confusion with EOF in ISO-8859-1"); +} +ATF_TC_BODY(eof_confusion_iso8859_1, tc) +{ + int ydots = 0xff; /* ÿ, LATIN SMALL LETTER Y WITH DIAERESIS */ + int ch; + + /* + * The LATIN SMALL LETTER Y WITH DIAERESIS code point 0xff in + * ISO-8859-1 is curious primarily because its bit pattern + * coincides with an 8-bit signed -1, which is to say, EOF as + * an 8-bit quantity; of course, for EOF, all of the is* + * functions are supposed to return false (as we test above). + * It also has the curious property that it lacks any + * corresponding uppercase code point in ISO-8859-1, so we + * can't distinguish it from EOF by tolower/toupper. + */ + ATF_REQUIRE(setlocale(LC_CTYPE, "fr_FR.ISO8859-1") != NULL); + ATF_CHECK(isalpha(ydots)); + ATF_CHECK(!isupper(ydots)); + ATF_CHECK(islower(ydots)); + ATF_CHECK(!isdigit(ydots)); + ATF_CHECK(!isxdigit(ydots)); + ATF_CHECK(isalnum(ydots)); + ATF_CHECK(!isspace(ydots)); + ATF_CHECK(!ispunct(ydots)); + ATF_CHECK(isprint(ydots)); + ATF_CHECK(isgraph(ydots)); + ATF_CHECK(!iscntrl(ydots)); + ATF_CHECK(!isblank(ydots)); + ATF_CHECK_MSG((ch = toupper(ydots)) == ydots, "ch=0x%x", ch); + ATF_CHECK_MSG((ch = tolower(ydots)) == ydots, "ch=0x%x", ch); +} + +ATF_TC(eof_confusion_koi8_u); +ATF_TC_HEAD(eof_confusion_koi8_u, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test potential confusion with EOF in KOI8-U"); +} +ATF_TC_BODY(eof_confusion_koi8_u, tc) +{ + int Hard = 0xff; /* Ъ, CYRILLIC CAPITAL LETTER HARD SIGN */ + int hard = 0xdf; /* ъ, CYRILLIC SMALL LETTER HARD SIGN */ + int ch; + + /* + * The CYRILLIC CAPITAL LETTER HARD SIGN code point 0xff in + * KOI8-U (and KOI8-R) also coincides with the bit pattern of + * an 8-bit signed -1. Unlike LATIN SMALL LETTER Y WITH + * DIAERESIS, it has a lowercase equivalent in KOI8-U. + */ + ATF_REQUIRE(setlocale(LC_CTYPE, "uk_UA.KOI8-U") != NULL); + ATF_CHECK(isalpha(Hard)); + ATF_CHECK(isupper(Hard)); + ATF_CHECK(!islower(Hard)); + ATF_CHECK(!isdigit(Hard)); + ATF_CHECK(!isxdigit(Hard)); + ATF_CHECK(isalnum(Hard)); + ATF_CHECK(!isspace(Hard)); + ATF_CHECK(!ispunct(Hard)); + ATF_CHECK(isprint(Hard)); + ATF_CHECK(isgraph(Hard)); + ATF_CHECK(!iscntrl(Hard)); + ATF_CHECK(!isblank(Hard)); + ATF_CHECK_MSG((ch = toupper(Hard)) == Hard, "ch=0x%x", ch); + ATF_CHECK_MSG((ch = tolower(Hard)) == hard, "ch=0x%x", ch); +} + +ATF_TC(eof_confusion_pt154); +ATF_TC_HEAD(eof_confusion_pt154, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test potential confusion with EOF in PT154"); +} +ATF_TC_BODY(eof_confusion_pt154, tc) +{ + int ya = 0xff; /* я, CYRILLIC SMALL LETTER YA */ + int Ya = 0xdf; /* Я, CYRILLIC CAPITAL LETTER YA */ + int ch; + + /* + * The CYRILLIC SMALL LETTER YA code point 0xff in PT154 also + * coincides with the bit pattern of an 8-bit signed -1, and is + * lowercase with a corresponding uppercase code point in + * PT154. + */ + ATF_REQUIRE(setlocale(LC_CTYPE, "kk_KZ.PT154") != NULL); + ATF_CHECK(isalpha(ya)); + ATF_CHECK(!isupper(ya)); + ATF_CHECK(islower(ya)); + ATF_CHECK(!isdigit(ya)); + ATF_CHECK(!isxdigit(ya)); + ATF_CHECK(isalnum(ya)); + ATF_CHECK(!isspace(ya)); + ATF_CHECK(!ispunct(ya)); + ATF_CHECK(isprint(ya)); + ATF_CHECK(isgraph(ya)); + ATF_CHECK(!iscntrl(ya)); + ATF_CHECK(!isblank(ya)); + ATF_CHECK_MSG((ch = toupper(ya)) == Ya, "ch=0x%x", ch); + ATF_CHECK_MSG((ch = tolower(ya)) == ya, "ch=0x%x", ch); +} + +ATF_TP_ADD_TCS(tp) +{ + + ADD_TEST_ABUSE(tp, isalpha); + ADD_TEST_ABUSE(tp, isupper); + ADD_TEST_ABUSE(tp, islower); + ADD_TEST_ABUSE(tp, isdigit); + ADD_TEST_ABUSE(tp, isxdigit); + ADD_TEST_ABUSE(tp, isalnum); + ADD_TEST_ABUSE(tp, isspace); + ADD_TEST_ABUSE(tp, ispunct); + ADD_TEST_ABUSE(tp, isprint); + ADD_TEST_ABUSE(tp, isgraph); + ADD_TEST_ABUSE(tp, iscntrl); + ADD_TEST_ABUSE(tp, isblank); + ADD_TEST_ABUSE(tp, toupper); + ADD_TEST_ABUSE(tp, tolower); + + ADD_TEST_ABUSE_OVERRIDE(tp, isalpha); + ADD_TEST_ABUSE_OVERRIDE(tp, isupper); + ADD_TEST_ABUSE_OVERRIDE(tp, islower); + ADD_TEST_ABUSE_OVERRIDE(tp, isdigit); + ADD_TEST_ABUSE_OVERRIDE(tp, isxdigit); + ADD_TEST_ABUSE_OVERRIDE(tp, isalnum); + ADD_TEST_ABUSE_OVERRIDE(tp, isspace); + ADD_TEST_ABUSE_OVERRIDE(tp, ispunct); + ADD_TEST_ABUSE_OVERRIDE(tp, isprint); + ADD_TEST_ABUSE_OVERRIDE(tp, isgraph); + ADD_TEST_ABUSE_OVERRIDE(tp, iscntrl); + ADD_TEST_ABUSE_OVERRIDE(tp, isblank); + ADD_TEST_ABUSE_OVERRIDE(tp, toupper); + ADD_TEST_ABUSE_OVERRIDE(tp, tolower); + + ADD_TEST_USE(tp, isalpha); + ADD_TEST_USE(tp, isupper); + ADD_TEST_USE(tp, islower); + ADD_TEST_USE(tp, isdigit); + ADD_TEST_USE(tp, isxdigit); + ADD_TEST_USE(tp, isalnum); + ADD_TEST_USE(tp, isspace); + ADD_TEST_USE(tp, ispunct); + ADD_TEST_USE(tp, isprint); + ADD_TEST_USE(tp, isgraph); + ADD_TEST_USE(tp, iscntrl); + ADD_TEST_USE(tp, isblank); + ADD_TEST_USE(tp, toupper); + ADD_TEST_USE(tp, tolower); + + ATF_TP_ADD_TC(tp, eof_confusion_iso8859_1); + ATF_TP_ADD_TC(tp, eof_confusion_koi8_u); + ATF_TP_ADD_TC(tp, eof_confusion_pt154); + + return atf_no_error(); +} diff --git a/lib/libc/gen/t_timespec_get.c b/lib/libc/gen/t_timespec_get.c new file mode 100644 index 000000000000..b51625311032 --- /dev/null +++ b/lib/libc/gen/t_timespec_get.c @@ -0,0 +1,123 @@ +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nia Alarie. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <atf-c.h> + +#include <limits.h> +#include <time.h> + +ATF_TC(timespec_getres); +ATF_TC_HEAD(timespec_getres, tc) +{ + atf_tc_set_md_var(tc, "descr", "Resolution tests for timespec_getres"); +} + +ATF_TC_BODY(timespec_getres, tc) +{ + struct timespec ts, ts2; + + ATF_REQUIRE_EQ(timespec_getres(&ts, TIME_MONOTONIC), TIME_MONOTONIC); + ATF_REQUIRE_EQ(clock_getres(CLOCK_MONOTONIC, &ts2), 0); + + ATF_REQUIRE_EQ(ts.tv_sec, ts2.tv_sec); + ATF_REQUIRE_EQ(ts.tv_nsec, ts2.tv_nsec); + + ATF_REQUIRE_EQ(timespec_getres(&ts, TIME_UTC), TIME_UTC); + ATF_REQUIRE_EQ(clock_getres(CLOCK_REALTIME, &ts2), 0); + + ATF_REQUIRE_EQ(ts.tv_sec, ts2.tv_sec); + ATF_REQUIRE_EQ(ts.tv_nsec, ts2.tv_nsec); + + /* now an invalid value */ + ATF_REQUIRE_EQ(timespec_getres(&ts, INT_MAX), 0); +} + +ATF_TC(timespec_get); +ATF_TC_HEAD(timespec_get, tc) +{ + atf_tc_set_md_var(tc, "descr", "Basic tests for timespec_get"); +} + +ATF_TC_BODY(timespec_get, tc) +{ + struct timespec ts, ts2; + + ATF_REQUIRE_EQ(timespec_get(&ts, TIME_UTC), TIME_UTC); + ATF_REQUIRE_EQ(clock_gettime(CLOCK_REALTIME, &ts2), 0); + + /* + * basically test that these clocks (which should be the same source) + * aren't too wildly apart... + */ + + if (ts2.tv_sec >= ts.tv_sec) { + ATF_REQUIRE((ts2.tv_sec - ts.tv_sec) < 86400); + } else { + ATF_REQUIRE((ts.tv_sec - ts2.tv_sec) < 86400); + } + + /* now an invalid value */ + ATF_REQUIRE_EQ(timespec_get(&ts, INT_MAX), 0); +} + +ATF_TC(timespec_get_monotonic); +ATF_TC_HEAD(timespec_get_monotonic, tc) +{ + atf_tc_set_md_var(tc, "descr", "Monotonic tests for timespec_getres"); +} + +ATF_TC_BODY(timespec_get_monotonic, tc) +{ + struct timespec ts, ts2; + + ATF_REQUIRE_EQ(timespec_get(&ts, TIME_MONOTONIC), TIME_MONOTONIC); + ATF_REQUIRE_EQ(clock_gettime(CLOCK_MONOTONIC, &ts2), 0); + + /* + * basically test that these clocks (which should be the same source) + * aren't too wildly apart... + */ + + ATF_REQUIRE(ts2.tv_sec >= ts.tv_sec); + ATF_REQUIRE((ts2.tv_sec - ts.tv_sec) < 86400); + + /* test that it's actually monotonic */ + ATF_REQUIRE_EQ(timespec_get(&ts2, TIME_MONOTONIC), TIME_MONOTONIC); + ATF_REQUIRE(ts2.tv_sec >= ts.tv_sec); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, timespec_getres); + ATF_TP_ADD_TC(tp, timespec_get); + ATF_TP_ADD_TC(tp, timespec_get_monotonic); + + return atf_no_error(); +} + diff --git a/lib/libc/locale/t_c16rtomb.c b/lib/libc/locale/t_c16rtomb.c new file mode 100644 index 000000000000..3d695db8dc97 --- /dev/null +++ b/lib/libc/locale/t_c16rtomb.c @@ -0,0 +1,287 @@ +/* $NetBSD: t_c16rtomb.c,v 1.6 2024/08/19 16:22:10 riastradh Exp $ */ + +/*- + * Copyright (c) 2002 Tim J. Robbins + * All rights reserved. + * + * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Test program for c16rtomb() as specified by ISO/IEC 9899:2011. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_c16rtomb.c,v 1.6 2024/08/19 16:22:10 riastradh Exp $"); + +#include <errno.h> +#include <limits.h> +#include <locale.h> +#include <stdio.h> +#include <string.h> +#include <uchar.h> + +#include <atf-c.h> + +static void +require_lc_ctype(const char *locale_name) +{ + char *lc_ctype_set; + + lc_ctype_set = setlocale(LC_CTYPE, locale_name); + if (lc_ctype_set == NULL) + atf_tc_fail("setlocale(LC_CTYPE, \"%s\") failed; errno=%d", + locale_name, errno); + + ATF_REQUIRE_EQ_MSG(strcmp(lc_ctype_set, locale_name), 0, + "lc_ctype_set=%s locale_name=%s", lc_ctype_set, locale_name); +} + +static mbstate_t s; +static char buf[7*MB_LEN_MAX + 1]; + +ATF_TC_WITHOUT_HEAD(c16rtomb_c_locale_test); +ATF_TC_BODY(c16rtomb_c_locale_test, tc) +{ + size_t n; + + require_lc_ctype("C"); + + /* + * If the buffer argument is NULL, c16 is implicitly 0, + * c16rtomb() resets its internal state. + */ + ATF_CHECK_EQ_MSG((n = c16rtomb(NULL, L'\0', NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c16rtomb(NULL, 0xdc00, NULL)), 1, "n=%zu", n); + + /* Null wide character. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0, &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == 0 && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); + + /* Latin letter A, internal state. */ + ATF_CHECK_EQ_MSG((n = c16rtomb(NULL, L'\0', NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c16rtomb(NULL, L'A', NULL)), 1, "n=%zu", n); + + /* Latin letter A. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, L'A', &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == 'A' && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); + + /* Unicode character 'Pile of poo'. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0xd83d, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0xdca9, &s)), (size_t)-1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(errno, EILSEQ, "errno=%d", errno); + ATF_CHECK_EQ_MSG((unsigned char)buf[0], 0xcc, "buf=[%02x]", buf[0]); + + /* Incomplete Unicode character 'Pile of poo', interrupted by NUL. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0xd83d, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, L'\0', &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == '\0' && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); +} + +ATF_TC_WITHOUT_HEAD(c16rtomb_iso2022jp_locale_test); +ATF_TC_BODY(c16rtomb_iso2022jp_locale_test, tc) +{ + char *p; + size_t n; + + require_lc_ctype("ja_JP.ISO-2022-JP"); + + /* + * If the buffer argument is NULL, c16 is implicitly 0, + * c16rtomb() resets its internal state. + */ + ATF_CHECK_EQ_MSG((n = c16rtomb(NULL, L'\0', NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c16rtomb(NULL, 0xdc00, NULL)), 1, "n=%zu", n); + + /* Null wide character. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0, &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == 0 && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); + + /* Latin letter A, internal state. */ + ATF_CHECK_EQ_MSG((n = c16rtomb(NULL, L'\0', NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c16rtomb(NULL, L'A', NULL)), 1, "n=%zu", n); + + /* + * 1. U+0042 LATIN CAPITAL LETTER A + * 2. U+00A5 YEN SIGN + * 3. U+00A5 YEN SIGN (again, no shift needed) + * 4. U+30A2 KATAKANA LETTER A + * 5. U+30A2 KATAKANA LETTER A (again, no shift needed) + * 6. incomplete UTF-16 surrogate pair -- no output + * 7. U+0000 NUL (plus shift sequence to initial state) + */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + p = buf; + ATF_CHECK_EQ_MSG((n = c16rtomb(p, L'A', &s)), 1, "n=%zu", n); /* 1 */ + p += 1; + ATF_CHECK_EQ_MSG((n = c16rtomb(p, 0xa5, &s)), 4, "n=%zu", n); /* 2 */ + p += 4; + ATF_CHECK_EQ_MSG((n = c16rtomb(p, 0xa5, &s)), 1, "n=%zu", n); /* 3 */ + p += 1; + ATF_CHECK_EQ_MSG((n = c16rtomb(p, 0x30a2, &s)), 5, "n=%zu", n); /* 4 */ + p += 5; + ATF_CHECK_EQ_MSG((n = c16rtomb(p, 0x30a2, &s)), 2, "n=%zu", n); /* 5 */ + p += 2; + ATF_CHECK_EQ_MSG((n = c16rtomb(p, 0xd800, &s)), 0, "n=%zu", n); /* 6 */ + ATF_CHECK_EQ_MSG((n = c16rtomb(p, L'\0', &s)), 4, "n=%zu", n); /* 7 */ + p += 4; + ATF_CHECK_MSG(((unsigned char)buf[0] == 'A' && + (unsigned char)buf[1] == 0x1b && /* shift ISO/IEC 646:JP */ + (unsigned char)buf[2] == '(' && + (unsigned char)buf[3] == 'J' && + (unsigned char)buf[4] == 0x5c && /* YEN SIGN */ + (unsigned char)buf[5] == 0x5c && /* YEN SIGN */ + (unsigned char)buf[6] == 0x1b && /* shift JIS X 0208 */ + (unsigned char)buf[7] == '$' && + (unsigned char)buf[8] == 'B' && + (unsigned char)buf[9] == 0x25 && /* KATAKANA LETTER A */ + (unsigned char)buf[10] == 0x22 && + (unsigned char)buf[11] == 0x25 && /* KATAKANA LETTER A */ + (unsigned char)buf[12] == 0x22 && + (unsigned char)buf[13] == 0x1b && /* shift US-ASCII */ + (unsigned char)buf[14] == '(' && + (unsigned char)buf[15] == 'B' && + (unsigned char)buf[16] == '\0' && + (unsigned char)buf[17] == 0xcc), + "buf=[%02x %02x %02x %02x %02x %02x %02x %02x " + " %02x %02x %02x %02x %02x %02x %02x %02x " + " %02x %02x]", + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7], + buf[8], buf[9], buf[10], buf[11], + buf[12], buf[13], buf[14], buf[15], + buf[16], buf[17]); +} + +ATF_TC_WITHOUT_HEAD(c16rtomb_iso_8859_1_test); +ATF_TC_BODY(c16rtomb_iso_8859_1_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.ISO8859-1"); + + /* Unicode character 'Euro sign'. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0x20ac, &s)), (size_t)-1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(errno, EILSEQ, "errno=%d", errno); + ATF_CHECK_EQ_MSG((unsigned char)buf[0], 0xcc, "buf=[%02x]", buf[0]); +} + +ATF_TC_WITHOUT_HEAD(c16rtomb_iso_8859_15_test); +ATF_TC_BODY(c16rtomb_iso_8859_15_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.ISO8859-15"); + + /* Unicode character 'Euro sign'. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0x20ac, &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == 0xa4 && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); +} + +ATF_TC_WITHOUT_HEAD(c16rtomb_utf_8_test); +ATF_TC_BODY(c16rtomb_utf_8_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.UTF-8"); + + /* Unicode character 'Pile of poo'. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0xd83d, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0xdca9, &s)), 4, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == 0xf0 && + (unsigned char)buf[1] == 0x9f && + (unsigned char)buf[2] == 0x92 && + (unsigned char)buf[3] == 0xa9 && + (unsigned char)buf[4] == 0xcc), + "buf=[%02x %02x %02x %02x %02x]", + buf[0], buf[1], buf[2], buf[3], buf[4]); + + /* Invalid code; 'Pile of poo' without the trail surrogate. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0xd83d, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, L'A', &s)), (size_t)-1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(errno, EILSEQ, "errno=%d", errno); + ATF_CHECK_EQ_MSG((unsigned char)buf[0], 0xcc, "buf=[%02x]", buf[0]); + + /* Invalid code; 'Pile of poo' without the lead surrogate. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0xdca9, &s)), (size_t)-1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(errno, EILSEQ, "errno=%d", errno); + ATF_CHECK_EQ_MSG((unsigned char)buf[0], 0xcc, "buf=[%02x]", buf[0]); + + /* Incomplete Unicode character 'Pile of poo', interrupted by NUL. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, 0xd83d, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c16rtomb(buf, L'\0', &s)), 1, + "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == '\0' && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, c16rtomb_c_locale_test); + ATF_TP_ADD_TC(tp, c16rtomb_iso2022jp_locale_test); + ATF_TP_ADD_TC(tp, c16rtomb_iso_8859_1_test); + ATF_TP_ADD_TC(tp, c16rtomb_iso_8859_15_test); + ATF_TP_ADD_TC(tp, c16rtomb_utf_8_test); + + return (atf_no_error()); +} diff --git a/lib/libc/locale/t_c32rtomb.c b/lib/libc/locale/t_c32rtomb.c new file mode 100644 index 000000000000..7233e14f7967 --- /dev/null +++ b/lib/libc/locale/t_c32rtomb.c @@ -0,0 +1,60 @@ +/* $NetBSD: t_c32rtomb.c,v 1.1 2024/08/15 14:16:34 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_c32rtomb.c,v 1.1 2024/08/15 14:16:34 riastradh Exp $"); + +#include <atf-c.h> +#include <locale.h> +#include <uchar.h> + +#include "h_macros.h" + +ATF_TC(c32rtomb_null); +ATF_TC_HEAD(c32rtomb_null, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test null string output to c32rtomb"); +} +ATF_TC_BODY(c32rtomb_null, tc) +{ + char *locale; + mbstate_t ps = {0}; + size_t n; + + REQUIRE_LIBC((locale = setlocale(LC_ALL, "C")), NULL); + ATF_REQUIRE_EQ_MSG(strcmp(locale, "C"), 0, "locale=%s", locale); + + ATF_CHECK_EQ_MSG((n = c32rtomb(NULL, L'x', &ps)), 1, "n=%zu", n); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, c32rtomb_null); + return atf_no_error(); +} diff --git a/lib/libc/locale/t_c8rtomb.c b/lib/libc/locale/t_c8rtomb.c new file mode 100644 index 000000000000..ce03e6ed1d20 --- /dev/null +++ b/lib/libc/locale/t_c8rtomb.c @@ -0,0 +1,355 @@ +/* $NetBSD: t_c8rtomb.c,v 1.7 2024/08/19 16:22:10 riastradh Exp $ */ + +/*- + * Copyright (c) 2002 Tim J. Robbins + * All rights reserved. + * + * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Test program for c8rtomb() as specified by C23. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_c8rtomb.c,v 1.7 2024/08/19 16:22:10 riastradh Exp $"); + +#include <errno.h> +#include <limits.h> +#include <locale.h> +#include <stdio.h> +#include <string.h> +#include <uchar.h> + +#include <atf-c.h> + +static void +require_lc_ctype(const char *locale_name) +{ + char *lc_ctype_set; + + lc_ctype_set = setlocale(LC_CTYPE, locale_name); + if (lc_ctype_set == NULL) + atf_tc_fail("setlocale(LC_CTYPE, \"%s\") failed; errno=%d", + locale_name, errno); + + ATF_REQUIRE_EQ_MSG(strcmp(lc_ctype_set, locale_name), 0, + "lc_ctype_set=%s locale_name=%s", lc_ctype_set, locale_name); +} + +static mbstate_t s; +static char buf[7*MB_LEN_MAX + 1]; + +ATF_TC_WITHOUT_HEAD(c8rtomb_c_locale_test); +ATF_TC_BODY(c8rtomb_c_locale_test, tc) +{ + size_t n; + + require_lc_ctype("C"); + + /* + * If the buffer argument is NULL, c8 is implicitly 0, + * c8rtomb() resets its internal state. + */ + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, '\0', NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0x80, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xc0, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xe0, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xf0, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xf8, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xfc, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xfe, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xff, NULL)), 1, "n=%zu", n); + + /* Null wide character. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0, &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == 0 && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); + + /* Latin letter A, internal state. */ + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, '\0', NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 'A', NULL)), 1, "n=%zu", n); + + /* Latin letter A. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 'A', &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == 'A' && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); + + /* Unicode character 'Pile of poo'. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xf0, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x9f, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x92, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xa9, &s)), (size_t)-1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(errno, EILSEQ, "errno=%d", errno); + ATF_CHECK_EQ_MSG((unsigned char)buf[0], 0xcc, "buf=[%02x]", buf[0]); + + /* Incomplete Unicode character 'Pile of poo', interrupted by NUL. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xf0, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, '\0', &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == '\0' && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); + + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xf0, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x9f, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, '\0', &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == '\0' && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); + + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xf0, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x9f, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x92, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, '\0', &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == '\0' && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); +} + +ATF_TC_WITHOUT_HEAD(c8rtomb_iso2022jp_locale_test); +ATF_TC_BODY(c8rtomb_iso2022jp_locale_test, tc) +{ + char *p; + size_t n; + + require_lc_ctype("ja_JP.ISO-2022-JP"); + + /* + * If the buffer argument is NULL, c8 is implicitly 0, + * c8rtomb() resets its internal state. + */ + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, '\0', NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0x80, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xc0, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xe0, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xf0, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xf8, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xfc, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xfe, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 0xff, NULL)), 1, "n=%zu", n); + + /* Null wide character. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0, &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == 0 && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); + + /* Latin letter A, internal state. */ + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, '\0', NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(NULL, 'A', NULL)), 1, "n=%zu", n); + + /* + * 1. U+0042 LATIN CAPITAL LETTER A + * 2. U+00A5 YEN SIGN + * 3. U+00A5 YEN SIGN (again, no shift needed) + * 4. U+30A2 KATAKANA LETTER A + * 5. U+30A2 KATAKANA LETTER A (again, no shift needed) + * 6. incomplete UTF-8 multibyte sequence -- no output + * 7. U+0000 NUL (plus shift sequence to initial state) + */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + p = buf; + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 'A', &s)), 1, "n=%zu", n); /* 1 */ + p += 1; + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0xc2, &s)), 0, "n=%zu", n); /* 2 */ + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0xa5, &s)), 4, "n=%zu", n); + p += 4; + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0xc2, &s)), 0, "n=%zu", n); /* 3 */ + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0xa5, &s)), 1, "n=%zu", n); + p += 1; + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0xe3, &s)), 0, "n=%zu", n); /* 4 */ + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0x82, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0xa2, &s)), 5, "n=%zu", n); + p += 5; + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0xe3, &s)), 0, "n=%zu", n); /* 5 */ + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0x82, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0xa2, &s)), 2, "n=%zu", n); + p += 2; + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0xe3, &s)), 0, "n=%zu", n); /* 6 */ + ATF_CHECK_EQ_MSG((n = c8rtomb(p, 0x82, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(p, '\0', &s)), 4, "n=%zu", n); /* 7 */ + p += 4; + ATF_CHECK_MSG(((unsigned char)buf[0] == 'A' && + (unsigned char)buf[1] == 0x1b && /* shift ISO/IEC 646:JP */ + (unsigned char)buf[2] == '(' && + (unsigned char)buf[3] == 'J' && + (unsigned char)buf[4] == 0x5c && /* YEN SIGN */ + (unsigned char)buf[5] == 0x5c && /* YEN SIGN */ + (unsigned char)buf[6] == 0x1b && /* shift JIS X 0208 */ + (unsigned char)buf[7] == '$' && + (unsigned char)buf[8] == 'B' && + (unsigned char)buf[9] == 0x25 && /* KATAKANA LETTER A */ + (unsigned char)buf[10] == 0x22 && + (unsigned char)buf[11] == 0x25 && /* KATAKANA LETTER A */ + (unsigned char)buf[12] == 0x22 && + (unsigned char)buf[13] == 0x1b && /* shift US-ASCII */ + (unsigned char)buf[14] == '(' && + (unsigned char)buf[15] == 'B' && + (unsigned char)buf[16] == '\0' && + (unsigned char)buf[17] == 0xcc), + "buf=[%02x %02x %02x %02x %02x %02x %02x %02x " + " %02x %02x %02x %02x %02x %02x %02x %02x " + " %02x %02x]", + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7], + buf[8], buf[9], buf[10], buf[11], + buf[12], buf[13], buf[14], buf[15], + buf[16], buf[17]); +} + +ATF_TC_WITHOUT_HEAD(c8rtomb_iso_8859_1_test); +ATF_TC_BODY(c8rtomb_iso_8859_1_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.ISO8859-1"); + + /* Unicode character 'Euro sign'. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xe2, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x82, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xac, &s)), (size_t)-1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(errno, EILSEQ, "errno=%d", errno); + ATF_CHECK_EQ_MSG((unsigned char)buf[0], 0xcc, "buf=[%02x]", buf[0]); +} + +ATF_TC_WITHOUT_HEAD(c8rtomb_iso_8859_15_test); +ATF_TC_BODY(c8rtomb_iso_8859_15_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.ISO8859-15"); + + /* Unicode character 'Euro sign'. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xe2, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x82, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xac, &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == 0xa4 && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); +} + +ATF_TC_WITHOUT_HEAD(c8rtomb_utf_8_test); +ATF_TC_BODY(c8rtomb_utf_8_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.UTF-8"); + + /* Unicode character 'Pile of poo'. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xf0, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x9f, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x92, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xa9, &s)), 4, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == 0xf0 && + (unsigned char)buf[1] == 0x9f && + (unsigned char)buf[2] == 0x92 && + (unsigned char)buf[3] == 0xa9 && + (unsigned char)buf[4] == 0xcc), + "buf=[%02x %02x %02x %02x %02x]", + buf[0], buf[1], buf[2], buf[3], buf[4]); + + /* Invalid code; 'Pile of poo' without the last byte. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xf0, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x9f, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x92, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 'A', &s)), (size_t)-1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(errno, EILSEQ, "errno=%d", errno); + ATF_CHECK_EQ_MSG((unsigned char)buf[0], 0xcc, "buf=[%02x]", buf[0]); + + /* Invalid code; 'Pile of poo' without the first byte. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x9f, &s)), (size_t)-1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(errno, EILSEQ, "errno=%d", errno); + ATF_CHECK_EQ_MSG((unsigned char)buf[0], 0xcc, "buf=[%02x]", buf[0]); + + /* Incomplete Unicode character 'Pile of poo', interrupted by NUL. */ + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xf0, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, '\0', &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == '\0' && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); + + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xf0, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x9f, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, '\0', &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == '\0' && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); + + memset(&s, 0, sizeof(s)); + memset(buf, 0xcc, sizeof(buf)); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0xf0, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x9f, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, 0x92, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = c8rtomb(buf, '\0', &s)), 1, "n=%zu", n); + ATF_CHECK_MSG(((unsigned char)buf[0] == '\0' && + (unsigned char)buf[1] == 0xcc), + "buf=[%02x %02x]", buf[0], buf[1]); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, c8rtomb_c_locale_test); + ATF_TP_ADD_TC(tp, c8rtomb_iso2022jp_locale_test); + ATF_TP_ADD_TC(tp, c8rtomb_iso_8859_1_test); + ATF_TP_ADD_TC(tp, c8rtomb_iso_8859_15_test); + ATF_TP_ADD_TC(tp, c8rtomb_utf_8_test); + + return (atf_no_error()); +} diff --git a/lib/libc/locale/t_mbrtoc16.c b/lib/libc/locale/t_mbrtoc16.c new file mode 100644 index 000000000000..cac804c84eed --- /dev/null +++ b/lib/libc/locale/t_mbrtoc16.c @@ -0,0 +1,364 @@ +/* $NetBSD: t_mbrtoc16.c,v 1.3 2024/08/20 17:43:09 riastradh Exp $ */ + +/*- + * Copyright (c) 2002 Tim J. Robbins + * All rights reserved. + * + * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Test program for mbrtoc16() as specified by ISO/IEC 9899:2011. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mbrtoc16.c,v 1.3 2024/08/20 17:43:09 riastradh Exp $"); + +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <locale.h> +#include <string.h> +#include <uchar.h> + +#include <atf-c.h> + +static void +require_lc_ctype(const char *locale_name) +{ + char *lc_ctype_set; + + lc_ctype_set = setlocale(LC_CTYPE, locale_name); + if (lc_ctype_set == NULL) + atf_tc_fail("setlocale(LC_CTYPE, \"%s\") failed; errno=%d", + locale_name, errno); + + ATF_REQUIRE_EQ_MSG(strcmp(lc_ctype_set, locale_name), 0, + "lc_ctype_set=%s locale_name=%s", lc_ctype_set, locale_name); +} + +static mbstate_t s; +static char16_t c16; + +ATF_TC_WITHOUT_HEAD(mbrtoc16_c_locale_test); +ATF_TC_BODY(mbrtoc16_c_locale_test, tc) +{ + size_t n; + + require_lc_ctype("C"); + + /* Null wide character, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 1, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%"PRIx16, (uint16_t)c16); + + /* Null wide character. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 1, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%"PRIx16, (uint16_t)c16); + + /* Latin letter A, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc16(NULL, 0, 0, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "A", 1, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'A', "c16=U+%"PRIx16" L'A'=U+%"PRIx16, + (uint16_t)c16, (uint16_t)L'A'); + + /* Latin letter A. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "A", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'A', "c16=U+%"PRIx16" L'A'=U+%"PRIx16, + (uint16_t)c16, (uint16_t)L'A'); + + /* Incomplete character sequence. */ + c16 = L'z'; + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 0, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'z', "c16=U+%"PRIx16" L'z'=U+%"PRIx16, + (uint16_t)c16, (uint16_t)L'z'); + + /* Check that mbrtoc16() doesn't access the buffer when n == 0. */ + c16 = L'z'; + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 0, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'z', "c16=U+%"PRIx16" L'z'=U+%"PRIx16, + (uint16_t)c16, (uint16_t)L'z'); + + /* Check that mbrtoc16() doesn't read ahead too aggressively. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "AB", 2, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'A', "c16=U+%"PRIx16" L'A'=U+%"PRIx16, + (uint16_t)c16, (uint16_t)L'A'); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "C", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'C', "c16=U+%"PRIx16" L'C'=U+%"PRIx16, + (uint16_t)c16, (uint16_t)L'C'); +} + +ATF_TC_WITHOUT_HEAD(mbrtoc16_iso2022jp_locale_test); +ATF_TC_BODY(mbrtoc16_iso2022jp_locale_test, tc) +{ + size_t n; + + require_lc_ctype("ja_JP.ISO-2022-JP"); + + /* Null wide character, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 1, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%04"PRIx16, (uint16_t)c16); + + /* Null wide character. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 1, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%04"PRIx16, (uint16_t)c16); + + /* Latin letter A, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc16(NULL, 0, 0, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "A", 1, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'A', "c16=U+%04"PRIx16" L'A'=U+%04"PRIx16, + (uint16_t)c16, (uint16_t)L'A'); + + /* Latin letter A. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "A", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'A', "c16=U+%04"PRIx16" L'A'=U+%04"PRIx16, + (uint16_t)c16, (uint16_t)L'A'); + + /* Incomplete character sequence. */ + c16 = L'z'; + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 0, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'z', "c16=U+%04"PRIx16" L'z'=U+%04"PRIx16, + (uint16_t)c16, (uint16_t)L'z'); + + /* Check that mbrtoc16() doesn't access the buffer when n == 0. */ + c16 = L'z'; + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 0, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'z', "c16=U+%04"PRIx16" L'z'=U+%04"PRIx16, + (uint16_t)c16, (uint16_t)L'z'); + + /* Check that mbrtoc16() doesn't read ahead too aggressively. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "AB", 2, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'A', "c16=U+%04"PRIx16" L'A'=U+%04"PRIx16, + (uint16_t)c16, (uint16_t)L'A'); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "C", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'C', "c16=U+%04"PRIx16" L'C'=U+%04"PRIx16, + (uint16_t)c16, (uint16_t)L'C'); + + /* Incomplete character sequence (shift sequence only). */ + memset(&s, 0, sizeof(s)); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\x1b(J", 3, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%04"PRIx16, (uint16_t)c16); + + /* Same as above, but complete (U+00A5 YEN SIGN). */ + memset(&s, 0, sizeof(s)); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\x1b(J\x5c", 4, &s)), 4, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0xa5, "c16=U+%04"PRIx16, (uint16_t)c16); + + /* Test restarting behaviour. */ + memset(&s, 0, sizeof(s)); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\x1b(", 2, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%04"PRIx16, (uint16_t)c16); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "J\x5c", 2, &s)), 2, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0xa5, "c16=U+%04"PRIx16, (uint16_t)c16); + + /* + * Test shift sequence state in various increments: + * 1. U+0042 LATIN CAPITAL LETTER A + * 2. (shift ISO/IEC 646:JP) U+00A5 YEN SIGN + * 3. U+00A5 YEN SIGN + * 4. (shift JIS X 0208) U+30A2 KATAKANA LETTER A + * 5. U+30A2 KATAKANA LETTER A + * 6. (shift to initial state) U+0000 NUL + */ + memset(&s, 0, sizeof(s)); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "A\x1b(J", 4, &s)), 1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'A', "c16=U+%04"PRIx16, (uint16_t)c16); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\x1b(J", 3, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%04"PRIx16, (uint16_t)c16); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\x5c\x5c", 2, &s)), 1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0x00a5, "c16=U+%04"PRIx16, (uint16_t)c16); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\x5c\x1b$", 3, &s)), 1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0x00a5, "c16=U+%04"PRIx16, (uint16_t)c16); + c16 = 0x1234; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\x1b", 1, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0x1234, "c16=U+%04"PRIx16, (uint16_t)c16); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "$B\x25\x22", 4, &s)), 4, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0x30a2, "c16=U+%04"PRIx16, (uint16_t)c16); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\x25", 1, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%04"PRIx16, (uint16_t)c16); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\x22\x1b(B\x00", 5, &s)), 1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0x30a2, "c16=U+%04"PRIx16, (uint16_t)c16); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\x1b(", 2, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%04"PRIx16, (uint16_t)c16); + c16 = 42; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "B\x00", 2, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%04"PRIx16, (uint16_t)c16); +} + +ATF_TC_WITHOUT_HEAD(mbrtoc16_iso_8859_1_test); +ATF_TC_BODY(mbrtoc16_iso_8859_1_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.ISO8859-1"); + + /* Currency sign. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\xa4", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0xa4, "c16=U+%"PRIx16, (uint16_t)c16); +} + +ATF_TC_WITHOUT_HEAD(mbrtoc16_iso_8859_15_test); +ATF_TC_BODY(mbrtoc16_iso_8859_15_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.ISO8859-15"); + + /* Euro sign. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\xa4", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0x20ac, "c16=U+%"PRIx16, (uint16_t)c16); +} + +ATF_TC_WITHOUT_HEAD(mbrtoc16_utf_8_test); +ATF_TC_BODY(mbrtoc16_utf_8_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.UTF-8"); + + /* Null wide character, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc16(NULL, 0, 0, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 1, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%"PRIx16, (uint16_t)c16); + + /* Null wide character. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 1, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%"PRIx16, (uint16_t)c16); + + /* Latin letter A, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc16(NULL, 0, 0, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "A", 1, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'A', "c16=U+%"PRIx16" L'A'=U+%"PRIx16, + (uint16_t)c16, (uint16_t)L'A'); + + /* Latin letter A. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "A", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'A', "c16=U+%"PRIx16" L'A'=U+%"PRIx16, + (uint16_t)c16, (uint16_t)L'A'); + + /* Incomplete character sequence (zero length). */ + c16 = L'z'; + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 0, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, L'z', "c16=U+%"PRIx16" L'z'=U+%"PRIx16, + (uint16_t)c16, (uint16_t)L'z'); + + /* Incomplete character sequence (truncated double-byte). */ + memset(&s, 0, sizeof(s)); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\xc3", 1, &s)), (size_t)-2, + "n=%zu", n); + + /* Same as above, but complete. */ + memset(&s, 0, sizeof(s)); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\xc3\x84", 2, &s)), 2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0xc4, "c16=U+%"PRIx16, (uint16_t)c16); + + /* Test restarting behaviour. */ + memset(&s, 0, sizeof(s)); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\xc3", 1, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0, "c16=U+%"PRIx16, (uint16_t)c16); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\xb7", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0xf7, "c16=U+%"PRIx16, (uint16_t)c16); + + /* Surrogate pair. */ + memset(&s, 0, sizeof(s)); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\xf0\x9f\x92\xa9", 4, &s)), 4, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0xd83d, "c16=U+%"PRIx16, (uint16_t)c16); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0xdca9, "c16=U+%"PRIx16, (uint16_t)c16); + + /* Letter e with acute, precomposed. */ + memset(&s, 0, sizeof(s)); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\xc3\xa9", 2, &s)), 2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0xe9, "c16=U+%"PRIx16, (uint16_t)c16); + + /* Letter e with acute, combined. */ + memset(&s, 0, sizeof(s)); + c16 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\x65\xcc\x81", 3, &s)), 1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0x65, "c16=U+%"PRIx16, (uint16_t)c16); + ATF_CHECK_EQ_MSG((n = mbrtoc16(&c16, "\xcc\x81", 2, &s)), 2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c16, 0x301, "c16=U+%"PRIx16, (uint16_t)c16); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, mbrtoc16_c_locale_test); + ATF_TP_ADD_TC(tp, mbrtoc16_iso2022jp_locale_test); + ATF_TP_ADD_TC(tp, mbrtoc16_iso_8859_1_test); + ATF_TP_ADD_TC(tp, mbrtoc16_iso_8859_15_test); + ATF_TP_ADD_TC(tp, mbrtoc16_utf_8_test); + + return (atf_no_error()); +} diff --git a/lib/libc/locale/t_mbrtoc32.c b/lib/libc/locale/t_mbrtoc32.c new file mode 100644 index 000000000000..8ccc421400a8 --- /dev/null +++ b/lib/libc/locale/t_mbrtoc32.c @@ -0,0 +1,61 @@ +/* $NetBSD: t_mbrtoc32.c,v 1.1 2024/08/15 14:16:34 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mbrtoc32.c,v 1.1 2024/08/15 14:16:34 riastradh Exp $"); + +#include <atf-c.h> +#include <locale.h> +#include <uchar.h> + +#include "h_macros.h" + +ATF_TC(mbrtoc32_null); +ATF_TC_HEAD(mbrtoc32_null, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test null string input to mbrtoc32"); +} +ATF_TC_BODY(mbrtoc32_null, tc) +{ + char *locale; + char32_t c32; + mbstate_t ps = {0}; + size_t n; + + REQUIRE_LIBC((locale = setlocale(LC_ALL, "C")), NULL); + ATF_REQUIRE_EQ_MSG(strcmp(locale, "C"), 0, "locale=%s", locale); + + ATF_CHECK_EQ_MSG((n = mbrtoc32(&c32, NULL, 0, &ps)), 0, "n=%zu", n); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, mbrtoc32_null); + return atf_no_error(); +} diff --git a/lib/libc/locale/t_mbrtoc8.c b/lib/libc/locale/t_mbrtoc8.c new file mode 100644 index 000000000000..760f19a62f08 --- /dev/null +++ b/lib/libc/locale/t_mbrtoc8.c @@ -0,0 +1,415 @@ +/* $NetBSD: t_mbrtoc8.c,v 1.3 2024/08/20 17:43:09 riastradh Exp $ */ + +/*- + * Copyright (c) 2002 Tim J. Robbins + * All rights reserved. + * + * Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Test program for mbrtoc8() as specified by C23. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mbrtoc8.c,v 1.3 2024/08/20 17:43:09 riastradh Exp $"); + +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <locale.h> +#include <string.h> +#include <uchar.h> + +#include <atf-c.h> + +static void +require_lc_ctype(const char *locale_name) +{ + char *lc_ctype_set; + + lc_ctype_set = setlocale(LC_CTYPE, locale_name); + if (lc_ctype_set == NULL) + atf_tc_fail("setlocale(LC_CTYPE, \"%s\") failed; errno=%d", + locale_name, errno); + + ATF_REQUIRE_EQ_MSG(strcmp(lc_ctype_set, locale_name), 0, + "lc_ctype_set=%s locale_name=%s", lc_ctype_set, locale_name); +} + +static mbstate_t s; +static char8_t c8; + +ATF_TC_WITHOUT_HEAD(mbrtoc8_c_locale_test); +ATF_TC_BODY(mbrtoc8_c_locale_test, tc) +{ + size_t n; + + require_lc_ctype("C"); + + /* Null wide character, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 1, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Null wide character. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 1, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Latin letter A, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc8(NULL, 0, 0, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "A", 1, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'A', "c8=0x%"PRIx8" 'A'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'A'); + + /* Latin letter A. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "A", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'A', "c8=0x%"PRIx8" 'A'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'A'); + + /* Incomplete character sequence. */ + c8 = 'z'; + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'z', "c8=0x%"PRIx8" 'z'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'z'); + + /* Check that mbrtoc8() doesn't access the buffer when n == 0. */ + c8 = 'z'; + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'z', "c8=0x%"PRIx8" 'z'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'z'); + + /* Check that mbrtoc8() doesn't read ahead too aggressively. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "AB", 2, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'A', "c8=0x%"PRIx8" 'A'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'A'); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "C", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'C', "c8=0x%"PRIx8" 'C'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'C'); + +} + +ATF_TC_WITHOUT_HEAD(mbrtoc8_iso2022jp_locale_test); +ATF_TC_BODY(mbrtoc8_iso2022jp_locale_test, tc) +{ + size_t n; + + require_lc_ctype("ja_JP.ISO-2022-JP"); + + /* Null wide character, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 1, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Null wide character. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 1, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Latin letter A, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc8(NULL, 0, 0, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "A", 1, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'A', "c8=0x%"PRIx8" 'A'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'A'); + + /* Latin letter A. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "A", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'A', "c8=0x%"PRIx8" 'A'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'A'); + + /* Incomplete character sequence. */ + c8 = 'z'; + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'z', "c8=0x%"PRIx8" 'z'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'z'); + + /* Check that mbrtoc8() doesn't access the buffer when n == 0. */ + c8 = 'z'; + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'z', "c8=0x%"PRIx8" 'z'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'z'); + + /* Check that mbrtoc8() doesn't read ahead too aggressively. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "AB", 2, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'A', "c8=0x%"PRIx8" 'A'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'A'); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "C", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'C', "c8=0x%"PRIx8" 'C'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'C'); + + /* Incomplete character sequence (shift sequence only). */ + memset(&s, 0, sizeof(s)); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x1b(J", 3, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Same as above, but complete (U+00A5 YEN SIGN). */ + memset(&s, 0, sizeof(s)); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x1b(J\x5c", 4, &s)), 4, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xc2, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xa5, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Test restarting behaviour. */ + memset(&s, 0, sizeof(s)); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x1b(", 2, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "J\x5c", 2, &s)), 2, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xc2, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xa5, "c8=0x%"PRIx8, (uint8_t)c8); + + /* + * Test shift sequence state in various increments: + * 1. U+0042 LATIN CAPITAL LETTER A + * 2. (shift ISO/IEC 646:JP) U+00A5 YEN SIGN + * 3. U+00A5 YEN SIGN + * 4. (shift JIS X 0208) U+30A2 KATAKANA LETTER A + * 5. U+30A2 KATAKANA LETTER A + * 6. (shift to initial state) U+0000 NUL + */ + memset(&s, 0, sizeof(s)); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "A\x1b(J", 4, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'A', "c8=0x%"PRIx8, (uint8_t)c8); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x1b(J", 3, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x5c\x5c", 2, &s)), 1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xc2, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x5c\x1b$", 3, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xa5, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x5c\x1b$", 3, &s)), 1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xc2, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x1b", 1, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xa5, "c8=0x%"PRIx8, (uint8_t)c8); + c8 = 0xff; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x1b", 1, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xff, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "$B\x25\x22", 4, &s)), 4, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xe3, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x25", 1, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0x82, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x25", 1, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xa2, "c8=0x%"PRIx8, (uint8_t)c8); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x25", 1, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x22\x1b(B\x00", 5, &s)), 1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xe3, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x1b(", 2, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0x82, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x1b(", 2, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xa2, "c8=0x%"PRIx8, (uint8_t)c8); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x1b(", 2, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + c8 = 42; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "B\x00", 2, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); +} + +ATF_TC_WITHOUT_HEAD(mbrtoc8_iso_8859_1_test); +ATF_TC_BODY(mbrtoc8_iso_8859_1_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.ISO8859-1"); + + /* Currency sign. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\xa4", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xc2, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xa4, "c8=0x%"PRIx8, (uint8_t)c8); +} + +ATF_TC_WITHOUT_HEAD(mbrtoc8_iso_8859_15_test); +ATF_TC_BODY(mbrtoc8_iso_8859_15_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.ISO8859-15"); + + /* Euro sign. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\xa4", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xe2, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0x82, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xac, "c8=0x%"PRIx8, (uint8_t)c8); +} + +ATF_TC_WITHOUT_HEAD(mbrtoc8_utf_8_test); +ATF_TC_BODY(mbrtoc8_utf_8_test, tc) +{ + size_t n; + + require_lc_ctype("en_US.UTF-8"); + + /* Null wide character, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc8(NULL, 0, 0, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 1, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Null wide character. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 1, &s)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Latin letter A, internal state. */ + ATF_CHECK_EQ_MSG((n = mbrtoc8(NULL, 0, 0, NULL)), 0, "n=%zu", n); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "A", 1, NULL)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'A', "c8=0x%"PRIx8" 'A'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'A'); + + /* Latin letter A. */ + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "A", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'A', "c8=0x%"PRIx8" 'A'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'A'); + + /* Incomplete character sequence (zero length). */ + c8 = 'z'; + memset(&s, 0, sizeof(s)); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 'z', "c8=0x%"PRIx8" 'z'=0x%"PRIx8, + (uint8_t)c8, (uint8_t)'z'); + + /* Incomplete character sequence (truncated double-byte). */ + memset(&s, 0, sizeof(s)); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\xc3", 1, &s)), (size_t)-2, + "n=%zu", n); + + /* Same as above, but complete. */ + memset(&s, 0, sizeof(s)); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\xc3\x84", 2, &s)), 2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xc3, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0x84, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Test restarting behaviour. */ + memset(&s, 0, sizeof(s)); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\xc3", 1, &s)), (size_t)-2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\xb7", 1, &s)), 1, "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xc3, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xb7, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Four-byte sequence. */ + memset(&s, 0, sizeof(s)); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\xf0\x9f\x92\xa9", 4, &s)), 4, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xf0, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0x9f, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0x92, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xa9, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Letter e with acute, precomposed. */ + memset(&s, 0, sizeof(s)); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\xc3\xa9", 2, &s)), 2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xc3, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xa9, "c8=0x%"PRIx8, (uint8_t)c8); + + /* Letter e with acute, combined. */ + memset(&s, 0, sizeof(s)); + c8 = 0; + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\x65\xcc\x81", 3, &s)), 1, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0x65, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "\xcc\x81", 2, &s)), 2, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0xcc, "c8=0x%"PRIx8, (uint8_t)c8); + ATF_CHECK_EQ_MSG((n = mbrtoc8(&c8, "", 0, &s)), (size_t)-3, + "n=%zu", n); + ATF_CHECK_EQ_MSG(c8, 0x81, "c8=0x%"PRIx8, (uint8_t)c8); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, mbrtoc8_c_locale_test); + ATF_TP_ADD_TC(tp, mbrtoc8_iso2022jp_locale_test); + ATF_TP_ADD_TC(tp, mbrtoc8_iso_8859_1_test); + ATF_TP_ADD_TC(tp, mbrtoc8_iso_8859_15_test); + ATF_TP_ADD_TC(tp, mbrtoc8_utf_8_test); + + return (atf_no_error()); +} diff --git a/lib/libc/locale/t_uchar.c b/lib/libc/locale/t_uchar.c new file mode 100644 index 000000000000..66e4830fb88a --- /dev/null +++ b/lib/libc/locale/t_uchar.c @@ -0,0 +1,81 @@ +/* $NetBSD: t_uchar.c,v 1.3 2024/10/14 06:02:14 rillig Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Include <uchar.h> first to verify it declares everything we need. + */ +#include <uchar.h> +typedef mbstate_t nbtest_mbstate_t; +typedef size_t nbtest_size_t; +typedef char8_t nbtest_char8_t; +typedef char16_t nbtest_char16_t; +typedef char32_t nbtest_char32_t; +static size_t (*nbtest_mbrtoc8)(char8_t *restrict, const char *restrict, + size_t, mbstate_t *restrict) __unused = &mbrtoc8; +static size_t (*nbtest_c8rtomb)(char *restrict, char8_t, + mbstate_t *restrict) __unused = &c8rtomb; +static size_t (*nbtest_mbrtoc16)(char16_t *restrict, const char *restrict, + size_t, mbstate_t *restrict) __unused = &mbrtoc16; +static size_t (*nbtest_c16rtomb)(char *restrict, char16_t, + mbstate_t *restrict) __unused = &c16rtomb; +static size_t (*nbtest_mbrtoc32)(char32_t *restrict, const char *restrict, + size_t, mbstate_t *restrict) __unused = mbrtoc32; +static size_t (*nbtest_c32rtomb)(char *restrict, char32_t, + mbstate_t *restrict) __unused = &c32rtomb; + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_uchar.c,v 1.3 2024/10/14 06:02:14 rillig Exp $"); + +#include <atf-c.h> +#include <stdint.h> + +ATF_TC(uchartypes); +ATF_TC_HEAD(uchartypes, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test <uchar.h> types are reasonable"); +} +ATF_TC_BODY(uchartypes, tc) +{ + + ATF_CHECK_EQ_MSG(sizeof(char8_t), sizeof(unsigned char), + "char8_t %zu, unsigned char %zu", + sizeof(char8_t), sizeof(unsigned char)); + ATF_CHECK_EQ_MSG(sizeof(char16_t), sizeof(uint_least16_t), + "char16_t %zu, uint_least16_t %zu", + sizeof(char16_t), sizeof(uint_least16_t)); + ATF_CHECK_EQ_MSG(sizeof(char32_t), sizeof(uint_least32_t), + "char32_t %zu, uint_least32_t %zu", + sizeof(char32_t), sizeof(uint_least32_t)); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, uchartypes); + return atf_no_error(); +} diff --git a/lib/libc/misc/t_vis.c b/lib/libc/misc/t_vis.c new file mode 100644 index 000000000000..a712ffa2f9d2 --- /dev/null +++ b/lib/libc/misc/t_vis.c @@ -0,0 +1,165 @@ +/* $NetBSD: t_vis.c,v 1.2 2025/11/16 12:43:25 nia Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Nia Alarie. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <atf-c.h> +#include <string.h> +#include <stdio.h> +#include "vis_types.h" +#include "vis_proto.h" + +ATF_TC(vis_test_addsub); + +ATF_TC_HEAD(vis_test_addsub, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test 32-bit packed add/subtract"); +} + +ATF_TC_BODY(vis_test_addsub, tc) +{ + vis_d64 v1, v2, v3; + vis_f32 f1, f2; + vis_u32 u1, u2; + + v1 = vis_to_double(8, 16); + v2 = vis_to_double(16, 8); + + v3 = vis_fpadd32(v1, v2); + + f1 = vis_read_lo(v3); + memcpy(&u1, &f1, sizeof(f1)); + f2 = vis_read_hi(v3); + memcpy(&u2, &f2, sizeof(f2)); + + ATF_REQUIRE(u1 == 24 && u2 == 24); + + v2 = vis_to_double(4, 4); + v3 = vis_fpsub32(v3, v2); + + f1 = vis_read_lo(v3); + memcpy(&u1, &f1, sizeof(f1)); + f2 = vis_read_hi(v3); + memcpy(&u2, &f2, sizeof(f2)); + + ATF_REQUIRE(u1 == 20 && u2 == 20); +} + +ATF_TC(vis_test_bitwise); + +ATF_TC_HEAD(vis_test_bitwise, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test 32-bit packed bitwise"); +} + +ATF_TC_BODY(vis_test_bitwise, tc) +{ + static vis_u8 testbytes1[8] = { 1, 0, 1, 1, 1, 0, 1, 1 }; + static vis_u8 testbytes2[8] = { 1, 1, 0, 1, 1, 1, 0, 1 }; + static vis_u8 test_and[8] = { 1, 0, 0, 1, 1, 0, 0, 1 }; + static vis_u8 test_or[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; + static vis_u8 test_zero[8] = { 0 }; + static vis_u64 test_ones = 0xffffffffffffffff; + double v1, v2, v3; + + memcpy(&v1, testbytes1, sizeof(v1)); + memcpy(&v2, testbytes2, sizeof(v2)); + + v3 = vis_fand(v1, v2); + + ATF_REQUIRE(memcmp(&v3, test_and, sizeof(v3)) == 0); + + v3 = vis_fone(); + + ATF_REQUIRE(memcmp(&v3, &test_ones, sizeof(v3)) == 0); + + v3 = vis_for(v1, v2); + + ATF_REQUIRE(memcmp(&v3, test_or, sizeof(v3)) == 0); + + v3 = vis_fzero(); + + ATF_REQUIRE(memcmp(&v3, test_zero, sizeof(v3)) == 0); +} + +ATF_TC(vis_test_fcmpeq16); + +ATF_TC_HEAD(vis_test_fcmpeq16, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test 16-bit packed compare"); +} + +ATF_TC_BODY(vis_test_fcmpeq16, tc) +{ + static vis_u16 testshort1[4] = { 16000, 16000, 16000, 16000 }; + static vis_u16 testshort2[4] = { 32000, 16000, 32000, 16000 }; + static vis_u16 testshort3[4] = { 48000, 48000, 48000, 48000 }; + vis_d64 v1, v2, v3; + + memcpy(&v1, testshort1, sizeof(v1)); + memcpy(&v2, testshort2, sizeof(v2)); + memcpy(&v3, testshort3, sizeof(v3)); + + ATF_REQUIRE((!!vis_fcmpeq16(v1, v2)) != 0); + ATF_REQUIRE((!!vis_fcmpeq16(v1, v3)) == 0); + ATF_REQUIRE((!!vis_fcmpne16(v1, v3)) != 0); +} + +ATF_TC(vis_test_fcmpeq32); + +ATF_TC_HEAD(vis_test_fcmpeq32, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test 32-bit packed compare"); +} + +ATF_TC_BODY(vis_test_fcmpeq32, tc) +{ + static vis_u32 testlong1[2] = { 16000, 16000 }; + static vis_u32 testlong2[2] = { 32000, 16000 }; + static vis_u32 testlong3[2] = { 48000, 48000 }; + vis_d64 v1, v2, v3; + + memcpy(&v1, testlong1, sizeof(v1)); + memcpy(&v2, testlong2, sizeof(v2)); + memcpy(&v3, testlong3, sizeof(v3)); + + ATF_REQUIRE((!!vis_fcmpeq32(v1, v2)) != 0); + ATF_REQUIRE((!!vis_fcmpeq32(v1, v3)) == 0); + ATF_REQUIRE((!!vis_fcmpne32(v1, v3)) != 0); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, vis_test_addsub); + ATF_TP_ADD_TC(tp, vis_test_bitwise); + ATF_TP_ADD_TC(tp, vis_test_fcmpeq16); + ATF_TP_ADD_TC(tp, vis_test_fcmpeq32); + + return atf_no_error(); +} diff --git a/lib/libc/regex/t_regex_binary.c b/lib/libc/regex/t_regex_binary.c new file mode 100644 index 000000000000..0c3d8cb9b908 --- /dev/null +++ b/lib/libc/regex/t_regex_binary.c @@ -0,0 +1,80 @@ +/* $NetBSD: t_regex_binary.c,v 1.1 2025/01/01 18:13:48 christos Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_regex_binary.c,v 1.1 2025/01/01 18:13:48 christos Exp $"); + +#include <atf-c.h> +#include <regex.h> + +ATF_TC(negative_ranges); +ATF_TC_HEAD(negative_ranges, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test negative ranges compilation"); +} +ATF_TC_BODY(negative_ranges, tc) +{ + regex_t re; + char msg[1024]; + int e; + + if ((e = regcomp(&re, "[\xe0-\xf1][\xa0-\xd1].*", REG_EXTENDED)) != 0) { + regerror(e, &re, msg, sizeof(msg)); + ATF_REQUIRE_MSG(0, "regcomp failed %s", msg); + } +} + +ATF_TC(negative_char); +ATF_TC_HEAD(negative_char, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test negative char in braces compilation"); +} +ATF_TC_BODY(negative_char, tc) +{ + regex_t re; + char msg[1024]; + int e; + + /* PR/58910 */ + if ((e = regcomp(&re, ": j:[]j:[]j:[\xd9j:[]", REG_EXTENDED)) != 0) { + regerror(e, &re, msg, sizeof(msg)); + ATF_REQUIRE_MSG(0, "regcomp failed %s", msg); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, negative_ranges); + ATF_TP_ADD_TC(tp, negative_char); + return atf_no_error(); +} diff --git a/lib/libc/setjmp/t_sigstack.c b/lib/libc/setjmp/t_sigstack.c new file mode 100644 index 000000000000..ea827da9545c --- /dev/null +++ b/lib/libc/setjmp/t_sigstack.c @@ -0,0 +1,389 @@ +/* $NetBSD: t_sigstack.c,v 1.25 2025/05/12 14:46:19 christos Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_sigstack.c,v 1.25 2025/05/12 14:46:19 christos Exp $"); + +#include <dlfcn.h> +#include <setjmp.h> +#include <signal.h> +#include <stddef.h> +#include <stdlib.h> +#include <ucontext.h> + +#include "h_macros.h" + +struct sigaltstack ss[3]; +jmp_buf jmp; +sigjmp_buf sigjmp; +unsigned nentries; +const char *bailname; +void (*bailfn)(void) __dead; + +/* + * Optional compat13 functions from when sigcontext was expanded. + * Fortunately the only change visible to the caller is that the size + * of jmp_buf increased, so we can always use the old symbols with new + * jmp_buf arrays. + */ +int (*compat13_sigsetjmp)(sigjmp_buf, int); +void (*compat13_siglongjmp)(sigjmp_buf, int) __dead; +int (*compat13_setjmp)(jmp_buf); +void (*compat13_longjmp)(jmp_buf, int) __dead; + +/* + * compatsigsys(signo) + * + * Signal handler for SIGSYS in case compat_13_sigreturn13 is not + * implemented by the kernel -- we will just skip the test in that + * case. + */ +static void +compatsigsys(int signo) +{ + + atf_tc_skip("no compat syscalls to test"); +} + +static void +compatsetup(void) +{ + + /* + * Grab the libc library symbols if available. + */ + if ((compat13_sigsetjmp = dlsym(RTLD_SELF, "sigsetjmp")) == NULL || + (compat13_siglongjmp = dlsym(RTLD_SELF, "siglongjmp")) == NULL || + (compat13_setjmp = dlsym(RTLD_SELF, "setjmp")) == NULL || + (compat13_longjmp = dlsym(RTLD_SELF, "longjmp")) == NULL) + atf_tc_skip("no compat functions to test"); + + /* + * Arrange for SIGSYS to skip the test -- this happens if the + * libc stub has the function, but the kernel isn't built with + * support for the compat13 sigreturn syscall for longjmp. + */ + REQUIRE_LIBC(signal(SIGSYS, &compatsigsys), SIG_ERR); +} + +static void +on_sigusr1(int signo, siginfo_t *si, void *ctx) +{ + ucontext_t *uc = ctx; + void *sp = (void *)(uintptr_t)_UC_MACHINE_SP(uc); + void *fp = __builtin_frame_address(0); + struct sigaltstack *ssp; + + /* + * Ensure we haven't re-entered the signal handler too many + * times. We should enter only twice. + */ + ATF_REQUIRE_MSG(nentries < 2, + "%u recursive signal handler entries is too many in this test", + nentries + 1); + + /* + * Ensure that the signal handler was called in the alternate + * signal stack. + */ + ssp = &ss[nentries]; + ATF_REQUIRE_MSG((fp >= ssp->ss_sp && + fp < (void *)((char *)ssp->ss_sp + ssp->ss_size)), + "sigaltstack failed to take effect on entry %u --" + " signal handler's frame pointer %p doesn't lie in sigaltstack" + " [%p, %p), size 0x%zx", + nentries, + fp, ssp->ss_sp, (char *)ssp->ss_sp + ssp->ss_size, ssp->ss_size); + + /* + * Ensure that if we enter the signal handler, we are entering + * it from the original stack, not from any of the alternate + * signal stacks. + */ + for (ssp = &ss[0]; ssp < &ss[__arraycount(ss)]; ssp++) { + ATF_REQUIRE_MSG((sp < ssp->ss_sp || + sp >= (void *)((char *)ssp->ss_sp + ssp->ss_size)), + "%s failed to restore stack" + " before allowing signal on entry %u --" + " interrupted stack pointer %p lies in sigaltstack %zd" + " [%p, %p), size 0x%zx", + bailname, + nentries, + sp, ssp - ss, + ssp->ss_sp, (char *)ssp->ss_sp + ssp->ss_size, + ssp->ss_size); + } + + /* + * First time through, we want to test whether longjmp restores + * the signal mask first, or restores the stack pointer first. + * The signal should be blocked at this point, so we re-raise + * the signal to queue it up for delivery as soon as it is + * unmasked -- which should wait until the stack pointer has + * been restored in longjmp. + */ + if (nentries++ == 0) + RL(raise(SIGUSR1)); + + /* + * Set up the next sigaltstack. We can't reuse the current one + * for the next signal handler re-entry until the system clears + * the SS_ONSTACK process state -- which normal return from + * signal handler does, but which longjmp does not. So to keep + * it simple (ha), we just use another sigaltstack. + */ + RL(sigaltstack(&ss[nentries], NULL)); + + /* + * Jump back to the original context. + */ + (*bailfn)(); +} + +static void +go(const char *name, void (*fn)(void) __dead) +{ + struct sigaction sa; + unsigned i; + + bailname = name; + bailfn = fn; + + /* + * Allocate a stack for the signal handler to run in, and + * configure the system to use the first one. + * + * XXX Should maybe use a guard page but this is simpler. + */ + for (i = 0; i < __arraycount(ss); i++) { + ss[i].ss_size = SIGSTKSZ; + REQUIRE_LIBC(ss[i].ss_sp = malloc(ss[i].ss_size), NULL); + } + RL(sigaltstack(&ss[0], NULL)); + + /* + * Set up a test signal handler for SIGUSR1. Allow all + * signals, except SIGUSR1 (which is masked by default) -- that + * way we don't inadvertently obscure weird crashes in the + * signal handler. + * + * Set SA_SIGINFO so the system will pass siginfo -- and, more + * to the point, ucontext, so the signal handler can determine + * the stack pointer of the logic it interrupted. + * + * Set SA_ONSTACK so the system will use the alternate signal + * stack to call the signal handler -- that way, it can tell + * whether the stack was restored before the second time + * around. + */ + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = &on_sigusr1; + RL(sigemptyset(&sa.sa_mask)); + sa.sa_flags = SA_SIGINFO|SA_ONSTACK; + RL(sigaction(SIGUSR1, &sa, NULL)); + + /* + * Raise the signal to enter the signal handler the first time. + */ + RL(raise(SIGUSR1)); + + /* + * If we ever reach this point, something went seriously wrong. + */ + atf_tc_fail("unreachable"); +} + +static void __dead +bail_longjmp(void) +{ + + longjmp(jmp, 1); +} + +ATF_TC(setjmp); +ATF_TC_HEAD(setjmp, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test longjmp restores stack first, then signal mask"); +} +ATF_TC_BODY(setjmp, tc) +{ + +#if defined __ia64__ + atf_tc_expect_fail("PR lib/57946:" + " longjmp fails to restore stack first before" + " restoring signal mask on most architectures"); +#endif + + /* + * Set up a return point for the signal handler: when the + * signal handler does longjmp(jmp, 1), it comes flying out of + * here. + */ + if (setjmp(jmp) == 1) + return; + + /* + * Run the test with longjmp. + */ + go("longjmp", &bail_longjmp); +} + +static void __dead +bail_compat13_longjmp(void) +{ + + (*compat13_longjmp)(jmp, 1); +} + +ATF_TC(compat13_setjmp); +ATF_TC_HEAD(compat13_setjmp, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test compat13 longjmp restores stack first, then signal mask"); +} +ATF_TC_BODY(compat13_setjmp, tc) +{ + + compatsetup(); + +#if defined __arm__ || defined __i386__ || defined __sh3__ +#ifndef __arm__ /* will be exposed once PR 59351 is fixed */ + atf_tc_expect_fail("PR lib/57946:" + " longjmp fails to restore stack first before" + " restoring signal mask on most architectures"); +#endif +#endif +#ifdef __arm__ + atf_tc_expect_signal(-1, "PR port-arm/59351: compat_setjmp is busted"); +#endif + + /* + * Set up a return point for the signal handler: when the + * signal handler does (*compat13_longjmp)(jmp, 1), it comes + * flying out of here. + */ + if ((*compat13_setjmp)(jmp) == 1) + return; + + /* + * Run the test with compat13_longjmp. + */ + go("longjmp", &bail_compat13_longjmp); +} + +static void __dead +bail_siglongjmp(void) +{ + + siglongjmp(sigjmp, 1); +} + +ATF_TC(sigsetjmp); +ATF_TC_HEAD(sigsetjmp, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test siglongjmp restores stack first, then signal mask"); +} +ATF_TC_BODY(sigsetjmp, tc) +{ + +#if defined __ia64__ + atf_tc_expect_fail("PR lib/57946:" + " longjmp fails to restore stack first before" + " restoring signal mask on most architectures"); +#endif + + /* + * Set up a return point for the signal handler: when the + * signal handler does siglongjmp(sigjmp, 1), it comes flying + * out of here. + */ + if (sigsetjmp(sigjmp, /*savesigmask*/1) == 1) + return; + + /* + * Run the test with siglongjmp. + */ + go("siglongjmp", &bail_siglongjmp); +} + +static void __dead +bail_compat13_siglongjmp(void) +{ + + (*compat13_siglongjmp)(sigjmp, 1); +} + +ATF_TC(compat13_sigsetjmp); +ATF_TC_HEAD(compat13_sigsetjmp, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test compat13 siglongjmp restores stack first," + " then signal mask"); +} +ATF_TC_BODY(compat13_sigsetjmp, tc) +{ + + compatsetup(); + +#if defined __arm__ || defined __i386__ || defined __sh3__ +#ifndef __arm__ /* will be exposed once PR 59351 is fixed */ + atf_tc_expect_fail("PR lib/57946:" + " longjmp fails to restore stack first before" + " restoring signal mask on most architectures"); +#endif +#endif +#ifdef __arm__ + atf_tc_expect_signal(-1, "PR port-arm/59351: compat_setjmp is busted"); +#endif + + /* + * Set up a return point for the signal handler: when the + * signal handler does (*compat13_siglongjmp)(sigjmp, 1), it + * comes flying out of here. + */ + if ((*compat13_sigsetjmp)(sigjmp, /*savesigmask*/1) == 1) + return; + + /* + * Run the test with compat13_siglongjmp. + */ + go("siglongjmp", &bail_compat13_siglongjmp); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, compat13_setjmp); + ATF_TP_ADD_TC(tp, compat13_sigsetjmp); + ATF_TP_ADD_TC(tp, setjmp); + ATF_TP_ADD_TC(tp, sigsetjmp); + + return atf_no_error(); +} diff --git a/lib/libc/ssp/h_getcwd2.c b/lib/libc/ssp/h_getcwd2.c new file mode 100644 index 000000000000..86cfd09f2bb0 --- /dev/null +++ b/lib/libc/ssp/h_getcwd2.c @@ -0,0 +1,18 @@ +#include <err.h> +#include <errno.h> +#include <unistd.h> + +char* +getcwd(char* buf, size_t buflen) +{ + errno = ENOSYS; + return NULL; +} +int +main(void) +{ + char buf[256]; + if (getcwd(buf, sizeof buf) == NULL) + err(1, "getcwd failed"); + return 0; +} diff --git a/lib/libc/stdlib/h_sort.c b/lib/libc/stdlib/h_sort.c new file mode 100644 index 000000000000..1e5f4b3b0798 --- /dev/null +++ b/lib/libc/stdlib/h_sort.c @@ -0,0 +1,225 @@ +/* $NetBSD: h_sort.c,v 1.3 2025/03/02 23:11:19 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_sort.c,v 1.3 2025/03/02 23:11:19 riastradh Exp $"); + +#include <assert.h> +#include <err.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void +heapsort_r_wrapper(void *a, size_t n, size_t sz, + int (*cmp)(const void *, const void *, void *), void *cookie) +{ + + if (heapsort_r(a, n, sz, cmp, cookie) == -1) + err(1, "heapsort_r"); +} + +static void +mergesort_r_wrapper(void *a, size_t n, size_t sz, + int (*cmp)(const void *, const void *, void *), void *cookie) +{ + + if (mergesort_r(a, n, sz, cmp, cookie) == -1) + err(1, "mergesort_r"); +} + +struct context { + const char *buf; + const size_t *linepos; +}; + +static int +cmp(const void *va, const void *vb, void *cookie) +{ + const struct context *C = cookie; + const size_t *a = va; + const size_t *b = vb; + + return strcmp(C->buf + C->linepos[*a], C->buf + C->linepos[*b]); +} + +static void __dead +usage(void) +{ + + fprintf(stderr, "Usage: %s [-n] <sortfn>\n", getprogname()); + exit(1); +} + +int +main(int argc, char **argv) +{ + int ch; + int nflag = 0; + void (*sortfn)(void *, size_t, size_t, + int (*)(const void *, const void *, void *), void *); + char *buf = NULL; + size_t nbuf; + size_t *linepos = NULL; + size_t nlines; + size_t *permutation = NULL; + size_t off; + ssize_t nread; + char *p; + size_t i; + int error; + + /* + * Parse arguments. + */ + setprogname(argv[0]); + while ((ch = getopt(argc, argv, "hn")) != -1) { + switch (ch) { + case 'n': + nflag = 1; + break; + case '?': + case 'h': + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (argc != 1) + usage(); + if (strcmp(argv[0], "heapsort_r") == 0) + sortfn = &heapsort_r_wrapper; + else if (strcmp(argv[0], "mergesort_r") == 0) + sortfn = &mergesort_r_wrapper; + else if (strcmp(argv[0], "qsort_r") == 0) + sortfn = &qsort_r; + else + errx(1, "unknown sort: %s", argv[0]); + + /* + * Allocate an initial 4K buffer. + */ + nbuf = 0x1000; + error = reallocarr(&buf, nbuf, 1); + if (error) + errc(1, error, "reallocarr"); + + /* + * Read the input into a contiguous buffer. Reject input with + * embedded NULs so we can use strcmp(3) to compare lines. + */ + off = 0; + while ((nread = read(STDIN_FILENO, buf + off, nbuf - off - 1)) != 0) { + if (nread == -1) + err(1, "read"); + if ((size_t)nread > nbuf - off - 1) + errx(1, "overlong read: %zu", (size_t)nread); + if (memchr(buf + off, '\0', (size_t)nread) != NULL) + errx(1, "NUL byte in input"); + off += (size_t)nread; + + /* + * If we filled the buffer, reallocate it with double + * the size. Bail if that would overflow. + */ + if (nbuf - off == 1) { + if (nbuf > SIZE_MAX/2) + errx(1, "input overflow"); + nbuf *= 2; + error = reallocarr(&buf, nbuf, 1); + if (error) + errc(1, error, "reallocarr"); + } + } + + /* + * If the input was empty, nothing to do. + */ + if (off == 0) + return 0; + + /* + * NUL-terminate the input and count the lines. The last line + * may have no trailing \n. + */ + buf[off] = '\0'; + nlines = 1; + for (p = buf; (p = strchr(p, '\n')) != NULL;) { + if (*++p == '\0') + break; + nlines++; + } + + /* + * Create an array of line positions to sort. NUL-terminate + * each line so we can use strcmp(3). + */ + error = reallocarr(&linepos, nlines, sizeof(linepos[0])); + if (error) + errc(1, error, "reallocarr"); + i = 0; + for (p = buf; linepos[i++] = p - buf, (p = strchr(p, '\n')) != NULL;) { + *p = '\0'; + if (*++p == '\0') + break; + } + assert(i == nlines); + + /* + * Create an array of permuted line numbers. + */ + error = reallocarr(&permutation, nlines, sizeof(permutation[0])); + if (error) + errc(1, error, "reallocarr"); + for (i = 0; i < nlines; i++) + permutation[i] = i; + + /* + * Sort the lines via comparison function that consults the + * buffer as a cookie. + */ + (*sortfn)(permutation, nlines, sizeof(permutation[0]), &cmp, + &(struct context) { .buf = buf, .linepos = linepos }); + + /* + * Print the lines in sorted order with the original line + * numbers. + */ + for (i = 0; i < nlines; i++) { + const size_t j = permutation[i]; + if (nflag) + printf("%zu %s\n", j, buf + linepos[j]); + else + printf("%s\n", buf + linepos[j]); + } + fflush(stdout); + return ferror(stdout); +} diff --git a/lib/libc/stdlib/t_sort.sh b/lib/libc/stdlib/t_sort.sh new file mode 100644 index 000000000000..8987ac1ec623 --- /dev/null +++ b/lib/libc/stdlib/t_sort.sh @@ -0,0 +1,115 @@ +# $NetBSD: t_sort.sh,v 1.2 2025/03/02 20:00:32 riastradh Exp $ +# +# Copyright (c) 2025 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +check_sort() +{ + local sortfn + + set -eu + + sortfn="$1" + + printf 'foo\nbar\nbaz\nquux' >in1 + printf '1 bar\n2 baz\n0 foo\n3 quux\n' >out1 + atf_check -s exit:0 -o file:out1 \ + "$(atf_get_srcdir)"/h_sort -n "$sortfn" <in1 + + atf_check -s exit:0 -o empty sh -c 'exec shuffle -f - <in1 >in2' + printf 'bar\nbaz\nfoo\nquux\n' >out2 + atf_check -s exit:0 -o file:out2 \ + "$(atf_get_srcdir)"/h_sort "$sortfn" <in2 +} + +check_stablesort() +{ + local sortfn + + set -eu + + sortfn="$1" + + printf 'foo\nfoo\nfoo\nfoo\nfoo' >in1 + printf '0 foo\n1 foo\n2 foo\n3 foo\n4 foo\n' >out1 + atf_check -s exit:0 -o file:out1 \ + "$(atf_get_srcdir)"/h_sort -n "$sortfn" <in1 + + printf 'foo\nfoo\nfoo\nfoo\nfoo\nbar\nbar\nbar\nbar\nbar' >in2 + printf '5 bar\n6 bar\n7 bar\n8 bar\n9 bar\n' >out2 + printf '0 foo\n1 foo\n2 foo\n3 foo\n4 foo\n' >>out2 + atf_check -s exit:0 -o file:out2 \ + "$(atf_get_srcdir)"/h_sort -n "$sortfn" <in2 + + printf 'foo\nfoo\nbar\nbaz\nquux' >in3 + printf '2 bar\n3 baz\n0 foo\n1 foo\n4 quux\n' >out3 + atf_check -s exit:0 -o file:out3 \ + "$(atf_get_srcdir)"/h_sort -n "$sortfn" <in3 + + printf 'foo\nbar\nbar\nbaz\nquux' >in4 + printf '1 bar\n2 bar\n3 baz\n0 foo\n4 quux\n' >out4 + atf_check -s exit:0 -o file:out4 \ + "$(atf_get_srcdir)"/h_sort -n "$sortfn" <in4 + + printf 'foo\nbar\nbaz\nbaz\nquux' >in5 + printf '1 bar\n2 baz\n3 baz\n0 foo\n4 quux\n' >out5 + atf_check -s exit:0 -o file:out5 \ + "$(atf_get_srcdir)"/h_sort -n "$sortfn" <in5 + + printf 'foo\nbar\nbaz\nquux\nquux' >in6 + printf '1 bar\n2 baz\n0 foo\n3 quux\n4 quux\n' >out6 + atf_check -s exit:0 -o file:out6 \ + "$(atf_get_srcdir)"/h_sort -n "$sortfn" <in6 +} + +sortfn_case() +{ + local sortfn + + sortfn="$1" + + eval "${sortfn}_head() { atf_set descr \"Test ${sortfn}\"; }" + eval "${sortfn}_body() { check_sort $sortfn; }" + atf_add_test_case "$sortfn" +} + +stablesortfn_case() +{ + local sortfn + + sortfn="$1" + + eval "${sortfn}_stable_head() { atf_set descr \"Test ${sortfn}\"; }" + eval "${sortfn}_stable_body() { check_stablesort $sortfn; }" + atf_add_test_case "${sortfn}_stable" +} + +atf_init_test_cases() +{ + + sortfn_case heapsort_r + sortfn_case mergesort_r + sortfn_case qsort_r + stablesortfn_case mergesort_r +} diff --git a/lib/libc/sys/t_aio_cancel.c b/lib/libc/sys/t_aio_cancel.c new file mode 100644 index 000000000000..43965cada251 --- /dev/null +++ b/lib/libc/sys/t_aio_cancel.c @@ -0,0 +1,223 @@ +/* $NetBSD: t_aio_cancel.c,v 1.1 2025/10/10 15:53:55 christos Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <atf-c.h> + +#include <aio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +static int mktemp_file(char *, size_t); +static void fill_pattern(uint8_t *, size_t, uint8_t); +static void wait_all(const struct aiocb * const [], size_t); + +static int +mktemp_file(char *path, size_t pathlen) +{ + int fd, n; + + n = snprintf(path, pathlen, "t_aio_cancel.XXXXXX"); + ATF_REQUIRE(n > 0 && (size_t)n < pathlen); + + fd = mkstemp(path); + ATF_REQUIRE(fd >= 0); + + return fd; +} + +static void +fill_pattern(uint8_t *buf, size_t len, uint8_t seed) +{ + size_t i; + + for (i = 0; i < len; i++) { + buf[i] = (uint8_t)(seed + (i & 0xff)); + } +} + +static void +wait_all(const struct aiocb * const list[], size_t nent) +{ + size_t i; + int pending, rv; + + for (;;) { + pending = 0; + + for (i = 0; i < nent; i++) { + int err; + + if (list[i] == NULL) { + continue; + } + + err = aio_error(list[i]); + if (err == EINPROGRESS) { + pending = 1; + } + } + + if (!pending) { + break; + } + + rv = aio_suspend(list, (int)nent, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "aio_suspend failed: %s", + strerror(errno)); + } +} + +ATF_TC_WITHOUT_HEAD(cancel_active_write); +ATF_TC_BODY(cancel_active_write, tc) +{ + char path[64]; + int fd, rv, crv, err; + const size_t blksz = 0x1000; + uint8_t *wbuf; + struct aiocb cb; + const struct aiocb *list[1]; + + fd = mktemp_file(path, sizeof(path)); + + wbuf = malloc(blksz); + ATF_REQUIRE(wbuf != NULL); + fill_pattern(wbuf, blksz, 0x33); + + memset(&cb, 0, sizeof(cb)); + cb.aio_fildes = fd; + cb.aio_buf = wbuf; + cb.aio_nbytes = blksz; + cb.aio_offset = 0; + + rv = aio_write(&cb); + ATF_REQUIRE_EQ(0, rv); + + crv = aio_cancel(fd, &cb); + ATF_REQUIRE(crv == AIO_CANCELED || crv == AIO_NOTCANCELED + || crv == AIO_ALLDONE); + + if (crv == AIO_CANCELED) { + do { + err = aio_error(&cb); + } while (err == EINPROGRESS); + ATF_REQUIRE_EQ(ECANCELED, err); + ATF_REQUIRE_EQ(-1, aio_return(&cb)); + } else if (crv == AIO_NOTCANCELED) { + list[0] = &cb; + wait_all(list, 1); + ATF_REQUIRE_EQ(0, aio_error(&cb)); + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb)); + } else { + do { + err = aio_error(&cb); + } while (err == EINPROGRESS); + ATF_REQUIRE_EQ(0, err); + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb)); + } + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); + + free(wbuf); +} + +ATF_TC_WITHOUT_HEAD(cancel_completed_request); +ATF_TC_BODY(cancel_completed_request, tc) +{ + char path[64]; + int fd, rv, crv; + const size_t blksz = 4096; + uint8_t *wbuf; + struct aiocb cb; + const struct aiocb *list[1]; + + fd = mktemp_file(path, sizeof(path)); + + wbuf = malloc(blksz); + ATF_REQUIRE(wbuf != NULL); + memset(wbuf, 0x7E, blksz); + + memset(&cb, 0, sizeof(cb)); + cb.aio_fildes = fd; + cb.aio_buf = wbuf; + cb.aio_nbytes = blksz; + cb.aio_offset = 0; + + rv = aio_write(&cb); + ATF_REQUIRE_EQ(0, rv); + + list[0] = &cb; + wait_all(list, 1); + ATF_REQUIRE_EQ(0, aio_error(&cb)); + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb)); + + crv = aio_cancel(fd, &cb); + ATF_REQUIRE_EQ(AIO_ALLDONE, crv); + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); + + free(wbuf); +} + +ATF_TC_WITHOUT_HEAD(cancel_invalid_fd); +ATF_TC_BODY(cancel_invalid_fd, tc) +{ + struct aiocb cb; + int crv; + + memset(&cb, 0, sizeof(cb)); + cb.aio_fildes = -1; + + errno = 0; + crv = aio_cancel(-1, &cb); + ATF_REQUIRE_EQ(-1, crv); + ATF_REQUIRE_EQ(EBADF, errno); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, cancel_active_write); + ATF_TP_ADD_TC(tp, cancel_completed_request); + ATF_TP_ADD_TC(tp, cancel_invalid_fd); + return atf_no_error(); +} diff --git a/lib/libc/sys/t_aio_lio.c b/lib/libc/sys/t_aio_lio.c new file mode 100644 index 000000000000..991db8d5a7cd --- /dev/null +++ b/lib/libc/sys/t_aio_lio.c @@ -0,0 +1,264 @@ +/* $NetBSD: t_aio_lio.c,v 1.1 2025/10/10 15:53:55 christos Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <atf-c.h> + +#include <aio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +static int mktemp_file(char *, size_t); +static void fill_pattern(uint8_t *, size_t, uint8_t); +static void wait_all(const struct aiocb * const [], size_t); + +static int +mktemp_file(char *path, size_t pathlen) +{ + int fd, n; + + n = snprintf(path, pathlen, "t_aio_lio.XXXXXX"); + ATF_REQUIRE(n > 0 && (size_t)n < pathlen); + + fd = mkstemp(path); + ATF_REQUIRE(fd >= 0); + + return fd; +} + +static void +fill_pattern(uint8_t *buf, size_t len, uint8_t seed) +{ + size_t i; + + for (i = 0; i < len; i++) { + buf[i] = (uint8_t)(seed + (i & 0xff)); + } +} + +static void +wait_all(const struct aiocb * const list[], size_t nent) +{ + size_t i; + int pending, rv; + + for (;;) { + pending = 0; + + for (i = 0; i < nent; i++) { + int err; + + if (list[i] == NULL) { + continue; + } + + err = aio_error(list[i]); + if (err == EINPROGRESS) { + pending = 1; + } + } + + if (!pending) { + break; + } + + rv = aio_suspend(list, (int)nent, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "aio_suspend failed: %s", + strerror(errno)); + } +} + +ATF_TC_WITHOUT_HEAD(lio_nowait); +ATF_TC_BODY(lio_nowait, tc) +{ + char path[64]; + int fd, rv; +#define NW_REQS 8 +#define NW_BLKSIZ 8192 + uint8_t *bufs[NW_REQS]; + struct aiocb cbs[NW_REQS]; + struct aiocb *list[NW_REQS]; + off_t off; + size_t i; + + fd = mktemp_file(path, sizeof(path)); + + off = 0; + for (i = 0; i < NW_REQS; i++) { + bufs[i] = malloc(NW_BLKSIZ); + ATF_REQUIRE(bufs[i] != NULL); + + fill_pattern(bufs[i], NW_BLKSIZ, (uint8_t)i); + + memset(&cbs[i], 0, sizeof(cbs[i])); + cbs[i].aio_fildes = fd; + cbs[i].aio_buf = bufs[i]; + cbs[i].aio_nbytes = NW_BLKSIZ; + cbs[i].aio_offset = off; + cbs[i].aio_lio_opcode = LIO_WRITE; + + list[i] = &cbs[i]; + off += (off_t)NW_BLKSIZ; + } + + rv = lio_listio(LIO_NOWAIT, list, (int)NW_REQS, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "lio_listio failed: %s", + strerror(errno)); + + wait_all((const struct aiocb * const *)list, NW_REQS); + + for (i = 0; i < NW_REQS; i++) { + int err; + ssize_t done; + + err = aio_error(&cbs[i]); + ATF_REQUIRE_EQ(0, err); + + done = aio_return(&cbs[i]); + ATF_REQUIRE_EQ(NW_BLKSIZ, done); + + free(bufs[i]); + } + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); +} + +ATF_TC_WITHOUT_HEAD(lio_wait_write_then_read); +ATF_TC_BODY(lio_wait_write_then_read, tc) +{ + char path[64]; + int fd, rv; +#define WWTR_REQS 4 +#define WWTR_BLKSIZ 4096 + + uint8_t *wbufs[WWTR_REQS]; + struct aiocb wcbs[WWTR_REQS]; + struct aiocb *wlist[WWTR_REQS]; + + uint8_t *rbufs[WWTR_REQS]; + struct aiocb rcbs[WWTR_REQS]; + struct aiocb *rlist[WWTR_REQS]; + + size_t i; + off_t off; + + fd = mktemp_file(path, sizeof(path)); + + off = 0; + for (i = 0; i < WWTR_REQS; i++) { + wbufs[i] = malloc(WWTR_BLKSIZ); + ATF_REQUIRE(wbufs[i] != NULL); + + fill_pattern(wbufs[i], WWTR_BLKSIZ, (uint8_t)(0xA0 + i)); + + memset(&wcbs[i], 0, sizeof(wcbs[i])); + wcbs[i].aio_fildes = fd; + wcbs[i].aio_buf = wbufs[i]; + wcbs[i].aio_nbytes = WWTR_BLKSIZ; + wcbs[i].aio_offset = off; + wcbs[i].aio_lio_opcode = LIO_WRITE; + + wlist[i] = &wcbs[i]; + off += WWTR_BLKSIZ; + } + + rv = lio_listio(LIO_WAIT, wlist, (int)WWTR_REQS, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "lio_listio write failed: %s", + strerror(errno)); + + for (i = 0; i < WWTR_REQS; i++) { + int err; + ssize_t done; + + err = aio_error(&wcbs[i]); + ATF_REQUIRE_EQ(0, err); + + done = aio_return(&wcbs[i]); + ATF_REQUIRE_EQ(WWTR_BLKSIZ, done); + } + + for (i = 0; i < WWTR_REQS; i++) { + rbufs[i] = calloc(1, WWTR_BLKSIZ); + ATF_REQUIRE(rbufs[i] != NULL); + + memset(&rcbs[i], 0, sizeof(rcbs[i])); + rcbs[i].aio_fildes = fd; + rcbs[i].aio_buf = rbufs[i]; + rcbs[i].aio_nbytes = WWTR_BLKSIZ; + rcbs[i].aio_offset = (off_t)i * WWTR_BLKSIZ; + rcbs[i].aio_lio_opcode = LIO_READ; + + rlist[i] = &rcbs[i]; + } + + rv = lio_listio(LIO_NOWAIT, rlist, WWTR_REQS, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "lio_listio read failed: %s", + strerror(errno)); + + wait_all((const struct aiocb * const *)rlist, WWTR_REQS); + + for (i = 0; i < WWTR_REQS; i++) { + int err; + ssize_t done; + + err = aio_error(&rcbs[i]); + ATF_REQUIRE_EQ(0, err); + + done = aio_return(&rcbs[i]); + ATF_REQUIRE_EQ(WWTR_BLKSIZ, done); + + ATF_REQUIRE_EQ(0, memcmp(wbufs[i], rbufs[i], WWTR_BLKSIZ)); + + free(wbufs[i]); + free(rbufs[i]); + } + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, lio_nowait); + ATF_TP_ADD_TC(tp, lio_wait_write_then_read); + + return atf_no_error(); +} diff --git a/lib/libc/sys/t_aio_rw.c b/lib/libc/sys/t_aio_rw.c new file mode 100644 index 000000000000..e7a5b4fa67d1 --- /dev/null +++ b/lib/libc/sys/t_aio_rw.c @@ -0,0 +1,167 @@ +/* $NetBSD: t_aio_rw.c,v 1.1 2025/10/10 15:53:55 christos Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <atf-c.h> + +#include <aio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +static int mktemp_file(char *, size_t); +static void fill_pattern(uint8_t *, size_t, uint8_t); +static void wait_all(const struct aiocb * const [], size_t); + +static int +mktemp_file(char *path, size_t pathlen) +{ + int fd, n; + + n = snprintf(path, pathlen, "t_aio_rw.XXXXXX"); + ATF_REQUIRE(n > 0 && (size_t)n < pathlen); + + fd = mkstemp(path); + ATF_REQUIRE(fd >= 0); + + return fd; +} + +static void +fill_pattern(uint8_t *buf, size_t len, uint8_t seed) +{ + size_t i; + + for (i = 0; i < len; i++) { + buf[i] = (uint8_t)(seed + (i & 0xff)); + } +} + +static void +wait_all(const struct aiocb * const list[], size_t nent) +{ + size_t i; + int pending, rv, error; + + for (;;) { + pending = 0; + + for (i = 0; i < nent; i++) { + if (list[i] == NULL) { + continue; + } + + error = aio_error(list[i]); + if (error == EINPROGRESS) { + pending = 1; + } + } + + if (!pending) { + break; + } + + rv = aio_suspend(list, (int)nent, NULL); + ATF_REQUIRE_EQ_MSG(0, rv, "aio_suspend failed: %s", + strerror(errno)); + } +} + +/* + * write_then_read_back + * Write a block then read it back asynchronously and compare. + */ +ATF_TC_WITHOUT_HEAD(write_then_read_back); +ATF_TC_BODY(write_then_read_back, tc) +{ + char path[64]; + int fd, rv; + const size_t blksz = 0x2000; + uint8_t *wbuf, *rbuf; + struct aiocb wcb, rcb; + const struct aiocb *wlist[1], *rlist[1]; + + fd = mktemp_file(path, sizeof(path)); + + wbuf = malloc(blksz); + rbuf = calloc(1, blksz); + ATF_REQUIRE(wbuf != NULL && rbuf != NULL); + + fill_pattern(wbuf, blksz, 0xA0); + + memset(&wcb, 0, sizeof(wcb)); + wcb.aio_fildes = fd; + wcb.aio_buf = wbuf; + wcb.aio_nbytes = blksz; + wcb.aio_offset = 0; + + rv = aio_write(&wcb); + ATF_REQUIRE_EQ(0, rv); + wlist[0] = &wcb; + wait_all(wlist, 1); + + ATF_REQUIRE_EQ(0, aio_error(&wcb)); + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&wcb)); + + memset(&rcb, 0, sizeof(rcb)); + rcb.aio_fildes = fd; + rcb.aio_buf = rbuf; + rcb.aio_nbytes = blksz; + rcb.aio_offset = 0; + + rv = aio_read(&rcb); + ATF_REQUIRE_EQ(0, rv); + rlist[0] = &rcb; + wait_all(rlist, 1); + + ATF_REQUIRE_EQ(0, aio_error(&rcb)); + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&rcb)); + ATF_REQUIRE_EQ(0, memcmp(wbuf, rbuf, blksz)); + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); + + free(wbuf); + free(rbuf); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, write_then_read_back); + return atf_no_error(); +} diff --git a/lib/libc/sys/t_aio_suspend.c b/lib/libc/sys/t_aio_suspend.c new file mode 100644 index 000000000000..96b0dc2cf6d0 --- /dev/null +++ b/lib/libc/sys/t_aio_suspend.c @@ -0,0 +1,170 @@ +/* $NetBSD: t_aio_suspend.c,v 1.1 2025/10/10 15:53:55 christos Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <atf-c.h> + +#include <aio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> + +static int mktemp_file(char *, size_t); +static void fill_pattern(uint8_t *, size_t, uint8_t); +static void wait_cb(struct aiocb *); + +static int +mktemp_file(char *path, size_t pathlen) +{ + int fd, n; + + n = snprintf(path, pathlen, "t_aio_suspend.XXXXXX"); + ATF_REQUIRE(n > 0 && (size_t)n < pathlen); + + fd = mkstemp(path); + ATF_REQUIRE(fd >= 0); + + return fd; +} + +static void +fill_pattern(uint8_t *buf, size_t len, uint8_t seed) +{ + size_t i; + + for (i = 0; i < len; i++) { + buf[i] = (uint8_t)(seed + (i & 0xff)); + } +} + +static void +wait_cb(struct aiocb *cb) +{ + const struct aiocb *one[1]; + int rv; + + one[0] = cb; + while (aio_error(cb) == EINPROGRESS) { + rv = aio_suspend(one, 1, NULL); + ATF_REQUIRE_EQ(0, rv); + } + if (aio_error(cb) == 0) { + aio_return(cb); + } +} + +ATF_TC_WITHOUT_HEAD(suspend_any); +ATF_TC_BODY(suspend_any, tc) +{ + char path[64]; + int fd, rv; + const size_t blksz = 4096; + uint8_t *buf0, *buf1; + struct aiocb cb0, cb1; + const struct aiocb *list[2]; + int done; + + fd = mktemp_file(path, sizeof(path)); + + buf0 = malloc(blksz); + buf1 = malloc(blksz); + ATF_REQUIRE(buf0 != NULL && buf1 != NULL); + fill_pattern(buf0, blksz, 0x20); + fill_pattern(buf1, blksz, 0x40); + + memset(&cb0, 0, sizeof(cb0)); + cb0.aio_fildes = fd; + cb0.aio_buf = buf0; + cb0.aio_nbytes = blksz; + cb0.aio_offset = 0; + + memset(&cb1, 0, sizeof(cb1)); + cb1.aio_fildes = fd; + cb1.aio_buf = buf1; + cb1.aio_nbytes = blksz; + cb1.aio_offset = blksz; + + ATF_REQUIRE_EQ(0, aio_write(&cb0)); + ATF_REQUIRE_EQ(0, aio_write(&cb1)); + + list[0] = &cb0; + list[1] = &cb1; + + rv = aio_suspend(list, 2, NULL); + ATF_REQUIRE_EQ(0, rv); + + done = 0; + if (aio_error(&cb0) != EINPROGRESS) { + done++; + if (aio_error(&cb0) == 0) { + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb0)); + } else { + ATF_REQUIRE_EQ(ECANCELED, aio_error(&cb0)); + ATF_REQUIRE_EQ(-1, aio_return(&cb0)); + } + } + if (aio_error(&cb1) != EINPROGRESS) { + done++; + if (aio_error(&cb1) == 0) { + ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb1)); + } else { + ATF_REQUIRE_EQ(ECANCELED, aio_error(&cb1)); + ATF_REQUIRE_EQ(-1, aio_return(&cb1)); + } + } + ATF_REQUIRE(done >= 1); + + if (aio_error(&cb0) == EINPROGRESS) { + wait_cb(&cb0); + } + if (aio_error(&cb1) == EINPROGRESS) { + wait_cb(&cb1); + } + + rv = close(fd); + ATF_REQUIRE_EQ(0, rv); + rv = unlink(path); + ATF_REQUIRE_EQ(0, rv); + + free(buf0); + free(buf1); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, suspend_any); + return atf_no_error(); +} diff --git a/lib/libc/sys/t_ptrace_kill.c b/lib/libc/sys/t_ptrace_kill.c new file mode 100644 index 000000000000..fdd6298c2a8a --- /dev/null +++ b/lib/libc/sys/t_ptrace_kill.c @@ -0,0 +1,131 @@ +/* $NetBSD: t_ptrace_kill.c,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_ptrace_kill.c,v 1.2 2025/05/02 02:24:32 riastradh Exp $"); + +#include <sys/types.h> +#include <sys/ptrace.h> +#include <sys/wait.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <errno.h> +#include <err.h> +#include <atf-c.h> + +#define SYSCALL(a, b) ATF_REQUIRE_EQ_MSG(a, b, "%s got %s", #a, strerror(errno)) + +ATF_TC(pt_kill); +ATF_TC_HEAD(pt_kill, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test PT_KILL of a PT_STOP'ed process"); +} + +static void +child(int *fdto, int *fdfrom) +{ + char p = '2', q; + printf("%d: born\n", getpid()); + write(fdfrom[1], &p, 1); + read(fdto[0], &q, 1); + printf("%d: seppuku %c\n", getpid(), q); + write(fdfrom[1], &p, 1); + read(fdto[0], &q, 1); +// *(int *)1 = 0; +// kill(getpid(), SIGSEGV); +// kill(getpid(), SIGSTOP); + for (;;) + sleep(1); + +} + +static void * +waitthread(void *pidp) +{ + int status = 0; + pid_t rpid, pid; + + pid = *(pid_t *)pidp; + printf("waiting for %d\n", pid); + while ((rpid = waitpid(pid, &status, 0)) != pid) { + printf("waitpid %d = %d status = %#x", pid, rpid, status); + } + printf("done waitpid %d = %d status = %#x", pid, rpid, status); + return NULL; +} + +ATF_TC_BODY(pt_kill, tc) +{ + pid_t pid; + int fdto[2], fdfrom[2]; + char p = '1', q; + int status; + pthread_t thread; + + SYSCALL(pipe(fdto), 0); + SYSCALL(pipe(fdfrom), 0); + switch (pid = fork()) { + case 0: + child(fdto, fdfrom); + break; + case -1: + err(EXIT_FAILURE, "fork failed"); + default: + SYSCALL(pthread_create(&thread, NULL, waitthread, &pid), 0); + sleep(1); // XXX: too lazy to sync properly + SYSCALL(read(fdfrom[0], &q, 1), 1); + printf("%d: read %c\n", pid, q); + SYSCALL(ptrace(PT_ATTACH, pid, NULL, 0), 0); + printf("%d: attached\n", pid); + SYSCALL(write(fdto[1], &p, 1), 1); + waitpid(pid, NULL, WNOHANG); + printf("%d: sent\n", pid); + SYSCALL(ptrace(PT_CONTINUE, pid, (void *)1, 0), 0); + SYSCALL(read(fdfrom[0], &p, 1), 1); + printf("%d: received\n", pid); + SYSCALL(ptrace(PT_STOP, pid, NULL, 0), 0); + SYSCALL(ptrace(PT_KILL, pid, NULL, 0), 0); + SYSCALL(waitpid(pid, &status, 0), pid); + ATF_REQUIRE(status == 9); + break; + } +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, pt_kill); + + return atf_no_error(); +} diff --git a/lib/libexecinfo/t_backtrace_sandbox.c b/lib/libexecinfo/t_backtrace_sandbox.c new file mode 100644 index 000000000000..51d650c3424a --- /dev/null +++ b/lib/libexecinfo/t_backtrace_sandbox.c @@ -0,0 +1,88 @@ +/* $NetBSD: t_backtrace_sandbox.c,v 1.3 2025/01/30 16:13:51 christos Exp $ */ + +/*- + * Copyright (c) 2025 Kyle Evans <kevans@FreeBSD.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_backtrace_sandbox.c,v 1.3 2025/01/30 16:13:51 christos Exp $"); + +#include <sys/param.h> +#include <sys/wait.h> +#ifdef __FreeBSD__ +#include <sys/capsicum.h> +#define __arraycount(a) nitems(a) +#endif + +#include <execinfo.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include <atf-c.h> + +#define BT_FUNCTIONS 10 + +ATF_TC(backtrace_sandbox); +ATF_TC_HEAD(backtrace_sandbox, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test backtrace_sandbox_init(3) in sandbox"); +#ifndef __FreeBSD__ + atf_tc_set_md_var(tc, "require.user", "root"); +#endif +} + +ATF_TC_BODY(backtrace_sandbox, tc) +{ + void *addr[BT_FUNCTIONS]; + char **syms; + size_t frames; + pid_t pid; + int status; + + frames = backtrace(addr, __arraycount(addr)); + ATF_REQUIRE(frames > 0); + + syms = backtrace_symbols_fmt(addr, frames, "%n"); + ATF_REQUIRE(strcmp(syms[0], "atfu_backtrace_sandbox_body") == 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + backtrace_sandbox_init(); +#ifdef __FreeBSD__ + cap_enter(); +#else + if (chroot("/tmp") != 0) + _exit(EXIT_FAILURE); +#endif + + syms = backtrace_symbols_fmt(addr, frames, "%n"); + if (strcmp(syms[0], "atfu_backtrace_sandbox_body") != 0) + _exit(EXIT_FAILURE); + + backtrace_sandbox_fini(); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&status); + + if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_SUCCESS) + atf_tc_fail("resolving symbols in chroot failed"); + +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, backtrace_sandbox); + + return atf_no_error(); +} diff --git a/lib/libm/t_errhandling.c b/lib/libm/t_errhandling.c new file mode 100644 index 000000000000..7c95afe22121 --- /dev/null +++ b/lib/libm/t_errhandling.c @@ -0,0 +1,97 @@ +/* $NetBSD: t_errhandling.c,v 1.3 2024/09/10 17:36:12 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define __TEST_FENV + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_errhandling.c,v 1.3 2024/09/10 17:36:12 riastradh Exp $"); + +#include <atf-c.h> +#include <errno.h> +#include <fenv.h> +#include <math.h> + +ATF_TC(log); +ATF_TC_HEAD(log, tc) +{ + atf_tc_set_md_var(tc, "descr", "log of invalid"); +} +ATF_TC_BODY(log, tc) +{ + static const struct { +#ifdef __HAVE_FENV + double x; + int e; +#define C(x, e) { x, e } +#else + double x; +#define C(x, e) { x } +#endif + } cases[] = { + C(0, FE_DIVBYZERO), + C(-0., FE_DIVBYZERO), + C(-1, FE_INVALID), + C(-HUGE_VAL, FE_INVALID), + }; + volatile double y; +#ifdef __HAVE_FENV + int except; +#endif + unsigned i; + + for (i = 0; i < __arraycount(cases); i++) { + const volatile double x = cases[i].x; + +#ifdef __HAVE_FENV + feclearexcept(FE_ALL_EXCEPT); +#endif + errno = 0; + y = log(x); + if (math_errhandling & MATH_ERREXCEPT) { +#ifdef __HAVE_FENV + ATF_CHECK_MSG(((except = fetestexcept(FE_ALL_EXCEPT)) & + cases[i].e) != 0, + "expected=0x%x actual=0x%x", cases[i].e, except); +#else + atf_tc_fail_nonfatal("MATH_ERREXCEPT but no fenv.h"); +#endif + } + if (math_errhandling & MATH_ERRNO) + ATF_CHECK_EQ_MSG(errno, EDOM, "errno=%d", errno); + } + + __USE(y); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, log); + + return atf_no_error(); +} diff --git a/lib/libm/t_next.c b/lib/libm/t_next.c new file mode 100644 index 000000000000..22363f92daf2 --- /dev/null +++ b/lib/libm/t_next.c @@ -0,0 +1,887 @@ +/* $NetBSD: t_next.c,v 1.8 2025/04/07 01:31:18 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_next.c,v 1.8 2025/04/07 01:31:18 riastradh Exp $"); + +#include <atf-c.h> +#include <float.h> +#include <math.h> + +#ifdef __vax__ /* XXX PR 57881: vax libm is missing various symbols */ + +ATF_TC(vaxafter); +ATF_TC_HEAD(vaxafter, tc) +{ + + atf_tc_set_md_var(tc, "descr", "vax nextafter/nexttoward reminder"); +} +ATF_TC_BODY(vaxafter, tc) +{ + + atf_tc_expect_fail("PR 57881: vax libm is missing various symbols"); + atf_tc_fail("missing nextafter{,f,l} and nexttoward{,f,l} on vax"); +} + +#else /* !__vax__ */ + +#define CHECK(i, next, x, d, y) do \ +{ \ + volatile __typeof__(x) check_x = (x); \ + volatile __typeof__(d) check_d = (d); \ + volatile __typeof__(y) check_y = (y); \ + const volatile __typeof__(y) check_tmp = (next)(check_x, check_d); \ + ATF_CHECK_MSG(check_tmp == check_y, \ + "[%u] %s(%s=%La=%Lg, %s=%La=%Lg)=%La=%Lg != %s=%La=%Lg", \ + (i), #next, \ + #x, (long double)check_x, (long double)check_x, \ + #d, (long double)check_d, (long double)check_d, \ + (long double)check_tmp, (long double)check_tmp, \ + #y, (long double)check_y, (long double)check_y); \ +} while (0) + +/* + * check(x, n) + * + * x[0], x[1], ..., x[n - 1] are consecutive double floating-point + * numbers. Verify nextafter and nexttoward follow exactly this + * sequence, forward and back, and in negative. + */ +static void +check(const double *x, unsigned n) +{ + unsigned i; + + for (i = 0; i < n; i++) { + CHECK(i, nextafter, x[i], x[i], x[i]); + CHECK(i, nexttoward, x[i], x[i], x[i]); + CHECK(i, nextafter, -x[i], -x[i], -x[i]); + CHECK(i, nexttoward, -x[i], -x[i], -x[i]); + } + + for (i = 0; i < n - 1; i++) { + ATF_REQUIRE_MSG(x[i] < x[i + 1], "i=%u", i); + + if (isnormal(x[i])) { + CHECK(i, nexttoward, x[i], x[i]*(1 + LDBL_EPSILON), + x[i + 1]); + } + + CHECK(i, nextafter, x[i], x[i + 1], x[i + 1]); + CHECK(i, nexttoward, x[i], x[i + 1], x[i + 1]); + CHECK(i, nextafter, x[i], x[n - 1], x[i + 1]); + CHECK(i, nexttoward, x[i], x[n - 1], x[i + 1]); + CHECK(i, nextafter, x[i], INFINITY, x[i + 1]); + CHECK(i, nexttoward, x[i], INFINITY, x[i + 1]); + + CHECK(i, nextafter, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nexttoward, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nextafter, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nexttoward, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nextafter, -x[i], -INFINITY, -x[i + 1]); + CHECK(i, nexttoward, -x[i], -INFINITY, -x[i + 1]); + } + + for (i = n; i --> 1;) { + ATF_REQUIRE_MSG(x[i - 1] < x[i], "i=%u", i); + +#ifdef __HAVE_LONG_DOUBLE + if (isnormal(x[i])) { + CHECK(i, nexttoward, x[i], x[i]*(1 - LDBL_EPSILON/2), + x[i - 1]); + } +#endif + + CHECK(i, nextafter, x[i], x[i - 1], x[i - 1]); + CHECK(i, nexttoward, x[i], x[i - 1], x[i - 1]); + CHECK(i, nextafter, x[i], x[0], x[i - 1]); + CHECK(i, nexttoward, x[i], x[0], x[i - 1]); + CHECK(i, nextafter, x[i], +0., x[i - 1]); + CHECK(i, nexttoward, x[i], +0., x[i - 1]); + CHECK(i, nextafter, x[i], -0., x[i - 1]); + CHECK(i, nexttoward, x[i], -0., x[i - 1]); + CHECK(i, nextafter, x[i], -x[0], x[i - 1]); + CHECK(i, nexttoward, x[i], -x[0], x[i - 1]); + CHECK(i, nextafter, x[i], -x[i], x[i - 1]); + CHECK(i, nexttoward, x[i], -x[i], x[i - 1]); + CHECK(i, nextafter, x[i], -INFINITY, x[i - 1]); + CHECK(i, nexttoward, x[i], -INFINITY, x[i - 1]); + + CHECK(i, nextafter, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nexttoward, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nextafter, -x[i], -x[0], -x[i - 1]); + CHECK(i, nexttoward, -x[i], -x[0], -x[i - 1]); + CHECK(i, nextafter, -x[i], -0., -x[i - 1]); + CHECK(i, nexttoward, -x[i], -0., -x[i - 1]); + CHECK(i, nextafter, -x[i], +0., -x[i - 1]); + CHECK(i, nexttoward, -x[i], +0., -x[i - 1]); + CHECK(i, nextafter, -x[i], x[0], -x[i - 1]); + CHECK(i, nexttoward, -x[i], x[0], -x[i - 1]); + CHECK(i, nextafter, -x[i], INFINITY, -x[i - 1]); + CHECK(i, nexttoward, -x[i], INFINITY, -x[i - 1]); + } +} + +/* + * checkf(x, n) + * + * x[0], x[1], ..., x[n - 1] are consecutive single floating-point + * numbers. Verify nextafterf and nexttowardf follow exactly this + * sequence, forward and back, and in negative. + */ +static void +checkf(const float *x, unsigned n) +{ + unsigned i; + + for (i = 0; i < n; i++) { + CHECK(i, nextafterf, x[i], x[i], x[i]); + CHECK(i, nexttowardf, x[i], x[i], x[i]); + CHECK(i, nextafterf, -x[i], -x[i], -x[i]); + CHECK(i, nexttowardf, -x[i], -x[i], -x[i]); + } + + for (i = 0; i < n - 1; i++) { + ATF_REQUIRE_MSG(x[i] < x[i + 1], "i=%u", i); + + if (isnormal(x[i])) { + CHECK(i, nexttowardf, x[i], x[i]*(1 + LDBL_EPSILON), + x[i + 1]); + } + + CHECK(i, nextafterf, x[i], x[i + 1], x[i + 1]); + CHECK(i, nexttowardf, x[i], x[i + 1], x[i + 1]); + CHECK(i, nextafterf, x[i], x[n - 1], x[i + 1]); + CHECK(i, nexttowardf, x[i], x[n - 1], x[i + 1]); + CHECK(i, nextafterf, x[i], INFINITY, x[i + 1]); + CHECK(i, nexttowardf, x[i], INFINITY, x[i + 1]); + + CHECK(i, nextafterf, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nexttowardf, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nextafterf, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nexttowardf, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nextafterf, -x[i], -INFINITY, -x[i + 1]); + CHECK(i, nexttowardf, -x[i], -INFINITY, -x[i + 1]); + } + + for (i = n; i --> 1;) { + ATF_REQUIRE_MSG(x[i - 1] < x[i], "i=%u", i); + + if (isnormal(x[i])) { + CHECK(i, nexttowardf, x[i], x[i]*(1 - LDBL_EPSILON/2), + x[i - 1]); + } + + CHECK(i, nextafterf, x[i], x[i - 1], x[i - 1]); + CHECK(i, nexttowardf, x[i], x[i - 1], x[i - 1]); + CHECK(i, nextafterf, x[i], x[0], x[i - 1]); + CHECK(i, nexttowardf, x[i], x[0], x[i - 1]); + CHECK(i, nextafterf, x[i], +0., x[i - 1]); + CHECK(i, nexttowardf, x[i], +0., x[i - 1]); + CHECK(i, nextafterf, x[i], -0., x[i - 1]); + CHECK(i, nexttowardf, x[i], -0., x[i - 1]); + CHECK(i, nextafterf, x[i], -x[0], x[i - 1]); + CHECK(i, nexttowardf, x[i], -x[0], x[i - 1]); + CHECK(i, nextafterf, x[i], -x[i], x[i - 1]); + CHECK(i, nexttowardf, x[i], -x[i], x[i - 1]); + CHECK(i, nextafterf, x[i], -INFINITY, x[i - 1]); + CHECK(i, nexttowardf, x[i], -INFINITY, x[i - 1]); + + CHECK(i, nextafterf, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nexttowardf, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nextafterf, -x[i], -x[0], -x[i - 1]); + CHECK(i, nexttowardf, -x[i], -x[0], -x[i - 1]); + CHECK(i, nextafterf, -x[i], -0., -x[i - 1]); + CHECK(i, nexttowardf, -x[i], -0., -x[i - 1]); + CHECK(i, nextafterf, -x[i], +0., -x[i - 1]); + CHECK(i, nexttowardf, -x[i], +0., -x[i - 1]); + CHECK(i, nextafterf, -x[i], x[0], -x[i - 1]); + CHECK(i, nexttowardf, -x[i], x[0], -x[i - 1]); + CHECK(i, nextafterf, -x[i], INFINITY, -x[i - 1]); + CHECK(i, nexttowardf, -x[i], INFINITY, -x[i - 1]); + } +} + +/* + * checkl(x, n) + * + * x[0], x[1], ..., x[n - 1] are consecutive long double + * floating-point numbers. Verify nextafterl and nexttowardl + * follow exactly this sequence, forward and back, and in + * negative. + */ +static void +checkl(const long double *x, unsigned n) +{ + unsigned i; + + for (i = 0; i < n; i++) { + CHECK(i, nextafterl, x[i], x[i], x[i]); + CHECK(i, nexttowardl, x[i], x[i], x[i]); + CHECK(i, nextafterl, -x[i], -x[i], -x[i]); + CHECK(i, nexttowardl, -x[i], -x[i], -x[i]); + } + + for (i = 0; i < n - 1; i++) { + ATF_REQUIRE_MSG(x[i] < x[i + 1], "i=%u", i); + + CHECK(i, nextafterl, x[i], x[i + 1], x[i + 1]); + CHECK(i, nexttowardl, x[i], x[i + 1], x[i + 1]); + CHECK(i, nextafterl, x[i], x[n - 1], x[i + 1]); + CHECK(i, nexttowardl, x[i], x[n - 1], x[i + 1]); + CHECK(i, nextafterl, x[i], INFINITY, x[i + 1]); + CHECK(i, nexttowardl, x[i], INFINITY, x[i + 1]); + + CHECK(i, nextafterl, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nexttowardl, -x[i], -x[i + 1], -x[i + 1]); + CHECK(i, nextafterl, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nexttowardl, -x[i], -x[n - 1], -x[i + 1]); + CHECK(i, nextafterl, -x[i], -INFINITY, -x[i + 1]); + CHECK(i, nexttowardl, -x[i], -INFINITY, -x[i + 1]); + } + + for (i = n; i --> 1;) { + ATF_REQUIRE_MSG(x[i - 1] < x[i], "i=%u", i); + + CHECK(i, nextafterl, x[i], x[i - 1], x[i - 1]); + CHECK(i, nexttowardl, x[i], x[i - 1], x[i - 1]); + CHECK(i, nextafterl, x[i], x[0], x[i - 1]); + CHECK(i, nexttowardl, x[i], x[0], x[i - 1]); + CHECK(i, nextafterl, x[i], +0., x[i - 1]); + CHECK(i, nexttowardl, x[i], +0., x[i - 1]); + CHECK(i, nextafterl, x[i], -0., x[i - 1]); + CHECK(i, nexttowardl, x[i], -0., x[i - 1]); + CHECK(i, nextafterl, x[i], -x[0], x[i - 1]); + CHECK(i, nexttowardl, x[i], -x[0], x[i - 1]); + CHECK(i, nextafterl, x[i], -x[i], x[i - 1]); + CHECK(i, nexttowardl, x[i], -x[i], x[i - 1]); + CHECK(i, nextafterl, x[i], -INFINITY, x[i - 1]); + CHECK(i, nexttowardl, x[i], -INFINITY, x[i - 1]); + + CHECK(i, nextafterl, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nexttowardl, -x[i], -x[i - 1], -x[i - 1]); + CHECK(i, nextafterl, -x[i], -x[0], -x[i - 1]); + CHECK(i, nexttowardl, -x[i], -x[0], -x[i - 1]); + CHECK(i, nextafterl, -x[i], -0., -x[i - 1]); + CHECK(i, nexttowardl, -x[i], -0., -x[i - 1]); + CHECK(i, nextafterl, -x[i], +0., -x[i - 1]); + CHECK(i, nexttowardl, -x[i], +0., -x[i - 1]); + CHECK(i, nextafterl, -x[i], x[0], -x[i - 1]); + CHECK(i, nexttowardl, -x[i], x[0], -x[i - 1]); + CHECK(i, nextafterl, -x[i], INFINITY, -x[i - 1]); + CHECK(i, nexttowardl, -x[i], INFINITY, -x[i - 1]); + } +} + +ATF_TC(next_nan); +ATF_TC_HEAD(next_nan, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward on NaN"); +} +ATF_TC_BODY(next_nan, tc) +{ +#ifdef NAN + /* XXX verify the NaN is quiet */ + ATF_CHECK(isnan(nextafter(NAN, 0))); + ATF_CHECK(isnan(nexttoward(NAN, 0))); + ATF_CHECK(isnan(nextafter(0, NAN))); + ATF_CHECK(isnan(nexttoward(0, NAN))); +#else + atf_tc_skip("no NaNs on this architecture"); +#endif +} + +ATF_TC(next_signed_0); +ATF_TC_HEAD(next_signed_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward on signed 0"); +} +ATF_TC_BODY(next_signed_0, tc) +{ + volatile double z_pos = +0.; + volatile double z_neg = -0.; +#if __DBL_HAS_DENORM__ + volatile double m = __DBL_DENORM_MIN__; +#else + volatile double m = DBL_MIN; +#endif + + if (signbit(z_pos) == signbit(z_neg)) + atf_tc_skip("no signed zeroes on this architecture"); + + /* + * `nextUp(x) is the least floating-point number in the format + * of x that compares greater than x. [...] nextDown(x) is + * -nextUp(-x).' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + * + * Verify that nextafter and nexttoward, which implement the + * nextUp and nextDown operations, obey this rule and don't + * send -0 to +0 or +0 to -0, respectively. + */ + + CHECK(0, nextafter, z_neg, +INFINITY, m); + CHECK(1, nexttoward, z_neg, +INFINITY, m); + CHECK(2, nextafter, z_pos, +INFINITY, m); + CHECK(3, nexttoward, z_pos, +INFINITY, m); + + CHECK(4, nextafter, z_pos, -INFINITY, -m); + CHECK(5, nexttoward, z_pos, -INFINITY, -m); + CHECK(6, nextafter, z_neg, -INFINITY, -m); + CHECK(7, nexttoward, z_neg, -INFINITY, -m); + + /* + * `If x is the negative number of least magnitude in x's + * format, nextUp(x) is -0.' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + * + * Verify that nextafter and nexttoward return the correctly + * signed zero. + */ + CHECK(8, nextafter, -m, +INFINITY, 0); + CHECK(9, nexttoward, -m, +INFINITY, 0); + ATF_CHECK(signbit(nextafter(-m, +INFINITY)) != 0); + CHECK(10, nextafter, m, -INFINITY, 0); + CHECK(11, nexttoward, m, -INFINITY, 0); + ATF_CHECK(signbit(nextafter(m, -INFINITY)) == 0); +} + +ATF_TC(next_near_0); +ATF_TC_HEAD(next_near_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward near 0"); +} +ATF_TC_BODY(next_near_0, tc) +{ + static const double x[] = { + [0] = 0, +#if __DBL_HAS_DENORM__ + [1] = __DBL_DENORM_MIN__, + [2] = 2*__DBL_DENORM_MIN__, + [3] = 3*__DBL_DENORM_MIN__, + [4] = 4*__DBL_DENORM_MIN__, +#else + [1] = DBL_MIN, + [2] = DBL_MIN*(1 + DBL_EPSILON), + [3] = DBL_MIN*(1 + 2*DBL_EPSILON), + [4] = DBL_MIN*(1 + 3*DBL_EPSILON), +#endif + }; + + check(x, __arraycount(x)); +} + +ATF_TC(next_near_sub_normal); +ATF_TC_HEAD(next_near_sub_normal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "nextafter/nexttoward near the subnormal/normal boundary"); +} +ATF_TC_BODY(next_near_sub_normal, tc) +{ +#if __DBL_HAS_DENORM__ + static const double x[] = { + [0] = DBL_MIN - 3*__DBL_DENORM_MIN__, + [1] = DBL_MIN - 2*__DBL_DENORM_MIN__, + [2] = DBL_MIN - __DBL_DENORM_MIN__, + [3] = DBL_MIN, + [4] = DBL_MIN + __DBL_DENORM_MIN__, + [5] = DBL_MIN + 2*__DBL_DENORM_MIN__, + [6] = DBL_MIN + 3*__DBL_DENORM_MIN__, + }; + + check(x, __arraycount(x)); +#else /* !__DBL_HAS_DENORM__ */ + atf_tc_skip("no subnormals on this architecture"); +#endif /* !__DBL_HAS_DENORM__ */ +} + +ATF_TC(next_near_1); +ATF_TC_HEAD(next_near_1, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward near 1"); +} +ATF_TC_BODY(next_near_1, tc) +{ + static const double x[] = { + [0] = 1 - 3*DBL_EPSILON/2, + [1] = 1 - 2*DBL_EPSILON/2, + [2] = 1 - DBL_EPSILON/2, + [3] = 1, + [4] = 1 + DBL_EPSILON, + [5] = 1 + 2*DBL_EPSILON, + [6] = 1 + 3*DBL_EPSILON, + }; + + check(x, __arraycount(x)); +} + +ATF_TC(next_near_1_5); +ATF_TC_HEAD(next_near_1_5, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward near 1.5"); +} +ATF_TC_BODY(next_near_1_5, tc) +{ + static const double x[] = { + [0] = 1.5 - 3*DBL_EPSILON, + [1] = 1.5 - 2*DBL_EPSILON, + [2] = 1.5 - DBL_EPSILON, + [3] = 1.5, + [4] = 1.5 + DBL_EPSILON, + [5] = 1.5 + 2*DBL_EPSILON, + [6] = 1.5 + 3*DBL_EPSILON, + }; + + check(x, __arraycount(x)); +} + +ATF_TC(next_near_infinity); +ATF_TC_HEAD(next_near_infinity, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafter/nexttoward near infinity"); +} +ATF_TC_BODY(next_near_infinity, tc) +{ + static const double x[] = { + [0] = DBL_MAX, + [1] = INFINITY, + }; + volatile double t; + + if (!isinf(INFINITY)) + atf_tc_skip("no infinities on this architecture"); + + check(x, __arraycount(x)); + + ATF_CHECK_EQ_MSG((t = nextafter(INFINITY, INFINITY)), INFINITY, + "t=%a=%g", t, t); + ATF_CHECK_EQ_MSG((t = nextafter(-INFINITY, -INFINITY)), -INFINITY, + "t=%a=%g", t, t); +} + +ATF_TC(nextf_nan); +ATF_TC_HEAD(nextf_nan, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf on NaN"); +} +ATF_TC_BODY(nextf_nan, tc) +{ +#ifdef NAN + /* XXX verify the NaN is quiet */ + ATF_CHECK(isnan(nextafterf(NAN, 0))); + ATF_CHECK(isnan(nexttowardf(NAN, 0))); + ATF_CHECK(isnan(nextafterf(0, NAN))); + ATF_CHECK(isnan(nexttowardf(0, NAN))); +#else + atf_tc_skip("no NaNs on this architecture"); +#endif +} + +ATF_TC(nextf_signed_0); +ATF_TC_HEAD(nextf_signed_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf on signed 0"); +} +ATF_TC_BODY(nextf_signed_0, tc) +{ + volatile float z_pos = +0.; + volatile float z_neg = -0.; +#if __FLT_HAS_DENORM__ + volatile float m = __FLT_DENORM_MIN__; +#else + volatile float m = FLT_MIN; +#endif + + if (signbit(z_pos) == signbit(z_neg)) + atf_tc_skip("no signed zeroes on this architecture"); + + /* + * `nextUp(x) is the least floating-point number in the format + * of x that compares greater than x. [...] nextDown(x) is + * -nextUp(-x).' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + * + * Verify that nextafterf and nexttowardf, which implement the + * nextUp and nextDown operations, obey this rule and don't + * send -0 to +0 or +0 to -0, respectively. + */ + + CHECK(0, nextafterf, z_neg, +INFINITY, m); + CHECK(1, nexttowardf, z_neg, +INFINITY, m); + CHECK(2, nextafterf, z_pos, +INFINITY, m); + CHECK(3, nexttowardf, z_pos, +INFINITY, m); + + CHECK(4, nextafterf, z_pos, -INFINITY, -m); + CHECK(5, nexttowardf, z_pos, -INFINITY, -m); + CHECK(6, nextafterf, z_neg, -INFINITY, -m); + CHECK(7, nexttowardf, z_neg, -INFINITY, -m); + + /* + * `If x is the negative number of least magnitude in x's + * format, nextUp(x) is -0.' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + */ + CHECK(8, nextafterf, -m, +INFINITY, 0); + CHECK(9, nexttowardf, -m, +INFINITY, 0); + ATF_CHECK(signbit(nextafterf(-m, +INFINITY)) != 0); + CHECK(10, nextafterf, m, -INFINITY, 0); + CHECK(11, nexttowardf, m, -INFINITY, 0); + ATF_CHECK(signbit(nextafterf(m, -INFINITY)) == 0); +} + +ATF_TC(nextf_near_0); +ATF_TC_HEAD(nextf_near_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf near 0"); +} +ATF_TC_BODY(nextf_near_0, tc) +{ + static const float x[] = { + [0] = 0, +#if __FLT_HAS_DENORM__ + [1] = __FLT_DENORM_MIN__, + [2] = 2*__FLT_DENORM_MIN__, + [3] = 3*__FLT_DENORM_MIN__, + [4] = 4*__FLT_DENORM_MIN__, +#else + [1] = FLT_MIN, + [2] = FLT_MIN*(1 + FLT_EPSILON), + [3] = FLT_MIN*(1 + 2*FLT_EPSILON), + [4] = FLT_MIN*(1 + 3*FLT_EPSILON), +#endif + }; + + checkf(x, __arraycount(x)); +} + +ATF_TC(nextf_near_sub_normal); +ATF_TC_HEAD(nextf_near_sub_normal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "nextafterf/nexttowardf near the subnormal/normal boundary"); +} +ATF_TC_BODY(nextf_near_sub_normal, tc) +{ +#if __FLT_HAS_DENORM__ + static const float x[] = { + [0] = FLT_MIN - 3*__FLT_DENORM_MIN__, + [1] = FLT_MIN - 2*__FLT_DENORM_MIN__, + [2] = FLT_MIN - __FLT_DENORM_MIN__, + [3] = FLT_MIN, + [4] = FLT_MIN + __FLT_DENORM_MIN__, + [5] = FLT_MIN + 2*__FLT_DENORM_MIN__, + [6] = FLT_MIN + 3*__FLT_DENORM_MIN__, + }; + + checkf(x, __arraycount(x)); +#else /* !__FLT_HAS_DENORM__ */ + atf_tc_skip("no subnormals on this architecture"); +#endif /* !__FLT_HAS_DENORM__ */ +} + +ATF_TC(nextf_near_1); +ATF_TC_HEAD(nextf_near_1, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf near 1"); +} +ATF_TC_BODY(nextf_near_1, tc) +{ + static const float x[] = { + [0] = 1 - 3*FLT_EPSILON/2, + [1] = 1 - 2*FLT_EPSILON/2, + [2] = 1 - FLT_EPSILON/2, + [3] = 1, + [4] = 1 + FLT_EPSILON, + [5] = 1 + 2*FLT_EPSILON, + [6] = 1 + 3*FLT_EPSILON, + }; + + checkf(x, __arraycount(x)); +} + +ATF_TC(nextf_near_1_5); +ATF_TC_HEAD(nextf_near_1_5, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf near 1.5"); +} +ATF_TC_BODY(nextf_near_1_5, tc) +{ + static const float x[] = { + [0] = 1.5 - 3*FLT_EPSILON, + [1] = 1.5 - 2*FLT_EPSILON, + [2] = 1.5 - FLT_EPSILON, + [3] = 1.5, + [4] = 1.5 + FLT_EPSILON, + [5] = 1.5 + 2*FLT_EPSILON, + [6] = 1.5 + 3*FLT_EPSILON, + }; + + checkf(x, __arraycount(x)); +} + +ATF_TC(nextf_near_infinity); +ATF_TC_HEAD(nextf_near_infinity, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterf/nexttowardf near infinity"); +} +ATF_TC_BODY(nextf_near_infinity, tc) +{ + static const float x[] = { + [0] = FLT_MAX, + [1] = INFINITY, + }; + volatile float t; + + if (!isinf(INFINITY)) + atf_tc_skip("no infinities on this architecture"); + + checkf(x, __arraycount(x)); + + ATF_CHECK_EQ_MSG((t = nextafterf(INFINITY, INFINITY)), INFINITY, + "t=%a=%g", t, t); + ATF_CHECK_EQ_MSG((t = nextafterf(-INFINITY, -INFINITY)), -INFINITY, + "t=%a=%g", t, t); +} + +ATF_TC(nextl_nan); +ATF_TC_HEAD(nextl_nan, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl on NaN"); +} +ATF_TC_BODY(nextl_nan, tc) +{ +#ifdef NAN + /* XXX verify the NaN is quiet */ + ATF_CHECK(isnan(nextafterl(NAN, 0))); + ATF_CHECK(isnan(nexttowardl(NAN, 0))); + ATF_CHECK(isnan(nextafterl(0, NAN))); + ATF_CHECK(isnan(nexttowardl(0, NAN))); +#else + atf_tc_skip("no NaNs on this architecture"); +#endif +} + +ATF_TC(nextl_signed_0); +ATF_TC_HEAD(nextl_signed_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl on signed 0"); +} +ATF_TC_BODY(nextl_signed_0, tc) +{ + volatile long double z_pos = +0.; + volatile long double z_neg = -0.; +#if __LDBL_HAS_DENORM__ + volatile long double m = __LDBL_DENORM_MIN__; +#else + volatile long double m = LDBL_MIN; +#endif + + if (signbit(z_pos) == signbit(z_neg)) + atf_tc_skip("no signed zeroes on this architecture"); + + /* + * `nextUp(x) is the least floating-point number in the format + * of x that compares greater than x. [...] nextDown(x) is + * -nextUp(-x).' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + * + * Verify that nextafterl and nexttowardl, which implement the + * nextUp and nextDown operations, obey this rule and don't + * send -0 to +0 or +0 to -0, respectively. + */ + + CHECK(0, nextafterl, z_neg, +INFINITY, m); + CHECK(1, nexttowardl, z_neg, +INFINITY, m); + CHECK(2, nextafterl, z_pos, +INFINITY, m); + CHECK(3, nexttowardl, z_pos, +INFINITY, m); + + CHECK(4, nextafterl, z_pos, -INFINITY, -m); + CHECK(5, nexttowardl, z_pos, -INFINITY, -m); + CHECK(6, nextafterl, z_neg, -INFINITY, -m); + CHECK(7, nexttowardl, z_neg, -INFINITY, -m); + + /* + * `If x is the negative number of least magnitude in x's + * format, nextUp(x) is -0.' + * --IEEE 754-2019, 5.3.1 General operations, p. 19 + */ + CHECK(8, nextafterl, -m, +INFINITY, 0); + CHECK(9, nexttowardl, -m, +INFINITY, 0); + ATF_CHECK(signbit(nextafterl(-m, +INFINITY)) != 0); + CHECK(10, nextafterl, m, -INFINITY, 0); + CHECK(11, nexttowardl, m, -INFINITY, 0); + ATF_CHECK(signbit(nextafterl(m, -INFINITY)) == 0); +} + +ATF_TC(nextl_near_0); +ATF_TC_HEAD(nextl_near_0, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl near 0"); +} +ATF_TC_BODY(nextl_near_0, tc) +{ + static const long double x[] = { + [0] = 0, +#if __LDBL_HAS_DENORM__ + [1] = __LDBL_DENORM_MIN__, + [2] = 2*__LDBL_DENORM_MIN__, + [3] = 3*__LDBL_DENORM_MIN__, + [4] = 4*__LDBL_DENORM_MIN__, +#else + [1] = LDBL_MIN, + [2] = LDBL_MIN*(1 + LDBL_EPSILON), + [3] = LDBL_MIN*(1 + 2*LDBL_EPSILON), + [4] = LDBL_MIN*(1 + 3*LDBL_EPSILON), +#endif + }; + + checkl(x, __arraycount(x)); +} + +ATF_TC(nextl_near_sub_normal); +ATF_TC_HEAD(nextl_near_sub_normal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "nextafterl/nexttowardl near the subnormal/normal boundary"); +} +ATF_TC_BODY(nextl_near_sub_normal, tc) +{ +#if __LDBL_HAS_DENORM__ + static const long double x[] = { + [0] = LDBL_MIN - 3*__LDBL_DENORM_MIN__, + [1] = LDBL_MIN - 2*__LDBL_DENORM_MIN__, + [2] = LDBL_MIN - __LDBL_DENORM_MIN__, + [3] = LDBL_MIN, + [4] = LDBL_MIN + __LDBL_DENORM_MIN__, + [5] = LDBL_MIN + 2*__LDBL_DENORM_MIN__, + [6] = LDBL_MIN + 3*__LDBL_DENORM_MIN__, + }; + + checkl(x, __arraycount(x)); +#else /* !__LDBL_HAS_DENORM__ */ + atf_tc_skip("no subnormals on this architecture"); +#endif /* !__LDBL_HAS_DENORM__ */ +} + +ATF_TC(nextl_near_1); +ATF_TC_HEAD(nextl_near_1, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl near 1"); +} +ATF_TC_BODY(nextl_near_1, tc) +{ + static const long double x[] = { + [0] = 1 - 3*LDBL_EPSILON/2, + [1] = 1 - 2*LDBL_EPSILON/2, + [2] = 1 - LDBL_EPSILON/2, + [3] = 1, + [4] = 1 + LDBL_EPSILON, + [5] = 1 + 2*LDBL_EPSILON, + [6] = 1 + 3*LDBL_EPSILON, + }; + + checkl(x, __arraycount(x)); +} + +ATF_TC(nextl_near_1_5); +ATF_TC_HEAD(nextl_near_1_5, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl near 1.5"); +} +ATF_TC_BODY(nextl_near_1_5, tc) +{ + static const long double x[] = { + [0] = 1.5 - 3*LDBL_EPSILON, + [1] = 1.5 - 2*LDBL_EPSILON, + [2] = 1.5 - LDBL_EPSILON, + [3] = 1.5, + [4] = 1.5 + LDBL_EPSILON, + [5] = 1.5 + 2*LDBL_EPSILON, + [6] = 1.5 + 3*LDBL_EPSILON, + }; + + checkl(x, __arraycount(x)); +} + +ATF_TC(nextl_near_infinity); +ATF_TC_HEAD(nextl_near_infinity, tc) +{ + atf_tc_set_md_var(tc, "descr", "nextafterl/nexttowardl near infinity"); +} +ATF_TC_BODY(nextl_near_infinity, tc) +{ + static const long double x[] = { + [0] = LDBL_MAX, + [1] = INFINITY, + }; + volatile long double t; + + if (!isinf(INFINITY)) + atf_tc_skip("no infinities on this architecture"); + + checkl(x, __arraycount(x)); + + ATF_CHECK_EQ_MSG((t = nextafterl(INFINITY, INFINITY)), INFINITY, + "t=%La=%Lg", t, t); + ATF_CHECK_EQ_MSG((t = nextafterl(-INFINITY, -INFINITY)), -INFINITY, + "t=%La=%Lg", t, t); +} + +#endif /* __vax__ */ + +ATF_TP_ADD_TCS(tp) +{ + +#ifdef __vax__ + ATF_TP_ADD_TC(tp, vaxafter); +#else + ATF_TP_ADD_TC(tp, next_nan); + ATF_TP_ADD_TC(tp, next_near_0); + ATF_TP_ADD_TC(tp, next_near_1); + ATF_TP_ADD_TC(tp, next_near_1_5); + ATF_TP_ADD_TC(tp, next_near_infinity); + ATF_TP_ADD_TC(tp, next_near_sub_normal); + ATF_TP_ADD_TC(tp, next_signed_0); + ATF_TP_ADD_TC(tp, nextf_nan); + ATF_TP_ADD_TC(tp, nextf_near_0); + ATF_TP_ADD_TC(tp, nextf_near_1); + ATF_TP_ADD_TC(tp, nextf_near_1_5); + ATF_TP_ADD_TC(tp, nextf_near_infinity); + ATF_TP_ADD_TC(tp, nextf_near_sub_normal); + ATF_TP_ADD_TC(tp, nextf_signed_0); + ATF_TP_ADD_TC(tp, nextl_nan); + ATF_TP_ADD_TC(tp, nextl_near_0); + ATF_TP_ADD_TC(tp, nextl_near_1); + ATF_TP_ADD_TC(tp, nextl_near_1_5); + ATF_TP_ADD_TC(tp, nextl_near_infinity); + ATF_TP_ADD_TC(tp, nextl_near_sub_normal); + ATF_TP_ADD_TC(tp, nextl_signed_0); +#endif + return atf_no_error(); +} diff --git a/lib/libm/t_remquo.c b/lib/libm/t_remquo.c new file mode 100644 index 000000000000..a60e93877335 --- /dev/null +++ b/lib/libm/t_remquo.c @@ -0,0 +1,126 @@ +/* $NetBSD: t_remquo.c,v 1.2 2024/09/20 22:24:51 rin Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen and Greg Troxel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <atf-c.h> +#include <float.h> +#include <math.h> + +/* + * remquo(3) + */ +ATF_TC(remquo_args); +ATF_TC_HEAD(remquo_args, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test some selected arguments"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, remquo_args); + + return atf_no_error(); +} + +#ifdef __vax__ + +ATF_TC_BODY(remquo_args, tc) +{ + atf_tc_expect_fail("PR 57881: vax libm is missing various symbols"); + atf_tc_fail("missing remquo on vax"); +} + +#else /* !__vax__ */ + +static const struct { + double x; + double y; + double r; /* expected */ + int quo; /* expected */ +} args[] = { + { -135.0, -90.0, 45.0, 2 }, + { -45.0, -90.0, -45.0, 8 }, + { 45.0, -90.0, 45.0, -8 }, + { 135.0, -90.0, -45.0, -2 }, + { -180.0, 90.0, -0.0, -2 }, + { -135.0, 90.0, 45.0, -2 }, + { -90.0, 90.0, -0.0, -1 }, + { -45.0, 90.0, -45.0, -8 }, + { 0.0, 90.0, 0.0, 0 }, + { 45.0, 90.0, 45.0, 8 }, + { 90.0, 90.0, 0.0, 1 }, + { 135.0, 90.0, -45.0, 2 }, + { 180.0, 90.0, 0.0, 2 }, +}; + +ATF_TC_BODY(remquo_args, tc) +{ + const double eps = DBL_EPSILON; + size_t i; + + for (i = 0; i < __arraycount(args); i++) { + double x = args[i].x; + double y = args[i].y; + double r; + double r_exp = args[i].r; + int quo; + int quo_exp = args[i].quo; + + bool ok = true; + + r = remquo(x, y, &quo); + + ok &= (fabs(r - r_exp) <= eps); + + /* + * For now, consider 0 to have positive sign. + */ + if (quo_exp < 0 && quo >= 0) + ok = false; + if (quo_exp >= 0 && quo < 0) + ok = false; + + /* + * The specification requires that quo be congruent to + * the integer remainder modulo 2^k for some k >=3. + */ + ok &= ((quo & 0x7) == (quo_exp & 0x7)); + + if (!ok) { + atf_tc_fail_nonfatal("remquo(%g, %g) " + "r/quo expected %g/%d != %g/%d", + x, y, r_exp, quo_exp, r, quo); + } + } +} + +#endif /* !__vax__ */ diff --git a/lib/libpthread/cancelpoint.h b/lib/libpthread/cancelpoint.h new file mode 100644 index 000000000000..0fa332a6042c --- /dev/null +++ b/lib/libpthread/cancelpoint.h @@ -0,0 +1,133 @@ +/* $NetBSD: cancelpoint.h,v 1.1 2025/04/05 11:22:32 riastradh Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TESTS_LIB_LIBPTHREAD_CANCELPOINT_H +#define TESTS_LIB_LIBPTHREAD_CANCELPOINT_H + +#include <pthread.h> +#include <stdbool.h> +#include <stddef.h> + +#include "h_macros.h" + +extern pthread_barrier_t bar; +extern bool cleanup_done; + +#if 0 +atomic_bool cancelpointreadydone; +#endif + +static void +cleanup(void *cookie) +{ + bool *cleanup_donep = cookie; + + *cleanup_donep = true; +} + +static void +cancelpointready(void) +{ + + (void)pthread_barrier_wait(&bar); + RL(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); +#if 0 + atomic_store_release(&cancelpointreadydone, true); +#endif +} + +static void * +thread_cancelpoint(void *cookie) +{ + void (*cancelpoint)(void) = cookie; + + RL(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)); + (void)pthread_barrier_wait(&bar); + + pthread_cleanup_push(&cleanup, &cleanup_done); + (*cancelpoint)(); + pthread_cleanup_pop(/*execute*/0); + + return NULL; +} + +static void +test_cancelpoint_before(void (*cancelpoint)(void)) +{ + pthread_t t; + void *result; + + RZ(pthread_barrier_init(&bar, NULL, 2)); + RZ(pthread_create(&t, NULL, &thread_cancelpoint, cancelpoint)); + + (void)pthread_barrier_wait(&bar); + fprintf(stderr, "cancel\n"); + RZ(pthread_cancel(t)); + (void)pthread_barrier_wait(&bar); + + alarm(1); + RZ(pthread_join(t, &result)); + ATF_CHECK_MSG(result == PTHREAD_CANCELED, + "result=%p PTHREAD_CANCELED=%p", result, PTHREAD_CANCELED); + ATF_CHECK(cleanup_done); +} + +#if 0 +static void +test_cancelpoint_wakeup(void (*cancelpoint)(void)) +{ + pthread_t t; + + RZ(pthread_barrier_init(&bar, NULL, 2)); + RZ(pthread_create(&t, NULL, &cancelpoint_thread, cancelpoint)); + + (void)pthread_barrier_wait(&bar); + while (!atomic_load_acquire(&cancelpointreadydone)) + continue; + while (!pthread_sleeping(t)) /* XXX find a way to do this */ + continue; + RZ(pthread_cancel(t)); +} +#endif + +#define TEST_CANCELPOINT(CANCELPOINT, XFAIL) \ +ATF_TC(CANCELPOINT); \ +ATF_TC_HEAD(CANCELPOINT, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", "Test cancellation point: " \ + #CANCELPOINT); \ +} \ +ATF_TC_BODY(CANCELPOINT, tc) \ +{ \ + XFAIL; \ + test_cancelpoint_before(&CANCELPOINT); \ +} +#define ADD_TEST_CANCELPOINT(CANCELPOINT) \ + ATF_TP_ADD_TC(tp, CANCELPOINT) + +#endif /* TESTS_LIB_LIBPTHREAD_CANCELPOINT_H */ diff --git a/lib/libpthread/t_cancellation.c b/lib/libpthread/t_cancellation.c new file mode 100644 index 000000000000..deb4ebb5efae --- /dev/null +++ b/lib/libpthread/t_cancellation.c @@ -0,0 +1,1543 @@ +/* $NetBSD: t_cancellation.c,v 1.4 2025/04/05 11:22:32 riastradh Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_cancellation.c,v 1.4 2025/04/05 11:22:32 riastradh Exp $"); + +#include <sys/event.h> +#include <sys/mman.h> +#include <sys/msg.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/wait.h> + +#include <aio.h> +#include <atf-c.h> +#include <fcntl.h> +#include <mqueue.h> +#include <paths.h> +#include <poll.h> +#include <pthread.h> +#include <signal.h> +#include <stdatomic.h> +#include <string.h> +#include <termios.h> +#include <threads.h> +#include <time.h> +#include <unistd.h> + +#include "cancelpoint.h" +#include "h_macros.h" + +static const char * +c11thrd_err(int error) +{ + static char buf[32]; + + switch (error) { + case thrd_busy: return "thrd_busy"; + case thrd_nomem: return "thrd_nomem"; + case thrd_success: return "thrd_success"; + case thrd_timedout: return "thrd_timedout"; + default: + snprintf(buf, sizeof(buf), "thrd_%d", error); + return buf; + } +} + +#define RT(x) do \ +{ \ + int RT_rv = (x); \ + ATF_REQUIRE_MSG(RT_rv == 0, "%s: %d (%s)", \ + #x, RT_rv, c11thrd_err(RT_rv)); \ +} while (0) + +pthread_barrier_t bar; +bool cleanup_done; + +/* POSIX style */ +static void * +emptythread(void *cookie) +{ + return NULL; +} + +/* C11 style */ +static int +emptythrd(void *cookie) +{ + return 123; +} + +static void +cleanup_pthread_join(void *cookie) +{ + pthread_t *tp = cookie; + void *result; + + RZ(pthread_join(*tp, &result)); + ATF_CHECK_MSG(result == NULL, "result=%p", result); +} + +static void +cleanup_thrd_join(void *cookie) +{ + thrd_t *tp = cookie; + int result; + + RT(thrd_join(*tp, &result)); + ATF_CHECK_MSG(result == 123, "result=%d", result); +} + +static void +cleanup_msgid(void *cookie) +{ + int *msgidp = cookie; + + /* + * These message queue identifiers are persistent, so make sure + * to clean them up; otherwise the operator will have to run + * `ipcrm -q all' from time to time or else the tests will fail + * with ENOSPC. + */ + RL(msgctl(*msgidp, IPC_RMID, NULL)); +} + +/* + * List of cancellation points in POSIX: + * + * https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/V2_chap02.html#tag_16_09_05_02 + */ + +static int +acceptsetup(void) +{ + struct sockaddr_un sun = { .sun_family = AF_LOCAL }; + int sock; + + strncpy(sun.sun_path, "sock", sizeof(sun.sun_path)); + RL(sock = socket(PF_LOCAL, SOCK_STREAM, 0)); + RL(bind(sock, (const struct sockaddr *)&sun, sizeof(sun))); + RL(listen(sock, 1)); + + return sock; +} + +static void +cancelpoint_accept(void) +{ + const int sock = acceptsetup(); + + cancelpointready(); + RL(accept(sock, NULL, NULL)); +} + +static void +cancelpoint_accept4(void) +{ + const int sock = acceptsetup(); + + cancelpointready(); + RL(accept4(sock, NULL, NULL, O_CLOEXEC)); +} + +static void +cancelpoint_aio_suspend(void) +{ + int fd[2]; + char buf[32]; + struct aiocb aio = { + .aio_offset = 0, + .aio_buf = buf, + .aio_nbytes = sizeof(buf), + .aio_fildes = -1, + }; + const struct aiocb *const aiolist[] = { &aio }; + + RL(pipe(fd)); + aio.aio_fildes = fd[0]; + RL(aio_read(&aio)); + cancelpointready(); + RL(aio_suspend(aiolist, __arraycount(aiolist), NULL)); +} + +static void +cancelpoint_clock_nanosleep(void) +{ + /* XXX test all CLOCK_*? */ + struct timespec t = {.tv_sec = 1, .tv_nsec = 0}; + + cancelpointready(); + RL(clock_nanosleep(CLOCK_MONOTONIC, 0, &t, NULL)); +} + +static void +cancelpoint_close(void) +{ + int fd; + + RL(fd = open("/dev/null", O_RDWR)); + cancelpointready(); + RL(close(fd)); +} + +static void +cancelpoint_cnd_timedwait(void) +{ + cnd_t cnd; + mtx_t mtx; + struct timespec t = {.tv_sec = 1, .tv_nsec = 0}; + + RT(cnd_init(&cnd)); + RT(mtx_init(&mtx, mtx_plain)); + cancelpointready(); + RT(mtx_lock(&mtx)); + RT(cnd_timedwait(&cnd, &mtx, &t)); + RT(mtx_unlock(&mtx)); +} + +static void +cancelpoint_cnd_wait(void) +{ + cnd_t cnd; + mtx_t mtx; + + RT(cnd_init(&cnd)); + RT(mtx_init(&mtx, mtx_plain)); + cancelpointready(); + RT(mtx_lock(&mtx)); + RT(cnd_wait(&cnd, &mtx)); + RT(mtx_unlock(&mtx)); +} + +static void +cancelpoint_connect(void) +{ + struct sockaddr_un sun = { .sun_family = AF_LOCAL }; + int sock; + + strncpy(sun.sun_path, "sock", sizeof(sun.sun_path)); + RL(sock = socket(PF_LOCAL, SOCK_STREAM, 0)); + cancelpointready(); + RL(connect(sock, (const struct sockaddr *)&sun, sizeof(sun))); +} + +static void +cancelpoint_creat(void) +{ + + cancelpointready(); + RL(creat("file", 0666)); +} + +static void +cancelpoint_fcntl_F_SETLKW(void) +{ + int fd; + struct flock fl = { + .l_start = 0, + .l_len = 0, + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + }; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(fcntl(fd, F_SETLKW, &fl)); +} + +static void +cancelpoint_fcntl_F_OFD_SETLKW(void) +{ +#ifdef F_OFD_SETLKW + int fd; + struct flock fl = { + .l_start = 0, + .l_len = 0, + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + }; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(fcntl(fd, F_OFD_SETLKW, &fl)); +#else + atf_tc_expect_fail("PR kern/59241: POSIX.1-2024:" + " OFD-owned file locks"); + atf_tc_fail("no F_OFD_SETLKW"); +#endif +} + +static void +cancelpoint_fdatasync(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(fdatasync(fd)); +} + +static void +cancelpoint_fsync(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(fsync(fd)); +} + +static void +cancelpoint_kevent(void) +{ + int kq; + struct kevent ev; + + EV_SET(&ev, SIGUSR1, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, + /*fflags*/0, /*data*/0, /*udata*/0); + + RL(kq = kqueue()); + RL(kevent(kq, &ev, 1, NULL, 1, &(const struct timespec){0,0})); + cancelpointready(); + RL(kevent(kq, NULL, 0, &ev, 1, NULL)); +} + +static void +cancelpoint_lockf_F_LOCK(void) +{ + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(lockf(fd, F_LOCK, 0)); +} + +static void +cancelpoint_mq_receive(void) +{ + mqd_t mq; + char buf[32]; + + RL(mq = mq_open("mq", O_RDWR|O_CREAT, 0666, NULL)); + cancelpointready(); + RL(mq_receive(mq, buf, sizeof(buf), NULL)); +} + +static void +cancelpoint_mq_send(void) +{ + mqd_t mq; + char buf[32] = {0}; + + RL(mq = mq_open("mq", O_RDWR|O_CREAT, 0666, NULL)); + cancelpointready(); + RL(mq_send(mq, buf, sizeof(buf), 0)); +} + +static void +cancelpoint_mq_timedreceive(void) +{ + mqd_t mq; + char buf[32]; + struct timespec t = {.tv_sec = 1, .tv_nsec = 0}; + + RL(mq = mq_open("mq", O_RDWR|O_CREAT, 0666, NULL)); + cancelpointready(); + RL(mq_timedreceive(mq, buf, sizeof(buf), NULL, &t)); +} + +static void +cancelpoint_mq_timedsend(void) +{ + mqd_t mq; + char buf[32] = {0}; + struct timespec t = {.tv_sec = 1, .tv_nsec = 0}; + + RL(mq = mq_open("mq", O_RDWR|O_CREAT, 0666, NULL)); + cancelpointready(); + RL(mq_timedsend(mq, buf, sizeof(buf), 0, &t)); +} + +static void +cancelpoint_msgrcv(void) +{ + int msgid; + char buf[32]; + + RL(msgid = msgget(IPC_PRIVATE, IPC_CREAT)); + pthread_cleanup_push(&cleanup_msgid, &msgid); + cancelpointready(); + RL(msgrcv(msgid, buf, sizeof(buf), 0, 0)); + pthread_cleanup_pop(/*execute*/1); +} + +static void +cancelpoint_msgsnd(void) +{ + int msgid; + char buf[32] = {0}; + + RL(msgid = msgget(IPC_PRIVATE, IPC_CREAT)); + pthread_cleanup_push(&cleanup_msgid, &msgid); + cancelpointready(); + RL(msgsnd(msgid, buf, sizeof(buf), 0)); + pthread_cleanup_pop(/*execute*/1); +} + +static void +cancelpoint_msync(void) +{ + const unsigned long pagesize = sysconf(_SC_PAGESIZE); + int fd; + void *map; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + RL(ftruncate(fd, pagesize)); + REQUIRE_LIBC(map = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, + MAP_SHARED, fd, 0), + MAP_FAILED); + cancelpointready(); + RL(msync(map, pagesize, MS_SYNC)); +} + +static void +cancelpoint_nanosleep(void) +{ + /* XXX test all CLOCK_*? */ + struct timespec t = {.tv_sec = 1, .tv_nsec = 0}; + + cancelpointready(); + RL(nanosleep(&t, NULL)); +} + +static void +cancelpoint_open(void) +{ + + cancelpointready(); + RL(open("file", O_RDWR)); +} + +static void +cancelpoint_openat(void) +{ + + cancelpointready(); + RL(openat(AT_FDCWD, "file", O_RDWR)); +} + +static void +cancelpoint_pause(void) +{ + + cancelpointready(); + RL(pause()); +} + +static void +cancelpoint_poll(void) +{ + int fd[2]; + struct pollfd pfd; + + RL(pipe(fd)); + pfd.fd = fd[0]; + pfd.events = POLLIN; + cancelpointready(); + RL(poll(&pfd, 1, 1000)); +} + +static void +cancelpoint_posix_close(void) +{ +#if 0 + int fd; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(posix_close(fd, POSIX_CLOSE_RESTART)); +#else + atf_tc_expect_fail("PR kern/58929: POSIX.1-2024 compliance:" + " posix_close, POSIX_CLOSE_RESTART"); + atf_tc_fail("no posix_close"); +#endif +} + +static void +cancelpoint_ppoll(void) +{ + int fd[2]; + struct pollfd pfd; + struct timespec t = {.tv_sec = 1, .tv_nsec = 0}; + + RL(pipe(fd)); + pfd.fd = fd[0]; + pfd.events = POLLIN; + cancelpointready(); + RL(ppoll(&pfd, 1, &t, NULL)); +} + +static void +cancelpoint_pread(void) +{ + int fd; + char buf[1]; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(pread(fd, buf, sizeof(buf), 1)); +} + + +static void +cancelpoint_pselect(void) +{ + int fd[2]; + fd_set readfd; + struct timespec t = {.tv_sec = 1, .tv_nsec = 0}; + + FD_ZERO(&readfd); + + RL(pipe(fd)); + FD_SET(fd[0], &readfd); + cancelpointready(); + RL(pselect(fd[0] + 1, &readfd, NULL, NULL, &t, NULL)); +} + +static void +cancelpoint_pthread_cond_clockwait(void) +{ +#if 0 + pthread_cond_t cond; + pthread_mutex_t mutex; + struct timespec t = {.tv_sec = 1, .tv_nsec = 0}; + + RZ(pthread_cond_init(&cond, NULL)); + RZ(pthread_mutex_init(&mutex, NULL)); + cancelpointready(); + RZ(pthread_mutex_lock(&mutex)); + RZ(pthread_cond_clockwait(&cond, &mutex, CLOCK_MONOTONIC, &t)); + RZ(pthread_mutex_unlock(&mutex)); +#else + atf_tc_expect_fail("PR lib/59142: POSIX.1-2024:" + " pthread_cond_clockwait and company"); + atf_tc_fail("no posix_cond_clockwait"); +#endif +} + +static void +cancelpoint_pthread_cond_timedwait(void) +{ + pthread_cond_t cond; + pthread_mutex_t mutex; + struct timespec t = {.tv_sec = 1, .tv_nsec = 0}; + + RZ(pthread_cond_init(&cond, NULL)); + RZ(pthread_mutex_init(&mutex, NULL)); + cancelpointready(); + RZ(pthread_mutex_lock(&mutex)); + RZ(pthread_cond_timedwait(&cond, &mutex, &t)); + RZ(pthread_mutex_unlock(&mutex)); +} + +static void +cancelpoint_pthread_cond_wait(void) +{ + pthread_cond_t cond; + pthread_mutex_t mutex; + + RZ(pthread_cond_init(&cond, NULL)); + RZ(pthread_mutex_init(&mutex, NULL)); + cancelpointready(); + RZ(pthread_mutex_lock(&mutex)); + RZ(pthread_cond_wait(&cond, &mutex)); + RZ(pthread_mutex_unlock(&mutex)); +} + +static void +cancelpoint_pthread_join(void) +{ + pthread_t t; + + RZ(pthread_create(&t, NULL, &emptythread, NULL)); + pthread_cleanup_push(&cleanup_pthread_join, &t); + cancelpointready(); + RZ(pthread_join(t, NULL)); + pthread_cleanup_pop(/*execute*/0); +} + +static void +cancelpoint_pthread_testcancel(void) +{ + + cancelpointready(); + pthread_testcancel(); +} + +static void +cancelpoint_pwrite(void) +{ + int fd; + char buf[1] = {0}; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(pwrite(fd, buf, sizeof(buf), 1)); +} + +static void +cancelpoint_read(void) +{ + int fd; + char buf[1]; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(read(fd, buf, sizeof(buf))); +} + +static void +cancelpoint_readv(void) +{ + int fd; + char buf[1]; + struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) }; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(readv(fd, &iov, 1)); +} + +static void +cancelpoint_recv(void) +{ + struct sockaddr_un sun = { .sun_family = AF_LOCAL }; + int sock; + char buf[1]; + + strncpy(sun.sun_path, "sock", sizeof(sun.sun_path)); + RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0)); + RL(bind(sock, (const struct sockaddr *)&sun, sizeof(sun))); + cancelpointready(); + RL(recv(sock, buf, sizeof(buf), 0)); +} + +static void +cancelpoint_recvfrom(void) +{ + struct sockaddr_un sun = { .sun_family = AF_LOCAL }; + int sock; + char buf[1]; + struct sockaddr_storage ss; + socklen_t len = sizeof(ss); + + strncpy(sun.sun_path, "sock", sizeof(sun.sun_path)); + RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0)); + RL(bind(sock, (const struct sockaddr *)&sun, sizeof(sun))); + cancelpointready(); + RL(recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&ss, &len)); +} + +static void +cancelpoint_recvmsg(void) +{ + struct sockaddr_un sun = { .sun_family = AF_LOCAL }; + int sock; + char buf[1]; + struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) }; + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + strncpy(sun.sun_path, "sock", sizeof(sun.sun_path)); + RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0)); + RL(bind(sock, (const struct sockaddr *)&sun, sizeof(sun))); + cancelpointready(); + RL(recvmsg(sock, &msg, 0)); +} + +static void +cancelpoint_select(void) +{ + int fd[2]; + fd_set readfd; + struct timeval t = {.tv_sec = 1, .tv_usec = 0}; + + FD_ZERO(&readfd); + + RL(pipe(fd)); + FD_SET(fd[0], &readfd); + cancelpointready(); + RL(select(fd[0] + 1, &readfd, NULL, NULL, &t)); +} + +static void +cancelpoint_send(void) +{ + struct sockaddr_un sun = { .sun_family = AF_LOCAL }; + int sock; + char buf[1] = {0}; + + strncpy(sun.sun_path, "sock", sizeof(sun.sun_path)); + RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0)); + RL(bind(sock, (const struct sockaddr *)&sun, sizeof(sun))); + cancelpointready(); + RL(send(sock, buf, sizeof(buf), 0)); +} + +static void +cancelpoint_sendto(void) +{ + struct sockaddr_un sun = { .sun_family = AF_LOCAL }; + int sock; + char buf[1] = {0}; + + strncpy(sun.sun_path, "sock", sizeof(sun.sun_path)); + RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0)); + cancelpointready(); + RL(sendto(sock, buf, sizeof(buf), 0, (const struct sockaddr *)&sun, + sizeof(sun))); +} + +static void +cancelpoint_sendmsg(void) +{ + struct sockaddr_un sun = { .sun_family = AF_LOCAL }; + int sock; + char buf[1] = {0}; + struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) }; + struct msghdr msg = { + .msg_name = (struct sockaddr *)&sun, + .msg_namelen = sizeof(sun), + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + strncpy(sun.sun_path, "sock", sizeof(sun.sun_path)); + RL(sock = socket(PF_LOCAL, SOCK_DGRAM, 0)); + cancelpointready(); + RL(sendmsg(sock, &msg, 0)); +} + +static void +cancelpoint_sigsuspend(void) +{ + sigset_t mask, omask; + + RL(sigfillset(&mask)); + RL(sigprocmask(SIG_BLOCK, &mask, &omask)); + cancelpointready(); + RL(sigsuspend(&omask)); +} + +static void +cancelpoint_sigtimedwait(void) +{ + sigset_t mask, omask; + siginfo_t info; + struct timespec t = {.tv_sec = 1, .tv_nsec = 0}; + + RL(sigfillset(&mask)); + RL(sigprocmask(SIG_BLOCK, &mask, &omask)); + cancelpointready(); + RL(sigtimedwait(&omask, &info, &t)); +} + +static void +cancelpoint_sigwait(void) +{ + sigset_t mask, omask; + int sig; + + RL(sigfillset(&mask)); + RL(sigprocmask(SIG_BLOCK, &mask, &omask)); + cancelpointready(); + RL(sigwait(&omask, &sig)); +} + +static void +cancelpoint_sigwaitinfo(void) +{ + sigset_t mask, omask; + siginfo_t info; + + RL(sigfillset(&mask)); + RL(sigprocmask(SIG_BLOCK, &mask, &omask)); + cancelpointready(); + RL(sigwaitinfo(&omask, &info)); +} + +static void +cancelpoint_sleep(void) +{ + + cancelpointready(); + (void)sleep(1); +} + +static void +cancelpoint_tcdrain(void) +{ + int hostfd, appfd; + char *pts; + + RL(hostfd = posix_openpt(O_RDWR|O_NOCTTY)); + RL(grantpt(hostfd)); + RL(unlockpt(hostfd)); + REQUIRE_LIBC(pts = ptsname(hostfd), NULL); + RL(appfd = open(pts, O_RDWR|O_NOCTTY)); + cancelpointready(); + RL(tcdrain(appfd)); +} + +static void +cancelpoint_thrd_join(void) +{ + thrd_t t; + + RT(thrd_create(&t, &emptythrd, NULL)); + pthread_cleanup_push(&cleanup_thrd_join, &t); + cancelpointready(); + RT(thrd_join(t, NULL)); + pthread_cleanup_pop(/*execute*/0); +} + +static void +cancelpoint_thrd_sleep(void) +{ + struct timespec t = {.tv_sec = 1, .tv_nsec = 0}; + + cancelpointready(); + RT(thrd_sleep(&t, NULL)); +} + +static void +cancelpoint_wait(void) +{ + + cancelpointready(); + RL(wait(NULL)); +} + +static void +cancelpoint_waitid(void) +{ + + cancelpointready(); + RL(waitid(P_ALL, 0, NULL, 0)); +} + +static void +cancelpoint_waitpid(void) +{ + + cancelpointready(); + RL(waitpid(-1, NULL, 0)); +} + +static void +cancelpoint_write(void) +{ + int fd; + char buf[1] = {0}; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(write(fd, buf, sizeof(buf))); +} + +static void +cancelpoint_writev(void) +{ + int fd; + char buf[1] = {0}; + struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) }; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + cancelpointready(); + RL(writev(fd, &iov, 1)); +} + +TEST_CANCELPOINT(cancelpoint_accept, __nothing) +TEST_CANCELPOINT(cancelpoint_accept4, __nothing) +TEST_CANCELPOINT(cancelpoint_aio_suspend, __nothing) +TEST_CANCELPOINT(cancelpoint_clock_nanosleep, __nothing) +TEST_CANCELPOINT(cancelpoint_close, __nothing) +TEST_CANCELPOINT(cancelpoint_cnd_timedwait, __nothing) +TEST_CANCELPOINT(cancelpoint_cnd_wait, __nothing) +TEST_CANCELPOINT(cancelpoint_connect, __nothing) +TEST_CANCELPOINT(cancelpoint_creat, __nothing) +TEST_CANCELPOINT(cancelpoint_fcntl_F_SETLKW, __nothing) +TEST_CANCELPOINT(cancelpoint_fcntl_F_OFD_SETLKW, __nothing) +TEST_CANCELPOINT(cancelpoint_fdatasync, __nothing) +TEST_CANCELPOINT(cancelpoint_fsync, __nothing) +TEST_CANCELPOINT(cancelpoint_kevent, __nothing) +TEST_CANCELPOINT(cancelpoint_lockf_F_LOCK, __nothing) +TEST_CANCELPOINT(cancelpoint_mq_receive, __nothing) +TEST_CANCELPOINT(cancelpoint_mq_send, __nothing) +TEST_CANCELPOINT(cancelpoint_mq_timedreceive, __nothing) +TEST_CANCELPOINT(cancelpoint_mq_timedsend, __nothing) +TEST_CANCELPOINT(cancelpoint_msgrcv, __nothing) +TEST_CANCELPOINT(cancelpoint_msgsnd, __nothing) +TEST_CANCELPOINT(cancelpoint_msync, __nothing) +TEST_CANCELPOINT(cancelpoint_nanosleep, __nothing) +TEST_CANCELPOINT(cancelpoint_open, __nothing) +TEST_CANCELPOINT(cancelpoint_openat, __nothing) +TEST_CANCELPOINT(cancelpoint_pause, __nothing) +TEST_CANCELPOINT(cancelpoint_poll, __nothing) +TEST_CANCELPOINT(cancelpoint_posix_close, __nothing) +TEST_CANCELPOINT(cancelpoint_ppoll, __nothing) +TEST_CANCELPOINT(cancelpoint_pread, __nothing) +TEST_CANCELPOINT(cancelpoint_pselect, __nothing) +TEST_CANCELPOINT(cancelpoint_pthread_cond_clockwait, __nothing) +TEST_CANCELPOINT(cancelpoint_pthread_cond_timedwait, __nothing) +TEST_CANCELPOINT(cancelpoint_pthread_cond_wait, __nothing) +TEST_CANCELPOINT(cancelpoint_pthread_join, __nothing) +TEST_CANCELPOINT(cancelpoint_pthread_testcancel, __nothing) +TEST_CANCELPOINT(cancelpoint_pwrite, __nothing) +TEST_CANCELPOINT(cancelpoint_read, __nothing) +TEST_CANCELPOINT(cancelpoint_readv, __nothing) +TEST_CANCELPOINT(cancelpoint_recv, __nothing) +TEST_CANCELPOINT(cancelpoint_recvfrom, __nothing) +TEST_CANCELPOINT(cancelpoint_recvmsg, __nothing) +TEST_CANCELPOINT(cancelpoint_select, __nothing) +TEST_CANCELPOINT(cancelpoint_send, __nothing) +TEST_CANCELPOINT(cancelpoint_sendto, __nothing) +TEST_CANCELPOINT(cancelpoint_sendmsg, __nothing) +TEST_CANCELPOINT(cancelpoint_sigsuspend, __nothing) +TEST_CANCELPOINT(cancelpoint_sigtimedwait, __nothing) +TEST_CANCELPOINT(cancelpoint_sigwait, __nothing) +TEST_CANCELPOINT(cancelpoint_sigwaitinfo, __nothing) +TEST_CANCELPOINT(cancelpoint_sleep, __nothing) +TEST_CANCELPOINT(cancelpoint_tcdrain, __nothing) +TEST_CANCELPOINT(cancelpoint_thrd_join, __nothing) +TEST_CANCELPOINT(cancelpoint_thrd_sleep, __nothing) +TEST_CANCELPOINT(cancelpoint_wait, __nothing) +TEST_CANCELPOINT(cancelpoint_waitid, __nothing) +TEST_CANCELPOINT(cancelpoint_waitpid, __nothing) +TEST_CANCELPOINT(cancelpoint_write, __nothing) +TEST_CANCELPOINT(cancelpoint_writev, __nothing) + +ATF_TC(cleanuppop0); +ATF_TC_HEAD(cleanuppop0, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test pthread_cleanup_pop(0)"); +} +ATF_TC_BODY(cleanuppop0, tc) +{ + + pthread_cleanup_push(&cleanup, &cleanup_done); + pthread_cleanup_pop(/*execute*/0); + ATF_CHECK(!cleanup_done); +} + +ATF_TC(cleanuppop1); +ATF_TC_HEAD(cleanuppop1, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test pthread_cleanup_pop(1)"); +} +ATF_TC_BODY(cleanuppop1, tc) +{ + + pthread_cleanup_push(&cleanup, &cleanup_done); + pthread_cleanup_pop(/*execute*/1); + ATF_CHECK(cleanup_done); +} + +static void * +cancelself_async(void *cookie) +{ + int *n = cookie; + + RZ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); + + pthread_cleanup_push(&cleanup, &cleanup_done); + + *n = 1; + RZ(pthread_cancel(pthread_self())); /* cancel */ + *n = 2; + RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)); + pthread_testcancel(); + *n = 3; + RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + pthread_testcancel(); + *n = 4; + + pthread_cleanup_pop(/*execute*/0); + return NULL; +} + +ATF_TC(cancelself_async); +ATF_TC_HEAD(cancelself_async, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test pthread_cancel(pthread_self()) async"); +} +ATF_TC_BODY(cancelself_async, tc) +{ + int n = 0; + pthread_t t; + + RZ(pthread_create(&t, NULL, &cancelself_async, &n)); + + alarm(1); + RZ(pthread_join(t, NULL)); + + atf_tc_expect_fail("lib/59135: PTHREAD_CANCEL_ASYNCHRONOUS" + " doesn't do much"); + ATF_CHECK_MSG(n == 1, "n=%d", n); + atf_tc_expect_pass(); + ATF_CHECK(cleanup_done); +} + +static void * +cancelself_deferred(void *cookie) +{ + int *n = cookie; + + /* PTHREAD_CANCEL_DEFERRED by default */ + + pthread_cleanup_push(&cleanup, &cleanup_done); + + *n = 1; + RZ(pthread_cancel(pthread_self())); + *n = 2; + RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)); + *n = 3; + pthread_testcancel(); + *n = 4; + RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + *n = 5; + pthread_testcancel(); /* cancel */ + *n = 6; + + pthread_cleanup_pop(/*execute*/0); + return NULL; +} + +ATF_TC(cancelself_deferred); +ATF_TC_HEAD(cancelself_deferred, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test pthread_cancel(pthread_self()) deferred"); +} +ATF_TC_BODY(cancelself_deferred, tc) +{ + int n = 0; + pthread_t t; + + RZ(pthread_create(&t, NULL, &cancelself_deferred, &n)); + + alarm(1); + RZ(pthread_join(t, NULL)); + + ATF_CHECK_MSG(n == 5, "n=%d", n); + ATF_CHECK(cleanup_done); +} + +static void * +defaults(void *cookie) +{ + int state, type; + + fprintf(stderr, "created thread\n"); + + RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state)); + RZ(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &type)); + + ATF_CHECK_MSG(state == PTHREAD_CANCEL_ENABLE, + "state=%d PTHREAD_CANCEL_ENABLE=%d PTHREAD_CANCEL_DISABLE=%d", + state, PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE); + + ATF_CHECK_MSG(type == PTHREAD_CANCEL_DEFERRED, + "type=%d" + " PTHREAD_CANCEL_DEFERRED=%d PTHREAD_CANCEL_ASYNCHRONOUS=%d", + type, PTHREAD_CANCEL_DEFERRED, PTHREAD_CANCEL_ASYNCHRONOUS); + + return NULL; +} + +ATF_TC(defaults); +ATF_TC_HEAD(defaults, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test default cancelability"); +} +ATF_TC_BODY(defaults, tc) +{ + pthread_t t; + + fprintf(stderr, "initial thread\n"); + (void)defaults(NULL); + + RZ(pthread_create(&t, NULL, &defaults, NULL)); + + alarm(1); + RZ(pthread_join(t, NULL)); +} + +static void * +disable_enable(void *cookie) +{ + int *n = cookie; + + pthread_cleanup_push(&cleanup, &cleanup_done); + + *n = 1; + pthread_testcancel(); + *n = 2; + RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)); + *n = 3; + (void)pthread_barrier_wait(&bar); + *n = 4; + pthread_testcancel(); + *n = 5; + (void)pthread_barrier_wait(&bar); + *n = 6; + pthread_testcancel(); + *n = 7; + RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + *n = 8; + pthread_testcancel(); /* cancel */ + *n = 9; + + pthread_cleanup_pop(/*execute*/0); + return NULL; +} + +ATF_TC(disable_enable); +ATF_TC_HEAD(disable_enable, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test disabling and re-enabling cancellation"); +} +ATF_TC_BODY(disable_enable, tc) +{ + int n = 0; + pthread_t t; + + RZ(pthread_barrier_init(&bar, NULL, 2)); + + RZ(pthread_create(&t, NULL, &disable_enable, &n)); + + (void)pthread_barrier_wait(&bar); + RZ(pthread_cancel(t)); + (void)pthread_barrier_wait(&bar); + + alarm(1); + RZ(pthread_join(t, NULL)); + + ATF_CHECK_MSG(n == 8, "n=%d", n); + ATF_CHECK(cleanup_done); +} + +static void * +notestcancel_loop_async(void *cookie) +{ + + RZ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); + + pthread_cleanup_push(&cleanup, &cleanup_done); + (void)pthread_barrier_wait(&bar); + for (;;) + __insn_barrier(); + pthread_cleanup_pop(/*execute*/0); + + return NULL; +} + +ATF_TC(notestcancel_loop_async); +ATF_TC_HEAD(notestcancel_loop_async, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test nothing in a loop with PTHREAD_CANCEL_ASYNCHRONOUS"); +} +ATF_TC_BODY(notestcancel_loop_async, tc) +{ + pthread_t t; + void *result; + + RZ(pthread_barrier_init(&bar, NULL, 2)); + RZ(pthread_create(&t, NULL, ¬estcancel_loop_async, NULL)); + + (void)pthread_barrier_wait(&bar); + RZ(pthread_cancel(t)); + + atf_tc_expect_signal(SIGALRM, "lib/59135: PTHREAD_CANCEL_ASYNCHRONOUS" + " doesn't do much"); + alarm(1); + RZ(pthread_join(t, &result)); + ATF_CHECK_MSG(result == PTHREAD_CANCELED, + "result=%p PTHREAD_CANCELED=%p", result, PTHREAD_CANCELED); + ATF_CHECK(cleanup_done); +} + +static void * +disable_enable_async(void *cookie) +{ + int *n = cookie; + + pthread_cleanup_push(&cleanup, &cleanup_done); + + RZ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); + + *n = 1; + pthread_testcancel(); + *n = 2; + RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)); + *n = 3; + (void)pthread_barrier_wait(&bar); + *n = 4; + pthread_testcancel(); + *n = 5; + (void)pthread_barrier_wait(&bar); + *n = 6; + pthread_testcancel(); + *n = 7; + RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); /* cancel */ + *n = 8; + pthread_testcancel(); + *n = 9; + + pthread_cleanup_pop(/*execute*/0); + return NULL; +} + +ATF_TC(disable_enable_async); +ATF_TC_HEAD(disable_enable_async, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test disabling and re-enabling cancellation when asynchronous"); +} +ATF_TC_BODY(disable_enable_async, tc) +{ + int n = 0; + pthread_t t; + + RZ(pthread_barrier_init(&bar, NULL, 2)); + + RZ(pthread_create(&t, NULL, &disable_enable_async, &n)); + + (void)pthread_barrier_wait(&bar); + RZ(pthread_cancel(t)); + (void)pthread_barrier_wait(&bar); + + alarm(1); + RZ(pthread_join(t, NULL)); + + ATF_CHECK_MSG(n == 7, "n=%d", n); + ATF_CHECK(cleanup_done); +} + +static void * +disable_enable_setcanceltype_async(void *cookie) +{ + int *n = cookie; + + pthread_cleanup_push(&cleanup, &cleanup_done); + + *n = 1; + pthread_testcancel(); + *n = 2; + RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)); + *n = 3; + (void)pthread_barrier_wait(&bar); + *n = 4; + pthread_testcancel(); + *n = 5; + (void)pthread_barrier_wait(&bar); + *n = 6; + pthread_testcancel(); + *n = 7; + RZ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)); + *n = 8; + pthread_testcancel(); + *n = 9; + RZ(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); /* cancel */ + *n = 10; + pthread_testcancel(); + *n = 11; + + pthread_cleanup_pop(/*execute*/0); + return NULL; +} + +ATF_TC(disable_enable_setcanceltype_async); +ATF_TC_HEAD(disable_enable_setcanceltype_async, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test disabling cancellation, setting it async, and re-enabling"); +} +ATF_TC_BODY(disable_enable_setcanceltype_async, tc) +{ + int n = 0; + pthread_t t; + + RZ(pthread_barrier_init(&bar, NULL, 2)); + + RZ(pthread_create(&t, NULL, &disable_enable_setcanceltype_async, &n)); + + (void)pthread_barrier_wait(&bar); + RZ(pthread_cancel(t)); + (void)pthread_barrier_wait(&bar); + + alarm(1); + RZ(pthread_join(t, NULL)); + + ATF_CHECK_MSG(n == 9, "n=%d", n); + ATF_CHECK(cleanup_done); +} + +static void * +setcanceltype_async(void *cookie) +{ + int *n = cookie; + + pthread_cleanup_push(&cleanup, &cleanup_done); + + *n = 1; + pthread_testcancel(); + *n = 2; + (void)pthread_barrier_wait(&bar); + *n = 3; + (void)pthread_barrier_wait(&bar); + *n = 4; + RZ(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, + NULL)); /* cancel */ + *n = 5; + + pthread_cleanup_pop(/*execute*/0); + return NULL; +} + +ATF_TC(setcanceltype_async); +ATF_TC_HEAD(setcanceltype_async, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test disabling cancellation, setting it async, and re-enabling"); +} +ATF_TC_BODY(setcanceltype_async, tc) +{ + int n = 0; + pthread_t t; + + RZ(pthread_barrier_init(&bar, NULL, 2)); + + RZ(pthread_create(&t, NULL, &setcanceltype_async, &n)); + + (void)pthread_barrier_wait(&bar); + RZ(pthread_cancel(t)); + (void)pthread_barrier_wait(&bar); + + alarm(1); + RZ(pthread_join(t, NULL)); + + ATF_CHECK_MSG(n == 4, "n=%d", n); + ATF_CHECK(cleanup_done); +} + +static void +sighandler(int signo) +{ + int state; + + RZ(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &state)); + RZ(pthread_setcancelstate(state, NULL)); +} + +static void * +sigsafecancelstate(void *cookie) +{ + atomic_ulong *n = cookie; + char name[128]; + + pthread_cleanup_push(&cleanup, &cleanup_done); + REQUIRE_LIBC(signal(SIGUSR1, &sighandler), SIG_ERR); + + (void)pthread_barrier_wait(&bar); + + while (atomic_load_explicit(n, memory_order_relaxed) != 0) { + /* + * Do some things that might take the same lock as + * pthread_setcancelstate. + */ + RZ(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)); + RZ(pthread_getname_np(pthread_self(), name, sizeof(name))); + RZ(pthread_setname_np(pthread_self(), "%s", name)); + } + + pthread_cleanup_pop(/*execute*/1); + return NULL; +} + +ATF_TC(sigsafecancelstate); +ATF_TC_HEAD(sigsafecancelstate, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test pthread_setcancelstate async-signal-safety"); +} +ATF_TC_BODY(sigsafecancelstate, tc) +{ + pthread_t t; + atomic_ulong n = 10000; + void *result; + + RZ(pthread_barrier_init(&bar, NULL, 2)); + RZ(pthread_create(&t, NULL, &sigsafecancelstate, &n)); + + (void)pthread_barrier_wait(&bar); + + while (atomic_load_explicit(&n, memory_order_relaxed)) { + pthread_kill(t, SIGUSR1); + atomic_store_explicit(&n, + atomic_load_explicit(&n, memory_order_relaxed) - 1, + memory_order_relaxed); + } + + alarm(1); + RZ(pthread_join(t, &result)); + ATF_CHECK_MSG(result == NULL, "result=%p", result); + ATF_CHECK(cleanup_done); +} + +static void * +testcancel_loop(void *cookie) +{ + + pthread_cleanup_push(&cleanup, &cleanup_done); + (void)pthread_barrier_wait(&bar); + for (;;) + pthread_testcancel(); + pthread_cleanup_pop(/*execute*/0); + + return NULL; +} + +ATF_TC(testcancel_loop); +ATF_TC_HEAD(testcancel_loop, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test pthread_testcancel in a loop"); +} +ATF_TC_BODY(testcancel_loop, tc) +{ + pthread_t t; + void *result; + + RZ(pthread_barrier_init(&bar, NULL, 2)); + RZ(pthread_create(&t, NULL, &testcancel_loop, NULL)); + + (void)pthread_barrier_wait(&bar); + RZ(pthread_cancel(t)); + + alarm(1); + RZ(pthread_join(t, &result)); + ATF_CHECK_MSG(result == PTHREAD_CANCELED, + "result=%p PTHREAD_CANCELED=%p", result, PTHREAD_CANCELED); + ATF_CHECK(cleanup_done); +} + +ATF_TP_ADD_TCS(tp) +{ + + ADD_TEST_CANCELPOINT(cancelpoint_accept); + ADD_TEST_CANCELPOINT(cancelpoint_accept4); + ADD_TEST_CANCELPOINT(cancelpoint_aio_suspend); + ADD_TEST_CANCELPOINT(cancelpoint_clock_nanosleep); + ADD_TEST_CANCELPOINT(cancelpoint_close); + ADD_TEST_CANCELPOINT(cancelpoint_cnd_timedwait); + ADD_TEST_CANCELPOINT(cancelpoint_cnd_wait); + ADD_TEST_CANCELPOINT(cancelpoint_connect); + ADD_TEST_CANCELPOINT(cancelpoint_creat); + ADD_TEST_CANCELPOINT(cancelpoint_fcntl_F_SETLKW); + ADD_TEST_CANCELPOINT(cancelpoint_fcntl_F_OFD_SETLKW); + ADD_TEST_CANCELPOINT(cancelpoint_fdatasync); + ADD_TEST_CANCELPOINT(cancelpoint_fsync); + ADD_TEST_CANCELPOINT(cancelpoint_kevent); + ADD_TEST_CANCELPOINT(cancelpoint_lockf_F_LOCK); + ADD_TEST_CANCELPOINT(cancelpoint_mq_receive); + ADD_TEST_CANCELPOINT(cancelpoint_mq_send); + ADD_TEST_CANCELPOINT(cancelpoint_mq_timedreceive); + ADD_TEST_CANCELPOINT(cancelpoint_mq_timedsend); + ADD_TEST_CANCELPOINT(cancelpoint_msgrcv); + ADD_TEST_CANCELPOINT(cancelpoint_msgsnd); + ADD_TEST_CANCELPOINT(cancelpoint_msync); + ADD_TEST_CANCELPOINT(cancelpoint_nanosleep); + ADD_TEST_CANCELPOINT(cancelpoint_open); + ADD_TEST_CANCELPOINT(cancelpoint_openat); + ADD_TEST_CANCELPOINT(cancelpoint_pause); + ADD_TEST_CANCELPOINT(cancelpoint_poll); + ADD_TEST_CANCELPOINT(cancelpoint_posix_close); + ADD_TEST_CANCELPOINT(cancelpoint_ppoll); + ADD_TEST_CANCELPOINT(cancelpoint_pread); + ADD_TEST_CANCELPOINT(cancelpoint_pselect); + ADD_TEST_CANCELPOINT(cancelpoint_pthread_cond_clockwait); + ADD_TEST_CANCELPOINT(cancelpoint_pthread_cond_timedwait); + ADD_TEST_CANCELPOINT(cancelpoint_pthread_cond_wait); + ADD_TEST_CANCELPOINT(cancelpoint_pthread_join); + ADD_TEST_CANCELPOINT(cancelpoint_pthread_testcancel); + ADD_TEST_CANCELPOINT(cancelpoint_pwrite); + ADD_TEST_CANCELPOINT(cancelpoint_read); + ADD_TEST_CANCELPOINT(cancelpoint_readv); + ADD_TEST_CANCELPOINT(cancelpoint_recv); + ADD_TEST_CANCELPOINT(cancelpoint_recvfrom); + ADD_TEST_CANCELPOINT(cancelpoint_recvmsg); + ADD_TEST_CANCELPOINT(cancelpoint_select); + ADD_TEST_CANCELPOINT(cancelpoint_send); + ADD_TEST_CANCELPOINT(cancelpoint_sendto); + ADD_TEST_CANCELPOINT(cancelpoint_sendmsg); + ADD_TEST_CANCELPOINT(cancelpoint_sigsuspend); + ADD_TEST_CANCELPOINT(cancelpoint_sigtimedwait); + ADD_TEST_CANCELPOINT(cancelpoint_sigwait); + ADD_TEST_CANCELPOINT(cancelpoint_sigwaitinfo); + ADD_TEST_CANCELPOINT(cancelpoint_sleep); + ADD_TEST_CANCELPOINT(cancelpoint_tcdrain); + ADD_TEST_CANCELPOINT(cancelpoint_thrd_join); + ADD_TEST_CANCELPOINT(cancelpoint_thrd_sleep); + ADD_TEST_CANCELPOINT(cancelpoint_wait); + ADD_TEST_CANCELPOINT(cancelpoint_waitid); + ADD_TEST_CANCELPOINT(cancelpoint_waitpid); + ADD_TEST_CANCELPOINT(cancelpoint_write); + ADD_TEST_CANCELPOINT(cancelpoint_writev); + + ATF_TP_ADD_TC(tp, cleanuppop0); + ATF_TP_ADD_TC(tp, cleanuppop1); + ATF_TP_ADD_TC(tp, cancelself_async); + ATF_TP_ADD_TC(tp, cancelself_deferred); + ATF_TP_ADD_TC(tp, defaults); + ATF_TP_ADD_TC(tp, disable_enable); + ATF_TP_ADD_TC(tp, disable_enable_async); + ATF_TP_ADD_TC(tp, disable_enable_setcanceltype_async); + ATF_TP_ADD_TC(tp, setcanceltype_async); + ATF_TP_ADD_TC(tp, notestcancel_loop_async); + ATF_TP_ADD_TC(tp, sigsafecancelstate); + ATF_TP_ADD_TC(tp, testcancel_loop); + + return atf_no_error(); +} diff --git a/lib/libpthread/t_compat_cancel.c b/lib/libpthread/t_compat_cancel.c new file mode 100644 index 000000000000..280d072b3dd6 --- /dev/null +++ b/lib/libpthread/t_compat_cancel.c @@ -0,0 +1,287 @@ +/* $NetBSD: t_compat_cancel.c,v 1.3 2025/04/25 13:09:44 riastradh Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define __LIBC12_SOURCE__ /* expose compat declarations */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_compat_cancel.c,v 1.3 2025/04/25 13:09:44 riastradh Exp $"); + +#include <sys/event.h> +#include <sys/mman.h> + +#include <aio.h> +#include <atf-c.h> +#include <mqueue.h> +#include <pthread.h> +#include <signal.h> + +#include <compat/sys/event.h> +#include <compat/sys/mman.h> +#include <compat/sys/poll.h> +#include <compat/sys/select.h> + +#include <compat/include/aio.h> +#include <compat/include/mqueue.h> +#include <compat/include/signal.h> +#include <compat/include/time.h> + +#include "cancelpoint.h" +#include "h_macros.h" + +pthread_barrier_t bar; +bool cleanup_done; + +static void +cancelpoint_compat100_kevent(void) +{ + int kq; + struct kevent100 ev; + + memset(&ev, 0, sizeof(ev)); + ev.ident = SIGUSR1; + ev.filter = EVFILT_SIGNAL; + ev.flags = EV_ADD|EV_ENABLE; + ev.fflags = 0; + ev.data = 0; + ev.udata = 0; + + RL(kq = kqueue()); + RL(__kevent50(kq, &ev, 1, NULL, 1, &(const struct timespec){0,0})); + cancelpointready(); + RL(__kevent50(kq, NULL, 0, &ev, 1, NULL)); +} + +static void +cancelpoint_compat12_msync(void) +{ + const unsigned long pagesize = sysconf(_SC_PAGESIZE); + int fd; + void *map; + + RL(fd = open("file", O_RDWR|O_CREAT, 0666)); + RL(ftruncate(fd, pagesize)); + REQUIRE_LIBC(map = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, + MAP_SHARED, fd, 0), + MAP_FAILED); + cancelpointready(); + RL(msync(map, pagesize)); +} + +static void +cancelpoint_compat50___sigtimedwait(void) +{ + sigset_t mask, omask; + siginfo_t info; + struct timespec50 t = {.tv_sec = 2, .tv_nsec = 0}; + + RL(__sigfillset14(&mask)); + RL(__sigprocmask14(SIG_BLOCK, &mask, &omask)); + cancelpointready(); + RL(__sigtimedwait(&omask, &info, &t)); +} + +static void +cancelpoint_compat50_aio_suspend(void) +{ + int fd[2]; + char buf[32]; + struct aiocb aio = { + .aio_offset = 0, + .aio_buf = buf, + .aio_nbytes = sizeof(buf), + .aio_fildes = -1, + }; + const struct aiocb *const aiolist[] = { &aio }; + + RL(pipe(fd)); + aio.aio_fildes = fd[0]; + RL(aio_read(&aio)); + cancelpointready(); + RL(aio_suspend(aiolist, __arraycount(aiolist), NULL)); +} + +static void +cancelpoint_compat50_kevent(void) +{ + int kq; + struct kevent100 ev; + + memset(&ev, 0, sizeof(ev)); + ev.ident = SIGUSR1; + ev.filter = EVFILT_SIGNAL; + ev.flags = EV_ADD|EV_ENABLE; + ev.fflags = 0; + ev.data = 0; + ev.udata = 0; + + RL(kq = kqueue()); + RL(kevent(kq, &ev, 1, NULL, 1, &(const struct timespec50){0,0})); + cancelpointready(); + RL(kevent(kq, NULL, 0, &ev, 1, NULL)); +} + +static void +cancelpoint_compat50_mq_timedreceive(void) +{ + mqd_t mq; + char buf[32]; + struct timespec50 t = {.tv_sec = 2, .tv_nsec = 0}; + + RL(mq = mq_open("mq", O_RDWR|O_CREAT, 0666, NULL)); + cancelpointready(); + RL(mq_timedreceive(mq, buf, sizeof(buf), NULL, &t)); +} + +static void +cancelpoint_compat50_mq_timedsend(void) +{ + mqd_t mq; + char buf[32] = {0}; + struct timespec50 t = {.tv_sec = 2, .tv_nsec = 0}; + + RL(mq = mq_open("mq", O_RDWR|O_CREAT, 0666, NULL)); + cancelpointready(); + RL(mq_timedsend(mq, buf, sizeof(buf), 0, &t)); +} + +static void +cancelpoint_compat50_nanosleep(void) +{ + struct timespec50 t = {.tv_sec = 2, .tv_nsec = 0}; + + cancelpointready(); + RL(nanosleep(&t, NULL)); +} + +static void +cancelpoint_compat50_pollts(void) +{ + int fd[2]; + struct pollfd pfd; + struct timespec50 t = {.tv_sec = 2, .tv_nsec = 0}; + + RL(pipe(fd)); + pfd.fd = fd[0]; + pfd.events = POLLIN; + cancelpointready(); + RL(pollts(&pfd, 1, &t, NULL)); +} + +static void +cancelpoint_compat50_pselect(void) +{ + int fd[2]; + fd_set readfd; + struct timespec50 t = {.tv_sec = 2, .tv_nsec = 0}; + + FD_ZERO(&readfd); + + RL(pipe(fd)); + FD_SET(fd[0], &readfd); + cancelpointready(); + RL(pselect(fd[0] + 1, &readfd, NULL, NULL, &t, NULL)); +} + +static void +cancelpoint_compat50_select(void) +{ + int fd[2]; + fd_set readfd; + struct timeval50 t = {.tv_sec = 1, .tv_usec = 0}; + + FD_ZERO(&readfd); + + RL(pipe(fd)); + FD_SET(fd[0], &readfd); + cancelpointready(); + RL(select(fd[0] + 1, &readfd, NULL, NULL, &t)); +} + +static void +cancelpoint_compat13_sigsuspend(void) +{ + sigset13_t mask, omask; + + RL(sigfillset(&mask)); + RL(sigprocmask(SIG_BLOCK, &mask, &omask)); + cancelpointready(); + RL(sigsuspend(&omask)); +} + +static void +cancelpoint_compat50_sigtimedwait(void) +{ + sigset_t mask, omask; + siginfo_t info; + struct timespec50 t = {.tv_sec = 2, .tv_nsec = 0}; + + RL(__sigfillset14(&mask)); + RL(__sigprocmask14(SIG_BLOCK, &mask, &omask)); + cancelpointready(); + RL(sigtimedwait(&omask, &info, &t)); +} + +TEST_CANCELPOINT(cancelpoint_compat100_kevent, __nothing) +TEST_CANCELPOINT(cancelpoint_compat12_msync, __nothing) +TEST_CANCELPOINT(cancelpoint_compat13_sigsuspend, + atf_tc_expect_signal(-1, "PR lib/59240: POSIX.1-2024:" + " cancellation point audit")) +TEST_CANCELPOINT(cancelpoint_compat50___sigtimedwait, + atf_tc_expect_signal(-1, "PR lib/59240: POSIX.1-2024:" + " cancellation point audit")) +TEST_CANCELPOINT(cancelpoint_compat50_aio_suspend, __nothing) +TEST_CANCELPOINT(cancelpoint_compat50_kevent, __nothing) +TEST_CANCELPOINT(cancelpoint_compat50_mq_timedreceive, __nothing) +TEST_CANCELPOINT(cancelpoint_compat50_mq_timedsend, __nothing) +TEST_CANCELPOINT(cancelpoint_compat50_nanosleep, __nothing) +TEST_CANCELPOINT(cancelpoint_compat50_pollts, __nothing) +TEST_CANCELPOINT(cancelpoint_compat50_pselect, __nothing) +TEST_CANCELPOINT(cancelpoint_compat50_select, __nothing) +TEST_CANCELPOINT(cancelpoint_compat50_sigtimedwait, + atf_tc_expect_signal(-1, "PR lib/59240: POSIX.1-2024:" + " cancellation point audit")) + +ATF_TP_ADD_TCS(tp) +{ + + ADD_TEST_CANCELPOINT(cancelpoint_compat100_kevent); + ADD_TEST_CANCELPOINT(cancelpoint_compat12_msync); + ADD_TEST_CANCELPOINT(cancelpoint_compat13_sigsuspend); + ADD_TEST_CANCELPOINT(cancelpoint_compat50___sigtimedwait); + ADD_TEST_CANCELPOINT(cancelpoint_compat50_aio_suspend); + ADD_TEST_CANCELPOINT(cancelpoint_compat50_kevent); + ADD_TEST_CANCELPOINT(cancelpoint_compat50_mq_timedreceive); + ADD_TEST_CANCELPOINT(cancelpoint_compat50_mq_timedsend); + ADD_TEST_CANCELPOINT(cancelpoint_compat50_nanosleep); + ADD_TEST_CANCELPOINT(cancelpoint_compat50_pollts); + ADD_TEST_CANCELPOINT(cancelpoint_compat50_pselect); + ADD_TEST_CANCELPOINT(cancelpoint_compat50_select); + ADD_TEST_CANCELPOINT(cancelpoint_compat50_sigtimedwait); + + return atf_no_error(); +} diff --git a/lib/libpthread/t_stack.c b/lib/libpthread/t_stack.c new file mode 100644 index 000000000000..1c5050d5fd4c --- /dev/null +++ b/lib/libpthread/t_stack.c @@ -0,0 +1,491 @@ +/* $NetBSD: t_stack.c,v 1.6 2023/11/28 02:54:33 riastradh Exp $ */ + +/*- + * Copyright (c) 2023 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _KMEMUSER /* __MACHINE_STACK_GROWS_UP */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_stack.c,v 1.6 2023/11/28 02:54:33 riastradh Exp $"); + +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/types.h> + +#include <uvm/uvm_param.h> /* VM_THREAD_GUARD_SIZE */ + +#include <atf-c.h> +#include <pthread.h> +#include <setjmp.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> + +#include "h_macros.h" + +struct jmp_ctx { + jmp_buf buf; +}; + +/* + * State used by various tests. + */ +struct ctx { + size_t size; /* default stack size */ + size_t guardsize; /* default guard size */ + void *addr; /* user-allocated stack */ + pthread_key_t jmp_key; /* jmp_ctx to return from SIGSEGV handler */ +} ctx, *C = &ctx; + +/* + * getdefaultstacksize() + * + * Return the default stack size for threads created with + * pthread_create. + */ +static size_t +getdefaultstacksize(void) +{ + pthread_attr_t attr; + size_t stacksize; + + /* + * When called from the main thread, this returns the default + * stack size (pthread__stacksize) used for pthreads. + */ + RZ(pthread_getattr_np(pthread_self(), &attr)); + RZ(pthread_attr_getstacksize(&attr, &stacksize)); + RZ(pthread_attr_destroy(&attr)); + + /* + * Verify that the assumption above holds. + */ + extern size_t pthread__stacksize; /* pthread_int.h */ + ATF_CHECK_EQ_MSG(stacksize, pthread__stacksize, + "stacksize=%zu pthread__stacksize=%zu", + stacksize, pthread__stacksize); + + return stacksize; +} + +/* + * getnondefaultstacksize() + * + * Return a stack size that is not the default stack size for + * threads created with pthread_create. + */ +static size_t +getnondefaultstacksize(void) +{ + + return getdefaultstacksize() + sysconf(_SC_PAGESIZE); +} + +/* + * getdefaultguardsize() + * + * Return the default guard size for threads created with + * pthread_create. + */ +static size_t +getdefaultguardsize(void) +{ + const int mib[2] = { CTL_VM, VM_THREAD_GUARD_SIZE }; + unsigned guardsize; + size_t len = sizeof(guardsize); + + RL(sysctl(mib, __arraycount(mib), &guardsize, &len, NULL, 0)); + ATF_REQUIRE_EQ_MSG(len, sizeof(guardsize), + "len=%zu sizeof(guardsize)=%zu", len, sizeof(guardsize)); + + /* + * Verify this matches what libpthread determined. + */ + extern size_t pthread__guardsize; /* pthread_int.h */ + ATF_CHECK_EQ_MSG(guardsize, pthread__guardsize, + "guardsize=%u pthread__guardsize=%zu", + guardsize, pthread__guardsize); + + return guardsize; +} + +/* + * alloc(nbytes) + * + * Allocate an nbytes-long page-aligned read/write region and + * return a pointer to it. Abort the test if allocation fails, so + * if this function returns it succeeds. + */ +static void * +alloc(size_t nbytes) +{ + void *ptr; + + REQUIRE_LIBC((ptr = mmap(/*hint*/NULL, nbytes, + PROT_READ|PROT_WRITE, MAP_ANON, /*fd*/-1, /*offset*/0)), + MAP_FAILED); + + return ptr; +} + +/* + * init(stacksize) + * + * Initialize state used by various tests with the specified + * stacksize. + * + * Make sure to allocate enough space that even if there shouldn't + * be a stack guard (i.e., it should be empty), adjusting the + * requested bounds by the default stack guard size will leave us + * inside allocated memory. + */ +static void +init(size_t stacksize) +{ + + C->size = stacksize; + C->guardsize = getdefaultguardsize(); + C->addr = alloc(C->size + C->guardsize); + RZ(pthread_key_create(&C->jmp_key, NULL)); +} + +/* + * stack_pointer() + * + * Return the stack pointer. This is used to verify whether the + * stack pointer lie within a certain address range. + */ +static __noinline void * +stack_pointer(void) +{ + return __builtin_frame_address(0); +} + +/* + * sigsegv_ok(signo) + * + * Signal handler for SIGSEGV to return to the jmp ctx, to verify + * that SIGSEGV happened without crashing. + */ +static void +sigsegv_ok(int signo) +{ + struct jmp_ctx *j = pthread_getspecific(C->jmp_key); + + longjmp(j->buf, 1); +} + +/* + * checksigsegv(p) + * + * Verify that reading *p triggers SIGSEGV. Fails test nonfatally + * if SIGSEGV doesn't happen. + */ +static void +checksigsegv(const char *p) +{ + struct jmp_ctx j; + struct sigaction act, oact; + volatile struct sigaction oactsave; + volatile char v; + + memset(&act, 0, sizeof(act)); + act.sa_handler = &sigsegv_ok; + + if (setjmp(j.buf) == 0) { + pthread_setspecific(C->jmp_key, &j); + RL(sigaction(SIGSEGV, &act, &oact)); + oactsave = oact; + v = *p; /* trigger SIGSEGV */ + atf_tc_fail_nonfatal("failed to trigger SIGSEGV at %p", p); + } else { + /* return from SIGSEGV handler */ + oact = oactsave; + } + RL(sigaction(SIGSEGV, &oact, NULL)); + pthread_setspecific(C->jmp_key, NULL); + + (void)v; /* suppress unused variable warnings */ +} + +/* + * checknosigsegv(p) + * + * Verify that reading *p does not trigger SIGSEGV. Fails test + * nonfatally if SIGSEGV happens. + */ +static void +checknosigsegv(const char *p) +{ + struct jmp_ctx j; + struct sigaction act, oact; + volatile struct sigaction oactsave; + volatile char v; + + memset(&act, 0, sizeof(act)); + act.sa_handler = &sigsegv_ok; + + if (setjmp(j.buf) == 0) { + pthread_setspecific(C->jmp_key, &j); + RL(sigaction(SIGSEGV, &act, &oact)); + oactsave = oact; + v = *p; /* better not trigger SIGSEGV */ + } else { + /* return from SIGSEGV handler */ + atf_tc_fail_nonfatal("spuriously triggered SIGSEGV at %p", p); + oact = oactsave; + } + RL(sigaction(SIGSEGV, &oact, NULL)); + pthread_setspecific(C->jmp_key, NULL); + + (void)v; /* suppress unused variable warnings */ +} + +/* + * checkguardaccessthread(cookie) + * + * Thread start routine that verifies it has access to the start + * and end of its stack, according to pthread_attr_getstack, and + * _does not_ have access to the start or end of its stack guard, + * above the stack (in stack growth direction) by + * pthread_attr_getguardsize bytes. + */ +static void * +checkguardaccessthread(void *cookie) +{ + pthread_t t = pthread_self(); + pthread_attr_t attr; + void *addr, *guard; + size_t size, guardsize; + + /* + * Get the the stack and stack guard parameters. + */ + RZ(pthread_getattr_np(t, &attr)); + RZ(pthread_attr_getstack(&attr, &addr, &size)); + RZ(pthread_attr_getguardsize(&attr, &guardsize)); + + /* + * Determine where the guard starts in virtual address space + * (not in stack growth direction). + */ +#ifdef __MACHINE_STACK_GROWS_UP + guard = (char *)addr + size; +#else + guard = (char *)addr - guardsize; +#endif + + /* + * Verify access to the start and end of the stack itself. + */ + checknosigsegv(addr); + checknosigsegv((char *)addr + size - 1); + + /* + * Verify no access to the start or end of the stack guard. + */ + checksigsegv(guard); + checksigsegv((char *)guard + guardsize - 1); + + return NULL; +} + +/* + * checkaddraccessthread(cookie) + * + * Thread start routine that verifies its stack is [C->addr, + * C->addr + C->size), according to pthread_attr_getstack and + * pthread_addr_getstacksize, and verifies it has access to that + * whole range. + */ +static void * +checkaddraccessthread(void *cookie) +{ + pthread_t t = pthread_self(); + pthread_attr_t attr; + void *sp; + void *addr; + size_t size, size0; + + /* + * Verify the stack pointer lies somewhere in the allocated + * range. + */ + sp = stack_pointer(); + ATF_CHECK_MSG(C->addr <= sp, "sp=%p not in [%p,%p + 0x%zu) = [%p,%p)", + sp, C->addr, C->addr, C->size, C->addr, (char *)C->addr + C->size); + ATF_CHECK_MSG(sp <= (void *)((char *)C->addr + C->size), + "sp=%p not in [%p,%p + 0x%zu) = [%p,%p)", + sp, C->addr, C->addr, C->size, C->addr, (char *)C->addr + C->size); + + /* + * Verify, if not that, then the stack pointer at least lies + * within the extra buffer we allocated for slop to address a + * bug NetBSD libpthread used to have of spuriously adding the + * guard size to a user-allocated stack address. This is + * ATF_REQUIRE, not ATF_CHECK, because if this doesn't hold, we + * might be clobbering some other memory like malloc pages, + * causing the whole test to crash with useless diagnostics. + */ + ATF_REQUIRE_MSG(sp <= (void *)((char *)C->addr + C->size + + C->guardsize), + "sp=%p not even in buffer [%p,%p + 0x%zu + 0x%zu) = [%p,%p)", + sp, C->addr, C->addr, C->size, C->guardsize, + C->addr, (char *)C->addr + C->size + C->guardsize); + + /* + * Get the stack parameters -- both via pthread_attr_getstack + * and via pthread_attr_getstacksize, to make sure they agree + * -- and verify that they are what we expect from the caller. + */ + RZ(pthread_getattr_np(t, &attr)); + RZ(pthread_attr_getstack(&attr, &addr, &size)); + RZ(pthread_attr_getstacksize(&attr, &size0)); + ATF_CHECK_EQ_MSG(C->addr, addr, "expected %p actual %p", + C->addr, addr); + ATF_CHECK_EQ_MSG(C->size, size, "expected %zu actual %zu", + C->size, size); + ATF_CHECK_EQ_MSG(C->size, size0, "expected %zu actual %zu", + C->size, size0); + + /* + * Verify that we have access to what we expect the stack to + * be. + */ + checknosigsegv(C->addr); + checknosigsegv((char *)C->addr + C->size - 1); + + return NULL; +} + +ATF_TC(stack1); +ATF_TC_HEAD(stack1, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test allocating and reallocating a thread with a user stack"); +} +ATF_TC_BODY(stack1, tc) +{ + pthread_attr_t attr; + pthread_t t, t2; + + /* + * Allocate a stack with a non-default size to verify + * libpthread didn't choose the stack size for us. + */ + init(getnondefaultstacksize()); + + /* + * Create a thread with user-allocated stack of a non-default + * size to verify the stack size and access. + */ + RZ(pthread_attr_init(&attr)); + RZ(pthread_attr_setstack(&attr, C->addr, C->size)); + RZ(pthread_create(&t, &attr, &checkaddraccessthread, C)); + RZ(pthread_join(t, NULL)); + + /* + * Create another thread with the same parameters, and verify + * that (a) it was recycled, and (b) it works the same way. + */ + RZ(pthread_create(&t2, &attr, &checkaddraccessthread, C)); + ATF_CHECK_EQ_MSG(t, t2, "t=%p t2=%p", t, t2); /* NetBSD recycles */ + RZ(pthread_join(t2, NULL)); +} + +ATF_TC(stack2); +ATF_TC_HEAD(stack2, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test reallocating a thread with a newly self-allocated stack"); +} +ATF_TC_BODY(stack2, tc) +{ + pthread_attr_t attr, attr2; + size_t size, size2; + pthread_t t, t2; + + /* + * Allocate a stack with the default size so that we verify + * when libpthread reuses the thread, it doesn't inadvertently + * reuse the libpthread-allocated stack too and instead + * correctly uses our user-allocated stack. + */ + init(getdefaultstacksize()); + + /* + * Create a thread with a libpthread-allocated stack that + * verifies + * (a) access to its own stack, and + * (b) no access to its own guard pages; + * then get its attributes and wait for it to complete. + */ + RZ(pthread_create(&t, NULL, &checkguardaccessthread, C)); + RZ(pthread_getattr_np(t, &attr)); + RZ(pthread_join(t, NULL)); + + /* + * Create a thread with a user-allocated stack that verifies + * (a) stack addr/size match request, and + * (b) access to the requested stack, + * and confirm that the first thread was recycled -- not part + * of POSIX semantics, but part of NetBSD's implementation; + * this way, we verify that, even though the thread is + * recycled, the thread's stack is set to the user-allocated + * stack and access to it works as expected. Then wait for it + * to complete. + */ + RZ(pthread_attr_init(&attr2)); + RZ(pthread_attr_setstack(&attr2, C->addr, C->size)); + RZ(pthread_create(&t2, &attr2, &checkaddraccessthread, C)); + ATF_CHECK_EQ_MSG(t, t2, "t=%p t2=%p", t, t2); /* NetBSD recycles */ + RZ(pthread_join(t2, NULL)); + + /* + * Verify that the libpthread-allocated stack and + * user-allocated stack had the same size, since we chose the + * default size. + * + * Note: We can't say anything about the guard size, because + * with pthread_attr_setstack, the guard size is ignored, and + * it's not clear from POSIX whether any meaningful guard size + * is stored for retrieval with pthread_attr_getguardsize in + * attributes with pthread_attr_setstack. + */ + RZ(pthread_attr_getstacksize(&attr, &size)); + RZ(pthread_attr_getstacksize(&attr2, &size2)); + ATF_CHECK_EQ_MSG(size, size2, "size=%zu size2=%zu", size, size2); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, stack1); + ATF_TP_ADD_TC(tp, stack2); + + return atf_no_error(); +} diff --git a/lib/libpthread/weak/Makefile b/lib/libpthread/weak/Makefile new file mode 100644 index 000000000000..f7cdd75c2723 --- /dev/null +++ b/lib/libpthread/weak/Makefile @@ -0,0 +1,25 @@ +# $NetBSD: Makefile,v 1.2 2025/10/18 20:27:23 riastradh Exp $ +# + +TESTSDIR= ${TESTSBASE}/lib/libpthread/weak + +TESTS_C+= t_pthread_weak_nothread +TESTS_C+= t_pthread_weak_threaded + +CPPFLAGS+= -I${.CURDIR}/lib + +.include <bsd.own.mk> # PRINTOBJDIR + +.if !defined(H_PTHREAD_WEAK_OBJDIR) +H_PTHREAD_WEAK_OBJDIR!= cd ${.CURDIR}/lib && ${PRINTOBJDIR} +.MAKEOVERRIDES+= H_PTHREAD_WEAK_OBJDIR +.endif + +LDADD+= -L${H_PTHREAD_WEAK_OBJDIR} +LDADD+= -Wl,-rpath,${TESTSBASE}/lib/libpthread/weak +LDADD+= -lh_pthread_weak +LDADD.t_pthread_weak_threaded+= -lpthread + +SUBDIR+= lib + +.include <bsd.test.mk> diff --git a/lib/libpthread/weak/Makefile.inc b/lib/libpthread/weak/Makefile.inc new file mode 100644 index 000000000000..921a499b55ba --- /dev/null +++ b/lib/libpthread/weak/Makefile.inc @@ -0,0 +1 @@ +.include "${.PARSEDIR}/../../Makefile.inc" diff --git a/lib/libpthread/weak/lib/Makefile b/lib/libpthread/weak/lib/Makefile new file mode 100644 index 000000000000..0976a72efd27 --- /dev/null +++ b/lib/libpthread/weak/lib/Makefile @@ -0,0 +1,21 @@ +# $NetBSD: Makefile,v 1.2 2026/01/21 17:57:27 christos Exp $ +# + +MKPROFILE= no # XXX hack -- should be NOPROFILE +NOLINT= # defined +NOPICINSTALL= # defined +NOMAN= # defined +NOSTATICLIB= # defined + +LIB= h_pthread_weak +SRCS+= h_pthread_weak.c + +LDADD+= -latf-c + +LIBDIR= ${TESTSBASE}/lib/libpthread/weak +SHLIBDIR= ${TESTSBASE}/lib/libpthread/weak +SHLIB_MAJOR= 1 + +LIBISCXX= yes + +.include <bsd.lib.mk> diff --git a/lib/libpthread/weak/lib/h_pthread_weak.c b/lib/libpthread/weak/lib/h_pthread_weak.c new file mode 100644 index 000000000000..d8b9e624c07d --- /dev/null +++ b/lib/libpthread/weak/lib/h_pthread_weak.c @@ -0,0 +1,83 @@ +/* $NetBSD: h_pthread_weak.c,v 1.1 2025/10/06 13:16:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_pthread_weak.c,v 1.1 2025/10/06 13:16:44 riastradh Exp $"); + +#define _NETBSD_PTHREAD_CREATE_WEAK + +#include "h_pthread_weak.h" + +#include <atf-c.h> +#include <pthread.h> + +#include "h_macros.h" + +static void * +start(void *cookie) +{ + return cookie; +} + +void +test_mutex(void) +{ + pthread_mutex_t mtx; + + RZ(pthread_mutex_init(&mtx, NULL)); + RZ(pthread_mutex_lock(&mtx)); + RZ(pthread_mutex_unlock(&mtx)); + RZ(pthread_mutex_destroy(&mtx)); +} + +void +test_thread_creation(void) +{ + int cookie = 123; + pthread_attr_t attr; + pthread_t t; + void *result; + + RZ(pthread_attr_init(&attr)); + RZ(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); + RZ(pthread_create(&t, NULL, &start, &cookie)); + RZ(pthread_attr_destroy(&attr)); + RZ(pthread_join(t, &result)); + ATF_CHECK_EQ(result, &cookie); +} + +void +test_thread_creation_failure(void) +{ + int cookie = 123; + pthread_t t; + int error; + + error = pthread_create(&t, NULL, &start, &cookie); + ATF_CHECK_MSG(error != 0, "pthread_create unexpectedly succeeded"); +} diff --git a/lib/libpthread/weak/lib/h_pthread_weak.h b/lib/libpthread/weak/lib/h_pthread_weak.h new file mode 100644 index 000000000000..b970d2b020c6 --- /dev/null +++ b/lib/libpthread/weak/lib/h_pthread_weak.h @@ -0,0 +1,36 @@ +/* $NetBSD: h_pthread_weak.h,v 1.1 2025/10/06 13:16:44 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef H_PTHREAD_WEAK_H +#define H_PTHREAD_WEAK_H + +void test_mutex(void); +void test_thread_creation(void); +void test_thread_creation_failure(void); + +#endif /* H_PTHREAD_WEAK_H */ diff --git a/lib/libpthread/weak/t_pthread_weak_nothread.c b/lib/libpthread/weak/t_pthread_weak_nothread.c new file mode 100644 index 000000000000..a5447b695dbb --- /dev/null +++ b/lib/libpthread/weak/t_pthread_weak_nothread.c @@ -0,0 +1,64 @@ +/* $NetBSD: t_pthread_weak_nothread.c,v 1.1 2025/10/18 20:27:23 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_pthread_weak_nothread.c,v 1.1 2025/10/18 20:27:23 riastradh Exp $"); + +#include <atf-c.h> + +#include "h_pthread_weak.h" + +ATF_TC(mutex); +ATF_TC_HEAD(mutex, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test mutex usage in library with _NETBSD_PTHREAD_CREATE_WEAK"); +} +ATF_TC_BODY(mutex, tc) +{ + test_mutex(); +} + +ATF_TC(thread_creation_failure); +ATF_TC_HEAD(thread_creation_failure, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test pthread_create via library fails in no-thread application"); +} +ATF_TC_BODY(thread_creation_failure, tc) +{ + test_thread_creation_failure(); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, mutex); + ATF_TP_ADD_TC(tp, thread_creation_failure); + + return atf_no_error(); +} diff --git a/lib/libpthread/weak/t_pthread_weak_threaded.c b/lib/libpthread/weak/t_pthread_weak_threaded.c new file mode 100644 index 000000000000..70c649ea13b6 --- /dev/null +++ b/lib/libpthread/weak/t_pthread_weak_threaded.c @@ -0,0 +1,64 @@ +/* $NetBSD: t_pthread_weak_threaded.c,v 1.1 2025/10/18 20:27:23 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_pthread_weak_threaded.c,v 1.1 2025/10/18 20:27:23 riastradh Exp $"); + +#include <atf-c.h> + +#include "h_pthread_weak.h" + +ATF_TC(mutex); +ATF_TC_HEAD(mutex, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test mutex usage in library with _NETBSD_PTHREAD_CREATE_WEAK"); +} +ATF_TC_BODY(mutex, tc) +{ + test_mutex(); +} + +ATF_TC(thread_creation); +ATF_TC_HEAD(thread_creation, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test pthread_create via library in threaded application"); +} +ATF_TC_BODY(thread_creation, tc) +{ + test_thread_creation(); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, mutex); + ATF_TP_ADD_TC(tp, thread_creation); + + return atf_no_error(); +} diff --git a/lib/libstdc++/Makefile b/lib/libstdc++/Makefile new file mode 100644 index 000000000000..3562d78dd70c --- /dev/null +++ b/lib/libstdc++/Makefile @@ -0,0 +1,12 @@ +# $NetBSD: Makefile,v 1.1 2024/04/28 01:21:27 riastradh Exp $ +# + +NOMAN= # defined + +TESTSDIR= ${TESTSBASE}/lib/libstdc++ +BINDIR= ${TESTSDIR} + +TESTS_SH+= t_sync_with_stdio +PROG_CXX+= h_cin_nosync + +.include <bsd.test.mk> diff --git a/lib/libstdc++/h_cin_nosync.cc b/lib/libstdc++/h_cin_nosync.cc new file mode 100644 index 000000000000..a934e2c67415 --- /dev/null +++ b/lib/libstdc++/h_cin_nosync.cc @@ -0,0 +1,40 @@ +/* $NetBSD: h_cin_nosync.cc,v 1.1 2024/04/28 01:21:27 riastradh Exp $ */ + +/*- + * Copyright (c) 2024 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <iostream> + +int +main(void) +{ + char buf[128]; + + std::ios::sync_with_stdio(false); + std::cin.read(buf, sizeof(buf)); + std::cout << std::cin.gcount() << std::endl; + return 0; +} diff --git a/lib/libstdc++/t_sync_with_stdio.sh b/lib/libstdc++/t_sync_with_stdio.sh new file mode 100644 index 000000000000..fe76c49b988f --- /dev/null +++ b/lib/libstdc++/t_sync_with_stdio.sh @@ -0,0 +1,41 @@ +# $NetBSD: t_sync_with_stdio.sh,v 1.2 2024/05/20 11:20:53 riastradh Exp $ +# +# Copyright (c) 2024 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +cin_nosync_head() +{ + atf_set descr "Check cin works after std::ios::sync_with_stdio(false)" +} +cin_nosync_body() +{ + echo hello >in + atf_check -o inline:'6\n' "$(atf_get_srcdir)"/h_cin_nosync <in +} + +atf_init_test_cases() +{ + atf_add_test_case cin_nosync +} diff --git a/lib/libutil/t_strpct.c b/lib/libutil/t_strpct.c new file mode 100644 index 000000000000..c061ae152321 --- /dev/null +++ b/lib/libutil/t_strpct.c @@ -0,0 +1,202 @@ +/* $NetBSD: t_strpct.c,v 1.2 2025/05/03 07:22:52 rillig Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code was contributed to The NetBSD Foundation by Roland Illig. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2025\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_strpct.c,v 1.2 2025/05/03 07:22:52 rillig Exp $"); + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <util.h> + +#include <atf-c.h> + +static void +check_strspct(const char *file, unsigned line, + size_t bufsiz, intmax_t num, intmax_t den, size_t digits, + const char *want) +{ + char buf[128]; + + ATF_REQUIRE_MSG(bufsiz < sizeof(buf) - 2, "bufsiz too large"); + memset(buf, '>', sizeof(buf)); + buf[0] = '<'; + buf[sizeof(buf) - 1] = '\0'; + + const char *have = strspct(buf + 1, bufsiz, num, den, digits); + + ATF_REQUIRE_MSG(buf[0] == '<', + "out-of-bounds write before"); + ATF_REQUIRE_MSG(buf[1 + bufsiz] == '>', + "out-of-bounds write after"); + ATF_REQUIRE_MSG(have == buf + 1, + "have != buf"); + ATF_CHECK_MSG(bufsiz > 0 ? strcmp(have, want) == 0 : true, + "%s:%u: want \"%s\", have \"%s\"", + file, line, want, have); +} + +#define h_strspct(bufsiz, num, den, digits, want) \ + check_strspct(__FILE__, __LINE__, bufsiz, num, den, digits, want) + +static void +check_strpct(const char *file, unsigned line, + size_t bufsiz, uintmax_t num, uintmax_t den, size_t digits, + const char *want) +{ + char buf[128]; + + ATF_REQUIRE_MSG(bufsiz < sizeof(buf) - 2, "bufsiz too large"); + memset(buf, '>', sizeof(buf)); + buf[0] = '<'; + buf[sizeof(buf) - 1] = '\0'; + + const char *have = strpct(buf + 1, bufsiz, num, den, digits); + + ATF_REQUIRE_MSG(buf[0] == '<', + "out-of-bounds write before"); + ATF_REQUIRE_MSG(buf[1 + bufsiz] == '>', + "out-of-bounds write after"); + ATF_REQUIRE_MSG(have == buf + 1, + "have != buf"); + ATF_CHECK_MSG(bufsiz > 0 ? strcmp(have, want) == 0 : true, + "%s:%u: want \"%s\", have \"%s\"", + file, line, want, have); +} + +#define h_strpct(bufsiz, num, den, digits, want) \ + check_strpct(__FILE__, __LINE__, bufsiz, num, den, digits, want) + +ATF_TC(strspct); +ATF_TC_HEAD(strspct, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks strspct(3)"); +} +ATF_TC_BODY(strspct, tc) +{ + + // Very small buffers. + h_strspct(0, 0, 0, 0, ""); + h_strspct(1, 0, 0, 0, ""); + + // Small buffers. + h_strspct(2, 1, 40, 0, "2"); + h_strspct(3, 1, 40, 0, "2"); + h_strspct(3, 1, 40, 1, "2."); + h_strspct(4, 1, 40, 1, "2.5"); + h_strspct(4, 8, 40, 1, "20."); + h_strspct(6, 1, 5, 1, "20.0"); + h_strspct(100, 1, 5, 5, "20.00000"); + h_strspct( 5, 11223344, 100, 10, "1122"); + h_strspct(10, 11223344, 100, 10, "11223344."); + h_strspct(11, 11223344, 100, 10, "11223344.0"); + + // Small buffers with negative numbers. + h_strspct(1, -1, 40, 0, ""); + h_strspct(2, -1, 40, 0, "-"); + h_strspct(3, -1, 40, 0, "-2"); + h_strspct(3, -1, 40, 1, "-2"); + h_strspct(4, -1, 40, 1, "-2."); + h_strspct(5, -1, 40, 1, "-2.5"); + h_strspct(4, -8, 40, 1, "-20"); + h_strspct(5, -8, 40, 1, "-20."); + h_strspct(6, -1, 5, 1, "-20.0"); + h_strspct(100, -1, 5, 5, "-20.00000"); + h_strspct( 5, -11223344, 100, 10, "-112"); + h_strspct(10, -11223344, 100, 10, "-11223344"); + h_strspct(11, -11223344, 100, 10, "-11223344."); + h_strspct(12, -11223344, 100, 10, "-11223344.0"); + + // Percentages are always rounded towards zero. + h_strspct(6, 1, 6, 1, "16.6"); + h_strspct(7, -1, 6, 1, "-16.6"); + h_strspct(7, 1, -6, 1, "-16.6"); + h_strspct(7, -1, -6, 1, "16.6"); + h_strspct(100, 1, 7, 20, "14.28571428571428571428"); + + // Big numbers. + h_strspct(100, INTMAX_MAX, INTMAX_MAX, 0, "100"); + h_strspct(100, INTMAX_MIN, INTMAX_MIN, 25, "100.0000000000000000000000000"); + h_strspct(100, INTMAX_MIN, INTMAX_MAX, 25, "-100.0000000000000000108420217"); + h_strspct(100, INTMAX_MAX, INTMAX_MIN, 25, "-99.9999999999999999891579782"); + h_strspct(100, INTMAX_MAX, INTMAX_MAX, 25, "100.0000000000000000000000000"); +} + +ATF_TC(strpct); +ATF_TC_HEAD(strpct, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks strpct(3)"); +} +ATF_TC_BODY(strpct, tc) +{ + + // Small buffers. + h_strpct(0, 0, 0, 0, ""); + h_strpct(1, 0, 0, 0, ""); + h_strpct(2, 0, 0, 0, "0"); + h_strpct(3, 0, 0, 0, "0"); + h_strpct(3, 0, 0, 1, "0."); + h_strpct(4, 0, 0, 1, "0.0"); + h_strpct(4, 1, 5, 1, "20."); + h_strpct(6, 1, 5, 1, "20.0"); + h_strpct(100, 1, 5, 5, "20.00000"); + + h_strpct(100, 1, 7, 20, "14.28571428571428571428"); + + h_strpct( 5, 11223344, 100, 10, "1122"); + h_strpct(10, 11223344, 100, 10, "11223344."); + h_strpct(11, 11223344, 100, 10, "11223344.0"); + + h_strpct(100, UINTMAX_MAX, UINTMAX_MAX, 0, "100"); + h_strpct(100, UINTMAX_MAX, UINTMAX_MAX, 1, "100.0"); + h_strpct(100, UINTMAX_MAX, UINTMAX_MAX, 5, "100.00000"); + h_strpct(100, UINTMAX_MAX, UINTMAX_MAX, 10, "100.0000000000"); + h_strpct(100, UINTMAX_MAX, UINTMAX_MAX, 15, "100.000000000000000"); + h_strpct(100, UINTMAX_MAX, UINTMAX_MAX, 20, "100.00000000000000000000"); + h_strpct(100, UINTMAX_MAX, UINTMAX_MAX, 25, "100.0000000000000000000000000"); + + h_strpct(100, UINTMAX_MAX - 1, UINTMAX_MAX, 25, "99.9999999999999999945789891"); + h_strpct(100, 1, (UINTMAX_MAX >> 1) + 1, 70, + "0.0000000000000000108420217248550443400745280086994171142578125000000000"); + h_strpct(100, UINTMAX_MAX, 1, 10, "1844674407370955161500.0000000000"); + h_strpct(100, 1, UINTMAX_MAX, 30, "0.000000000000000005421010862427"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, strspct); + ATF_TP_ADD_TC(tp, strpct); + + return atf_no_error(); +} diff --git a/libexec/ld.elf_so/h_r_rel.c b/libexec/ld.elf_so/h_r_rel.c new file mode 100644 index 000000000000..17cece208ebe --- /dev/null +++ b/libexec/ld.elf_so/h_r_rel.c @@ -0,0 +1,147 @@ +/* $NetBSD: h_r_rel.c,v 1.2 2025/12/21 19:08:09 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: h_r_rel.c,v 1.2 2025/12/21 19:08:09 riastradh Exp $"); + +#include <stddef.h> +#include <stdio.h> + +/* + * When built as position-independent executable, the value of foop and + * foopp should be computed either via R_*_RELATIVE or R_*_REL32 or + * similar, which -- ports that support it -- may be compressed into a + * SHT_RELR section. + * + * One pointer indirection is enough to produce this effect, but we use + * two pointer indirections to increase the probability of a crash in + * case the relocations are done wrong. + */ +static int foo = 0x5f4d7635; +static int *volatile foop = &foo; +static int *volatile *volatile foopp = &foop; + +/* + * The RELR section compresses relocations for adjacent addresses into + * bitmaps of 31 or 63 bits apiece. Create a bunch of consecutive + * addresses to relocate, punctuated by the occasional non-relocated + * address (null), to check for fencepost errors in the bitmap + * iteration. + */ +static int bar[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, +}; + +static int *volatile barp[] = { + &bar[0x00], &bar[0x01], &bar[0x02], &bar[0x03], + &bar[0x04], &bar[0x05], &bar[0x06], &bar[0x07], + &bar[0x08], &bar[0x09], &bar[0x0a], &bar[0x0b], + &bar[0x0c], &bar[0x0d], &bar[0x0e], &bar[0x0f], + &bar[0x10], &bar[0x11], &bar[0x12], &bar[0x13], + &bar[0x14], &bar[0x15], &bar[0x16], &bar[0x17], + &bar[0x18], &bar[0x19], &bar[0x1a], &bar[0x1b], + &bar[0x1c], &bar[0x1d], &bar[0x1e], &bar[0x1f], + &bar[0x20], &bar[0x21], &bar[0x22], &bar[0x23], + &bar[0x24], &bar[0x25], &bar[0x26], &bar[0x27], + &bar[0x28], &bar[0x29], &bar[0x2a], &bar[0x2b], + &bar[0x2c], &bar[0x2d], &bar[0x2e], &bar[0x2f], + &bar[0x30], &bar[0x31], &bar[0x32], &bar[0x33], + &bar[0x34], &bar[0x35], &bar[0x36], &bar[0x37], + &bar[0x38], &bar[0x39], &bar[0x3a], &bar[0x3b], + &bar[0x3c], &bar[0x3d], &bar[0x3e], &bar[0x3f], + NULL, &bar[0x41], &bar[0x42], &bar[0x43], /* test a clear bit */ + &bar[0x44], &bar[0x45], &bar[0x46], &bar[0x47], + &bar[0x48], &bar[0x49], &bar[0x4a], &bar[0x4b], + &bar[0x4c], &bar[0x4d], &bar[0x4e], &bar[0x4f], + &bar[0x50], &bar[0x51], &bar[0x52], &bar[0x53], + &bar[0x54], &bar[0x55], &bar[0x56], &bar[0x57], + &bar[0x58], &bar[0x59], &bar[0x5a], &bar[0x5b], + &bar[0x5c], &bar[0x5d], &bar[0x5e], &bar[0x5f], + &bar[0x60], &bar[0x61], &bar[0x62], &bar[0x63], + &bar[0x64], &bar[0x65], &bar[0x66], &bar[0x67], + &bar[0x68], &bar[0x69], &bar[0x6a], &bar[0x6b], + &bar[0x6c], &bar[0x6d], &bar[0x6e], &bar[0x6f], + &bar[0x70], &bar[0x71], &bar[0x72], &bar[0x73], + &bar[0x74], &bar[0x75], &bar[0x76], &bar[0x77], + &bar[0x78], &bar[0x79], &bar[0x7a], &bar[0x7b], + &bar[0x7c], &bar[0x7d], &bar[0x7e], &bar[0x7f], + NULL, /* confirm we stop at the end */ +}; + +static int baz = -0x1adbd477; +static int *volatile bazp = &baz; + +int +main(void) +{ + int i, result = 0; + + if (**foopp != 0x5f4d7635) { + fprintf(stderr, "foo @ %p, foop = %p, *foop = %p," + " **foopp = 0x%x\n", + &foo, foop, *foopp, **foopp); + result |= 1; + } + for (i = 0; i < (int)__arraycount(barp); i++) { + if (i == 0x40 || i == 0x80) { + if (barp[i] != NULL) { + fprintf(stderr, "barp[%u] = %p\n", + i, barp[i]); + } + } else { + if (*barp[i] != i) { + fprintf(stderr, "bar[%u] @ %p, barp[%u] = %p," + " *barp[%u] = %u\n", + i, &bar[i], i, barp[i], i, *barp[i]); + result |= 1; + } + } + } + if (*bazp != -0x1adbd477) { + fprintf(stderr, "baz @ %p, bazp = %p, *bazp = 0x%x\n", + &baz, bazp, *bazp); + result |= 1; + } + + return result; +} diff --git a/libexec/ld.elf_so/t_dladdr.c b/libexec/ld.elf_so/t_dladdr.c new file mode 100644 index 000000000000..5cdb0148fecf --- /dev/null +++ b/libexec/ld.elf_so/t_dladdr.c @@ -0,0 +1,171 @@ +/* $NetBSD: t_dladdr.c,v 1.2 2025/12/15 02:36:47 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_dladdr.c,v 1.2 2025/12/15 02:36:47 riastradh Exp $"); + +#include <sys/mman.h> + +#include <atf-c.h> +#include <dlfcn.h> +#include <unistd.h> + +#include "h_macros.h" + +#define SELF "t_dladdr" + +/* + * Note: the symbols foo, bar, and baz must be exposed to dlfcn(3) by + * linking this with -export-dynamic. + */ +int foo; /* something in this ELF object */ +int bar; /* something in this ELF object */ +int baz; /* something in this ELF object */ + +extern char _end[]; /* one past last byte of this ELF object */ + +ATF_TC(dladdr_self); +ATF_TC_HEAD(dladdr_self, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify dladdr of data in this object returns self"); +} +ATF_TC_BODY(dladdr_self, tc) +{ + Dl_info info; + const char *ptr = (char *)&bar + 1; + const char *p; + + /* + * If we're statically linked, dladdr just fails (XXX is that + * right?). But we're not statically linked because these are + * the ld.elf_so tests (XXX should migrate this to + * tests/lib/libc/dlfcn/ and handle it there). + * + * If we're dynamically linked, then foo, bar, and baz should + * live in self. + */ + ATF_CHECK_MSG(dladdr(ptr, &info) != 0, + "[bar @ %p + [0,%zu)] dladdr(%p) failed: %s", + &bar, sizeof(bar), ptr, dlerror()); + p = strrchr(info.dli_fname, '/'); + if (p == NULL) + p = info.dli_fname; + else + p++; + ATF_CHECK_MSG(strcmp(p, SELF) == 0, + "[bar @ %p + [0,%zu)] dladdr found %p in %s, not self=%s", + &bar, sizeof(bar), ptr, info.dli_fname, SELF); + ATF_CHECK_MSG(strcmp(info.dli_sname, "bar") == 0, + "[bar @ %p + [0,%zu)] dladdr found %p in %s at %p, not bar", + &bar, sizeof(bar), ptr, info.dli_sname, info.dli_saddr); +} + +ATF_TC(dladdr_errno); +ATF_TC_HEAD(dladdr_errno, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify dladdr(errno) returns libc.so (or self if static)"); +} +ATF_TC_BODY(dladdr_errno, tc) +{ + Dl_info info; + const char *p; + + /* + * If we're statically linked, dladdr just fails (XXX is that + * right?). But we're not statically linked because these are + * the ld.elf_so tests (XXX should migrate this to + * tests/lib/libc/dlfcn/ and handle it there). + * + * If we're dynamically linked and single-threaded (no + * libpthread.so), &errno will be in libc. + * + * If we're dynamically linked and multi-threaded, &errno would + * be in a pthread_t object -- but we're not multithreaded, so + * it's not. Hence only two cases: static vs dynamic. + */ + ATF_CHECK_MSG(dladdr(&errno, &info) != 0, + "[errno @ %p] dladdr failed: %s", &errno, dlerror()); + p = strrchr(info.dli_fname, '/'); + if (p == NULL) + p = info.dli_fname; + else + p++; + ATF_CHECK_MSG(strcmp(p, SELF) != 0, + "[errno @ %p] dladdr found errno in self=%s, not in libc.so", + &errno, info.dli_fname); +} + +ATF_TC(dladdr_after__end); +ATF_TC_HEAD(dladdr_after__end, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify dladdr doesn't claim pages past _end for self"); +} +ATF_TC_BODY(dladdr_after__end, tc) +{ + const size_t pagesize = sysconf(_SC_PAGESIZE); + uintptr_t endp, nextp; + void *page; + Dl_info info; + + /* + * Round up to a page start. + */ + endp = (uintptr_t)(void *)_end; + nextp = pagesize*((endp + pagesize - 1)/pagesize); + + /* + * Map the next page, or something after it. It just has to be + * not mapped by an existing object, but for the sake of + * testing for past bugs, we would like to make it as close to + * a real object as we can. + */ + REQUIRE_LIBC(page = mmap((void *)nextp, pagesize, PROT_NONE, MAP_ANON, + /*fd*/-1, /*off*/0), + MAP_FAILED); + + /* + * Verify dladdr doesn't return anything for this page. + */ + ATF_CHECK_MSG(dladdr(page, &info) == 0, + "dladdr returned %s @ %p (symbol %s @ %p) for bogus address %p", + info.dli_fname, info.dli_fbase, + info.dli_sname, info.dli_saddr, + page); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, dladdr_after__end); + ATF_TP_ADD_TC(tp, dladdr_errno); + ATF_TP_ADD_TC(tp, dladdr_self); + return atf_no_error(); +} diff --git a/libexec/ld.elf_so/t_dlclose_thread.c b/libexec/ld.elf_so/t_dlclose_thread.c new file mode 100644 index 000000000000..3b80990c1fec --- /dev/null +++ b/libexec/ld.elf_so/t_dlclose_thread.c @@ -0,0 +1,98 @@ +/* $NetBSD: t_dlclose_thread.c,v 1.1 2025/11/23 22:01:13 riastradh Exp $ */ + +/*- + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_dlclose_thread.c,v 1.1 2025/11/23 22:01:13 riastradh Exp $"); + +#include <atf-c.h> +#include <dlfcn.h> +#include <pthread.h> +#include <stdatomic.h> +#include <unistd.h> + +#include "h_macros.h" + +pthread_barrier_t bar; +atomic_bool stop = false; + +int sleep_init; +int sleep_fini; +int dlopen_cookie; +int dlclose_cookie; + +static const char *const libh_helper_dso[] = { + "libh_helper_dso1.so", + "libh_helper_dso2.so", + "libh_helper_dso3.so", +}; + +static void * +dlclose_thread(void *cookie) +{ + const unsigned i = (uintptr_t)cookie % __arraycount(libh_helper_dso); + void *handle; + + (void)pthread_barrier_wait(&bar); + while (!atomic_load_explicit(&stop, memory_order_relaxed)) { + handle = dlopen(libh_helper_dso[i], RTLD_LAZY | RTLD_LOCAL); + ATF_REQUIRE(handle != NULL); + dlclose(handle); + } + return NULL; +} + +ATF_TC(dlclose_thread); +ATF_TC_HEAD(dlclose_thread, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test concurrent dlopen and dlclose with destructors"); +} +ATF_TC_BODY(dlclose_thread, tc) +{ + pthread_t t[2*__arraycount(libh_helper_dso)]; + unsigned i; + + RZ(pthread_barrier_init(&bar, NULL, 1 + __arraycount(t))); + for (i = 0; i < __arraycount(t); i++) { + RZ(pthread_create(&t[i], NULL, &dlclose_thread, + (void *)(uintptr_t)i)); + } + atf_tc_expect_signal(-1, "PR lib/59751:" + " dlclose is not MT-safe depending on the libraries unloaded"); + (void)pthread_barrier_wait(&bar); + (void)sleep(1); + atomic_store_explicit(&stop, true, memory_order_relaxed); + for (i = 0; i < __arraycount(t); i++) + RZ(pthread_join(t[i], NULL)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, dlclose_thread); + return atf_no_error(); +} diff --git a/libexec/ld.elf_so/t_r_rel.sh b/libexec/ld.elf_so/t_r_rel.sh new file mode 100644 index 000000000000..2bc1059a32ca --- /dev/null +++ b/libexec/ld.elf_so/t_r_rel.sh @@ -0,0 +1,113 @@ +# $NetBSD: t_r_rel.sh,v 1.3 2025/12/21 19:08:09 riastradh Exp $ +# +# Copyright (c) 2025 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +cleanup_core() +{ + local prog + + prog=$1 + test -f "${prog}.core" || return 0 + readelf -rs "$(atf_get_srcdir)/${prog}" + gdb -batch -ex bt -ex 'info registers' -ex disas \ + "$(atf_get_srcdir)/${prog}" "${prog}.core" +} + +atf_test_case readelf_relative_nopack +readelf_relative_nopack_head() +{ + atf_set "descr" "readelf R_*_RELATIVE with -z nopack-relative-relocs" + atf_set "require.progs" "readelf" +} +readelf_relative_nopack_body() +{ + atf_check -o match:'R_.*_REL' \ + readelf -r "$(atf_get_srcdir)"/h_r_rel_nopack +} + +atf_test_case readelf_relative_pack +readelf_relative_pack_head() +{ + atf_set "descr" "readelf R_*_RELATIVE with -z pack-relative-relocs" + atf_set "require.progs" "readelf" +} +readelf_relative_pack_body() +{ + case `uname -p` in + i386|powerpc64*|x86_64) + ;; + *) # Actually missing GNU binutils ld(1) support. + atf_expect_fail "PR bin/59360: ld.elf_so(8):" \ + " missing RELR support" + ;; + esac + atf_check -o not-match:'R_.*_REL' \ + readelf -r "$(atf_get_srcdir)"/h_r_rel_pack +} + +atf_test_case run_relative_nopack cleanup +run_relative_nopack_head() +{ + atf_set "descr" "run R_*_RELATIVE with -z nopack-relative-relocs" +} +run_relative_nopack_body() +{ + atf_check "$(atf_get_srcdir)"/h_r_rel_nopack +} +run_relative_nopack_cleanup() +{ + cleanup_core h_r_rel_nopack +} + +atf_test_case run_relative_pack cleanup +run_relative_pack_head() +{ + atf_set "descr" "run R_*_RELATIVE with -z pack-relative-relocs" +} +run_relative_pack_body() +{ + case `uname -p` in + i386|powerpc64*|x86_64) + ;; + *) # Missing GNU binutils ld(1) support to generate RELR + # sections, so the program should run just fine because + # it just uses traditional REL/RELA instead. + ;; + esac + atf_check "$(atf_get_srcdir)"/h_r_rel_pack +} +run_relative_pack_cleanup() +{ + cleanup_core h_r_rel_pack +} + +atf_init_test_cases() +{ + atf_add_test_case readelf_relative_nopack + atf_add_test_case readelf_relative_pack + atf_add_test_case run_relative_nopack + atf_add_test_case run_relative_pack +} diff --git a/libexec/ld.elf_so/t_tls_alignment.c b/libexec/ld.elf_so/t_tls_alignment.c new file mode 100644 index 000000000000..13d2a5cf4536 --- /dev/null +++ b/libexec/ld.elf_so/t_tls_alignment.c @@ -0,0 +1,70 @@ +/* $NetBSD: t_tls_alignment.c,v 1.2 2026/01/17 10:48:31 skrll Exp $ */ + +/* + * Copyright (c) 2025 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND + * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> + +#include <atf-c.h> + +#define ALIGNMENT 64 + +#define MAGIC1 0xaa55aa55aa55aa55 +#define MAGIC2 0xc0ffeeeeeeeeeeee +#define MAGIC3 0xff00ff00ff00ff00 + +__thread +struct { + uint64_t magic1; + uint64_t magic2 __attribute__((aligned(ALIGNMENT))); + uint64_t magic3; +} tls_data = { + .magic1 = MAGIC1, + .magic2 = MAGIC2, + .magic3 = MAGIC3, +}; + +ATF_TC(tls_alignment); +ATF_TC_HEAD(tls_alignment, tc) +{ + atf_tc_set_md_var(tc, "descr", + "TLS alignment requirements met"); +} + +ATF_TC_BODY(tls_alignment, tc) +{ + ATF_CHECK(tls_data.magic1 == MAGIC1); + ATF_CHECK(tls_data.magic2 == MAGIC2); + ATF_CHECK(tls_data.magic3 == MAGIC3); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, tls_alignment); + + return atf_no_error(); +} diff --git a/net/if_bridge/broadcast.pcap.uue b/net/if_bridge/broadcast.pcap.uue new file mode 100644 index 000000000000..a5044e94f7f0 --- /dev/null +++ b/net/if_bridge/broadcast.pcap.uue @@ -0,0 +1,5 @@ +begin 644 broadcast.pcap +MU,.RH0(`!````````````/__```!````0(=S6Q-!#``J````*@````"JJJJJ +EJO_______P@`10``'``!``!`$:]@P*@`9`H``&0`4`!0``@SS@`` +` +end diff --git a/net/if_bridge/unicast.pcap.uue b/net/if_bridge/unicast.pcap.uue new file mode 100644 index 000000000000..d7c7019272a1 --- /dev/null +++ b/net/if_bridge/unicast.pcap.uue @@ -0,0 +1,5 @@ +begin 644 unicast.pcap +MU,.RH0(`!````````````/__```!````"KIR6R4C!0`J````*@````"JJJJJ +EJ@`1$1$1$0@`10``'``!``!`$:]@P*@`9`H``&0`4`!0``@SS@`` +` +end diff --git a/net/if_shmif/Makefile b/net/if_shmif/Makefile new file mode 100644 index 000000000000..fe9eb11d4fc1 --- /dev/null +++ b/net/if_shmif/Makefile @@ -0,0 +1,13 @@ +# $NetBSD: Makefile,v 1.1 2024/08/20 08:20:19 ozaki-r Exp $ +# + +.include <bsd.own.mk> + +TESTSDIR= ${TESTSBASE}/net/if_shmif + +.for name in shmif +TESTS_SH+= t_${name} +TESTS_SH_SRC_t_${name}= ../net_common.sh t_${name}.sh +.endfor + +.include <bsd.test.mk> diff --git a/net/if_shmif/t_shmif.sh b/net/if_shmif/t_shmif.sh new file mode 100644 index 000000000000..fcd33e357e34 --- /dev/null +++ b/net/if_shmif/t_shmif.sh @@ -0,0 +1,138 @@ +# $NetBSD: t_shmif.sh,v 1.1 2024/08/20 08:20:19 ozaki-r Exp $ +# +# Copyright (c) 2024 Internet Initiative Japan Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +RUMP_SERVER1=unix://./r1 +RUMP_SERVER2=unix://./r2 + +TIMEOUT=3 + +atf_test_case shmif_linkstate cleanup +shmif_linkstate_head() +{ + atf_set "descr" "tests of ifconfig media on shmif" + atf_set "require.progs" "rump_server" +} + +shmif_linkstate_body() +{ + local auto="Ethernet autoselect" + local none="Ethernet none" + + rump_server_start $RUMP_SERVER1 + rump_server_add_iface $RUMP_SERVER1 shmif0 bus1 + + export RUMP_SERVER=$RUMP_SERVER1 + # After ifconfig linkstr, the state becomes UP + atf_check -o match:'linkstate: up' \ + -o match:"media: $auto" \ + -o not-match:"<UP" rump.ifconfig -v shmif0 + atf_check rump.ifconfig shmif0 up + atf_check -o match:'linkstate: up' \ + -o match:"media: $auto" \ + -o match:"<UP" rump.ifconfig -v shmif0 + # ifconfig media none makes the state DOWN + atf_check rump.ifconfig shmif0 media none + atf_check -o match:'linkstate: down' \ + -o match:"media: $none" \ + -o match:"<UP" rump.ifconfig -v shmif0 + # ifconfig media auto makes the state UP + atf_check rump.ifconfig shmif0 media auto + atf_check -o match:'linkstate: up' \ + -o match:"media: $auto" \ + -o match:"<UP" rump.ifconfig -v shmif0 + atf_check rump.ifconfig shmif0 down + atf_check -o match:'linkstate: up' \ + -o match:"media: $auto" \ + -o not-match:"<UP" rump.ifconfig -v shmif0 + # After ifconfig -linkstr, the state becomes UNKNOWN + atf_check rump.ifconfig shmif0 -linkstr + atf_check -o match:'linkstate: unknown' \ + -o match:"media: $auto" \ + -o not-match:"<UP" rump.ifconfig -v shmif0 + + rump_server_destroy_ifaces +} + +shmif_linkstate_cleanup() +{ + + $DEBUG && dump + cleanup +} + +atf_test_case shmif_linkstate_down cleanup +shmif_linkstate_down_head() +{ + atf_set "descr" "tests of behaviors of down shmif" + atf_set "require.progs" "rump_server" +} + +shmif_linkstate_down_body() +{ + + rump_server_start $RUMP_SERVER1 + rump_server_start $RUMP_SERVER2 + rump_server_add_iface $RUMP_SERVER1 shmif0 bus1 + rump_server_add_iface $RUMP_SERVER2 shmif0 bus1 + + export RUMP_SERVER=$RUMP_SERVER1 + atf_check rump.sysctl -q -w net.inet.ip.dad_count=0 + atf_check rump.ifconfig shmif0 10.0.0.1/24 up + export RUMP_SERVER=$RUMP_SERVER2 + atf_check rump.sysctl -q -w net.inet.ip.dad_count=0 + atf_check rump.ifconfig shmif0 10.0.0.2/24 up + + export RUMP_SERVER=$RUMP_SERVER1 + atf_check -o ignore rump.ping -c 1 -w $TIMEOUT 10.0.0.2 + + atf_check rump.ifconfig shmif0 media none + atf_check -o match:'linkstate: down' rump.ifconfig -v shmif0 + + # shmif doesn't send any packets on link down + atf_check -s not-exit:0 -o ignore rump.ping -c 1 -w $TIMEOUT 10.0.0.2 + + atf_check rump.ifconfig shmif0 media auto + atf_check -o match:'linkstate: up' rump.ifconfig -v shmif0 + + atf_check -o ignore rump.ping -c 1 -w $TIMEOUT 10.0.0.2 + + rump_server_destroy_ifaces +} + +shmif_linkstate_down_cleanup() +{ + + $DEBUG && dump + cleanup +} + +atf_init_test_cases() +{ + + atf_add_test_case shmif_linkstate + atf_add_test_case shmif_linkstate_down +} diff --git a/sbin/gpt/gpt.2part.show.label-p b/sbin/gpt/gpt.2part.show.label-p new file mode 100644 index 000000000000..c25cc3d9229d --- /dev/null +++ b/sbin/gpt/gpt.2part.show.label-p @@ -0,0 +1,7 @@ +0 1 0 PMBR +1 1 0 Pri GPT header +2 32 0 Pri GPT table +34 1024 1 GPT part - potato +1058 9150 2 GPT part - tomato +10208 32 0 Sec GPT table +10240 1 0 Sec GPT header diff --git a/sbin/gpt/gpt.2part.show.normal-p b/sbin/gpt/gpt.2part.show.normal-p new file mode 100644 index 000000000000..03a420342c66 --- /dev/null +++ b/sbin/gpt/gpt.2part.show.normal-p @@ -0,0 +1,7 @@ +0 1 0 PMBR +1 1 0 Pri GPT header +2 32 0 Pri GPT table +34 1024 1 GPT part - EFI System +1058 9150 2 GPT part - NetBSD FFSv1/FFSv2 +10208 32 0 Sec GPT table +10240 1 0 Sec GPT header diff --git a/sbin/gpt/gpt.2part.show.uuid-p b/sbin/gpt/gpt.2part.show.uuid-p new file mode 100644 index 000000000000..1315ca228598 --- /dev/null +++ b/sbin/gpt/gpt.2part.show.uuid-p @@ -0,0 +1,7 @@ +0 1 0 PMBR +1 1 0 Pri GPT header +2 32 0 Pri GPT table +34 1024 1 GPT part - c12a7328-f81f-11d2-ba4b-00a0c93ec93b +1058 9150 2 GPT part - 49f48d5a-b10e-11dc-b99b-0019d1879648 +10208 32 0 Sec GPT table +10240 1 0 Sec GPT header diff --git a/sbin/gpt/gpt.disklabel.show.normal-p b/sbin/gpt/gpt.disklabel.show.normal-p new file mode 100644 index 000000000000..b8a389efb2f5 --- /dev/null +++ b/sbin/gpt/gpt.disklabel.show.normal-p @@ -0,0 +1,11 @@ +0 1 0 PMBR +1 1 0 Pri GPT header +2 32 0 Pri GPT table +34 29 0 Unused +63 500 1 GPT part - NetBSD FFSv1/FFSv2 +563 1000 2 GPT part - NetBSD swap +1563 1000 3 GPT part - NetBSD FFSv1/FFSv2 +2563 400 4 GPT part - Windows basic data +2963 7245 0 Unused +10208 32 0 Sec GPT table +10240 1 0 Sec GPT header diff --git a/sbin/gpt/gpt.empty.show.clean b/sbin/gpt/gpt.empty.show.clean new file mode 100644 index 000000000000..8e78dbe04915 --- /dev/null +++ b/sbin/gpt/gpt.empty.show.clean @@ -0,0 +1,4 @@ +GPT not found, displaying data from MBR. + + start size index contents + 0 10241 Unused diff --git a/sbin/gpt/gpt.empty.show.clean-p b/sbin/gpt/gpt.empty.show.clean-p new file mode 100644 index 000000000000..666b5642655e --- /dev/null +++ b/sbin/gpt/gpt.empty.show.clean-p @@ -0,0 +1,3 @@ +GPT not found, displaying data from MBR. + +0 10241 0 Unused diff --git a/sbin/gpt/gpt.empty.show.normal-p b/sbin/gpt/gpt.empty.show.normal-p new file mode 100644 index 000000000000..2b878d9a4b8b --- /dev/null +++ b/sbin/gpt/gpt.empty.show.normal-p @@ -0,0 +1,6 @@ +0 1 0 PMBR +1 1 0 Pri GPT header +2 32 0 Pri GPT table +34 10174 0 Unused +10208 32 0 Sec GPT table +10240 1 0 Sec GPT header diff --git a/sbin/gpt/gpt.removepart.show.normal-p b/sbin/gpt/gpt.removepart.show.normal-p new file mode 100644 index 000000000000..1eb369fabfcd --- /dev/null +++ b/sbin/gpt/gpt.removepart.show.normal-p @@ -0,0 +1,7 @@ +0 1 0 PMBR +1 1 0 Pri GPT header +2 32 0 Pri GPT table +34 1024 0 Unused +1058 9150 2 GPT part - NetBSD FFSv1/FFSv2 +10208 32 0 Sec GPT table +10240 1 0 Sec GPT header diff --git a/sbin/gpt/gpt.resizedisk.show.normal-p b/sbin/gpt/gpt.resizedisk.show.normal-p new file mode 100644 index 000000000000..cfad3e9f4424 --- /dev/null +++ b/sbin/gpt/gpt.resizedisk.show.normal-p @@ -0,0 +1,8 @@ +0 1 0 PMBR +1 1 0 Pri GPT header +2 32 0 Pri GPT table +34 1024 1 GPT part - EFI System +1058 9150 2 GPT part - NetBSD FFSv1/FFSv2 +10208 10240 0 Unused +20448 32 0 Sec GPT table +20480 1 0 Sec GPT header diff --git a/sbin/gpt/gpt.resizepart.show.normal-p b/sbin/gpt/gpt.resizepart.show.normal-p new file mode 100644 index 000000000000..71b34da592ab --- /dev/null +++ b/sbin/gpt/gpt.resizepart.show.normal-p @@ -0,0 +1,7 @@ +0 1 0 PMBR +1 1 0 Pri GPT header +2 32 0 Pri GPT table +34 1024 1 GPT part - EFI System +1058 19390 2 GPT part - NetBSD FFSv1/FFSv2 +20448 32 0 Sec GPT table +20480 1 0 Sec GPT header diff --git a/usr.bin/cc/t_ctype_abuse.sh b/usr.bin/cc/t_ctype_abuse.sh new file mode 100644 index 000000000000..e7c7c74d1220 --- /dev/null +++ b/usr.bin/cc/t_ctype_abuse.sh @@ -0,0 +1,124 @@ +# $NetBSD: t_ctype_abuse.sh,v 1.1 2024/12/18 02:47:00 riastradh Exp $ +# +# Copyright (c) 2024 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +ctype_abuse_head() +{ + local ctypefn reftype desc + + ctypefn=$1 + reftype=$2 + + case $reftype in + var) desc="variable";; + ptr) desc="pointer dereference";; + array) desc="array element";; + funcall) + desc="function call";; + esac + + atf_set "descr" "Test that $ctypefn warns on $desc of type char" + atf_set "require.progs" "cc" +} + +ctype_abuse_body() +{ + local ctypefn reftype + + ctypefn=$1 + reftype=$2 + + case $reftype in + var) decl='x'; ref='x';; + ptr) decl='*x'; ref='*x';; + array) decl='x[]'; ref='x[0]';; + funcall) + decl='f(void)'; ref='f()';; + esac + + cat >test.c <<EOF +#include <ctype.h> + +extern char $decl; + +int +g(void) +{ + + return $ctypefn($ref); +} +EOF + case $reftype in + var) atf_expect_fail 'PR lib/58912: ctype(3) abuse detection' \ + ' fails for variable references';; + esac + atf_check -s not-exit:0 \ + -e match:'array subscript has type.*char.*-W.*char-subscripts' \ + cc -c -Wall -Werror test.c +} + +ctype_abuse_tests() +{ + local ctypefn reftype tc + + for ctypefn in \ + isalpha \ + isupper \ + islower \ + isdigit \ + isxdigit \ + isalnum \ + isspace \ + ispunct \ + isprint \ + isgraph \ + iscntrl \ + isblank \ + toupper \ + tolower \ + # end of ctypefn enumeration + do + for reftype in var ptr array funcall; do + tc=${ctypefn}_${reftype} + eval "atf_test_case $tc" + eval "${tc}_head() + { + ctype_abuse_head $ctypefn $reftype + }" + eval "${tc}_body() + { + ctype_abuse_body $ctypefn $reftype + }" + atf_add_test_case $tc + done + done +} + +atf_init_test_cases() +{ + + ctype_abuse_tests +} diff --git a/usr.bin/cc/t_libm_cabs.sh b/usr.bin/cc/t_libm_cabs.sh new file mode 100644 index 000000000000..85cce3f19228 --- /dev/null +++ b/usr.bin/cc/t_libm_cabs.sh @@ -0,0 +1,57 @@ +# $NetBSD: t_libm_cabs.sh,v 1.1 2026/01/27 20:01:47 mrg Exp $ +# +# Copyright (c) 2026 Matthew R. Green +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + + +atf_test_case libm_cabs +libm_cabs_head() { + atf_set "descr" "compile using __builtin_cabsl(3) which should be renamed" + atf_set "require.progs" "cc" +} + +# +# Simple program that misses including <complex.h> so that the renames +# GCC itself is supposed to be doing are also applied, which makes their +# uses in libgfortran use the correct symbols. The use of +# "__builtin_cabsl" should become "__c99_cabsl". +# +libm_cabs_body() { + cat > cabsl.c << EOF +long double my_foo(long double _Complex); +long double +my_foo(long double _Complex z) +{ + return __builtin_cabsl(z); +} +EOF + atf_check -s exit:0 -o ignore -e ignore cc -O3 -c cabsl.c + atf_check -s exit:0 -o match:__c99_cabsl -e empty objdump -dr cabsl.o +} + +atf_init_test_cases() +{ + + atf_add_test_case libm_cabs +} diff --git a/usr.bin/cc/t_pthread_abuse.sh b/usr.bin/cc/t_pthread_abuse.sh new file mode 100644 index 000000000000..caf88e60557f --- /dev/null +++ b/usr.bin/cc/t_pthread_abuse.sh @@ -0,0 +1,79 @@ +# $NetBSD: t_pthread_abuse.sh,v 1.1 2025/10/06 13:11:56 riastradh Exp $ +# +# Copyright (c) 2025 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +pthread_abuse_head() +{ + + atf_set "descr" \ + "Test that pthread_create calls without -lpthread fail to link" + atf_set "require.progs" "cc" +} +pthread_abuse_body() +{ + + cat >test.c <<'EOF' +#include <err.h> +#include <pthread.h> +#include <stdlib.h> + +static void * +start(void *cookie) +{ + return cookie; +} + +int +main(void) +{ + int cookie = 123; + pthread_t t; + void *result; + int error; + + error = pthread_create(&t, NULL, &start, &cookie); + if (error) + errc(EXIT_FAILURE, error, "pthread_create"); + error = pthread_join(t, &result); + if (error) + errc(EXIT_FAILURE, error, "pthread_join"); + return (result == &cookie ? 0 : EXIT_FAILURE); +} +EOF + atf_check -s not-exit:0 \ + -e match:'undefined reference to.*pthread_create' \ + cc -o test test.c + atf_check cc -o test test.c -lpthread + atf_check ./test + atf_check cc -o test test.c -pthread + atf_check ./test +} + +atf_init_test_cases() +{ + + atf_add_test_case pthread_abuse +} diff --git a/usr.bin/diff/functionname.in b/usr.bin/diff/functionname.in new file mode 100644 index 000000000000..7b4c50c86cd9 --- /dev/null +++ b/usr.bin/diff/functionname.in @@ -0,0 +1,29 @@ +static void +doSomethingThenPrintHello(int test) +{ + test = test << 4; + if (test % 8 == 6) { + return; + } + + print("goodbye\n"); +} + + +- (long) readOffset:(FILE*)file +{ + if( version >= 11){ + long offset; + fread(&offset, sizeof(long), 1, file); + return offset; + } else { + int offset; + fread(&offset, sizeof(int), 1, file); + return offset; + } +} + ++ (BOOL) isEdible:(NSString *)mushroom +{ + return TRUE; +} diff --git a/usr.bin/diff/functionname_c.in b/usr.bin/diff/functionname_c.in new file mode 100644 index 000000000000..84f6846783ca --- /dev/null +++ b/usr.bin/diff/functionname_c.in @@ -0,0 +1,29 @@ +static void +doSomethingThenPrintHello(int test) +{ + test = test << 4; + if (test % 8 == 6) { + return; + } + + print("hello\n"); +} + + +- (long) readOffset:(FILE*)file +{ + if( version >= 11){ + long offset; + fread(&offset, sizeof(long), 1, file); + return offset; + } else { + int offset; + fread(&offset, sizeof(int), 1, file); + return offset; + } +} + ++ (BOOL) isEdible:(NSString *)mushroom +{ + return TRUE; +} diff --git a/usr.bin/diff/functionname_c.out b/usr.bin/diff/functionname_c.out new file mode 100644 index 000000000000..b17ce05d04ca --- /dev/null +++ b/usr.bin/diff/functionname_c.out @@ -0,0 +1,11 @@ +--- functionname.in ++++ functionname_c.in +@@ -6,7 +6,7 @@ doSomethingThenPrintHello(int test) + return; + } + +- print("goodbye\n"); ++ print("hello\n"); + } + + diff --git a/usr.bin/diff/header.out b/usr.bin/diff/header.out new file mode 100644 index 000000000000..2e1665a30e6d --- /dev/null +++ b/usr.bin/diff/header.out @@ -0,0 +1,4 @@ +--- empty 2015-04-03 01:02:03.000000000 +0000 ++++ hello 2016-12-22 11:22:33.000000000 +0000 +@@ -0,0 +1 @@ ++hello diff --git a/usr.bin/diff/header_ns.out b/usr.bin/diff/header_ns.out new file mode 100644 index 000000000000..b1316dfc12b9 --- /dev/null +++ b/usr.bin/diff/header_ns.out @@ -0,0 +1,4 @@ +--- empty 2015-04-03 01:02:03.123456789 +0000 ++++ hello 2016-12-22 11:22:33.987654321 +0000 +@@ -0,0 +1 @@ ++hello diff --git a/usr.bin/diff/input1.in b/usr.bin/diff/input1.in new file mode 100644 index 000000000000..3892e8400f86 --- /dev/null +++ b/usr.bin/diff/input1.in @@ -0,0 +1,2 @@ +Simple input file designed +to be able to test diff diff --git a/usr.bin/diff/input2.in b/usr.bin/diff/input2.in new file mode 100644 index 000000000000..c38b487353a7 --- /dev/null +++ b/usr.bin/diff/input2.in @@ -0,0 +1,3 @@ +Simple input file designed +and written +to be able to test diff utility diff --git a/usr.bin/diff/input_c1.in b/usr.bin/diff/input_c1.in new file mode 100644 index 000000000000..d39dfbdc511b --- /dev/null +++ b/usr.bin/diff/input_c1.in @@ -0,0 +1,15 @@ +/* + * A comment + * + * And another bla + * + * And yet another + */ + +int +main(void) +{ + printf("something"); + + return (0); +} diff --git a/usr.bin/diff/input_c2.in b/usr.bin/diff/input_c2.in new file mode 100644 index 000000000000..933ec67dc175 --- /dev/null +++ b/usr.bin/diff/input_c2.in @@ -0,0 +1,16 @@ +/* + * A comment + * + * And another bla + * + * and yet another + */ + +int +main(void) +{ + + printf("something"); + + return (0); +} diff --git a/usr.bin/diff/simple.out b/usr.bin/diff/simple.out new file mode 100644 index 000000000000..fcbcaa041e8c --- /dev/null +++ b/usr.bin/diff/simple.out @@ -0,0 +1,5 @@ +2c2,3 +< to be able to test diff +--- +> and written +> to be able to test diff utility diff --git a/usr.bin/diff/simple_b.out b/usr.bin/diff/simple_b.out new file mode 100644 index 000000000000..704be9d621a8 --- /dev/null +++ b/usr.bin/diff/simple_b.out @@ -0,0 +1,6 @@ +6c6 +< * And yet another +--- +> * and yet another +11a12 +> diff --git a/usr.bin/diff/simple_e.out b/usr.bin/diff/simple_e.out new file mode 100644 index 000000000000..0c7e2b5c752b --- /dev/null +++ b/usr.bin/diff/simple_e.out @@ -0,0 +1,4 @@ +2c +and written +to be able to test diff utility +. diff --git a/usr.bin/diff/simple_i.out b/usr.bin/diff/simple_i.out new file mode 100644 index 000000000000..9edc1f98d72d --- /dev/null +++ b/usr.bin/diff/simple_i.out @@ -0,0 +1,6 @@ +4c4 +< * And another bla +--- +> * And another bla +11a12 +> diff --git a/usr.bin/diff/simple_n.out b/usr.bin/diff/simple_n.out new file mode 100644 index 000000000000..33ca7090cf97 --- /dev/null +++ b/usr.bin/diff/simple_n.out @@ -0,0 +1,4 @@ +d2 1 +a2 2 +and written +to be able to test diff utility diff --git a/usr.bin/diff/simple_p.out b/usr.bin/diff/simple_p.out new file mode 100644 index 000000000000..f5aebb0d1199 --- /dev/null +++ b/usr.bin/diff/simple_p.out @@ -0,0 +1,34 @@ +*** input_c1.in +--- input_c2.in +*************** +*** 1,14 **** + /* + * A comment + * +! * And another bla + * +! * And yet another + */ + + int + main(void) + { + printf("something"); + + return (0); +--- 1,15 ---- + /* + * A comment + * +! * And another bla + * +! * and yet another + */ + + int + main(void) + { ++ + printf("something"); + + return (0); diff --git a/usr.bin/diff/simple_u.out b/usr.bin/diff/simple_u.out new file mode 100644 index 000000000000..f341987ebec6 --- /dev/null +++ b/usr.bin/diff/simple_u.out @@ -0,0 +1,7 @@ +--- input1 ++++ input2 +@@ -1,2 +1,3 @@ + Simple input file designed +-to be able to test diff ++and written ++to be able to test diff utility diff --git a/usr.bin/diff/simple_w.out b/usr.bin/diff/simple_w.out new file mode 100644 index 000000000000..704be9d621a8 --- /dev/null +++ b/usr.bin/diff/simple_w.out @@ -0,0 +1,6 @@ +6c6 +< * And yet another +--- +> * and yet another +11a12 +> diff --git a/usr.bin/diff/unified_9999.out b/usr.bin/diff/unified_9999.out new file mode 100644 index 000000000000..0f9303fbdc7c --- /dev/null +++ b/usr.bin/diff/unified_9999.out @@ -0,0 +1,21 @@ +--- input_c1.in ++++ input_c2.in +@@ -1,15 +1,16 @@ + /* + * A comment + * +- * And another bla ++ * And another bla + * +- * And yet another ++ * and yet another + */ + + int + main(void) + { ++ + printf("something"); + + return (0); + } diff --git a/usr.bin/diff/unified_p.out b/usr.bin/diff/unified_p.out new file mode 100644 index 000000000000..938b07890fbc --- /dev/null +++ b/usr.bin/diff/unified_p.out @@ -0,0 +1,20 @@ +--- input_c1.in ++++ input_c2.in +@@ -1,14 +1,15 @@ + /* + * A comment + * +- * And another bla ++ * And another bla + * +- * And yet another ++ * and yet another + */ + + int + main(void) + { ++ + printf("something"); + + return (0); diff --git a/usr.bin/error/Makefile b/usr.bin/error/Makefile new file mode 100644 index 000000000000..6d3e2e72fbc9 --- /dev/null +++ b/usr.bin/error/Makefile @@ -0,0 +1,6 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 10:06:16 rillig Exp $ + +TESTSDIR= ${TESTSBASE}/usr.bin/error +TESTS_SH= t_error + +.include <bsd.test.mk> diff --git a/usr.bin/error/t_error.sh b/usr.bin/error/t_error.sh new file mode 100644 index 000000000000..89f25e90b4e4 --- /dev/null +++ b/usr.bin/error/t_error.sh @@ -0,0 +1,101 @@ +# $NetBSD: t_error.sh,v 1.1 2023/08/26 10:06:16 rillig Exp $ +# +# Copyright (c) 2023 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Roland Illig. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +create_file() { + local fn="$1"; shift + printf '%s\n' "$@" > "$fn" +} + +atf_test_case cc +cc_body() { + create_file code.c \ + 'goto error' + create_file err \ + 'code.c:1: error: syntax error' + create_file expected \ + '/*###1 [cc] error: syntax error%%%*/' \ + 'goto error' + + atf_check -o ignore \ + error err + atf_check -o 'file:expected' cat code.c +} + +atf_test_case f77 +f77_body() { + create_file code.f \ + 'doi=1,1,1' + create_file err \ + 'Compiler error line 1 of code.f: syntax error' + create_file expected \ + 'C###1 [f77] Compiler error line 1 of code.f syntax error%%%' \ + 'doi=1,1,1' + + atf_check -o ignore \ + error err + atf_check -o 'file:expected' cat code.f +} + +atf_test_case lint +lint_body() { + create_file code.c \ + 'goto error' + create_file err \ + 'code.c(1): syntax error' + create_file expected \ + '/*###1 [lint] syntax error%%%*/' \ + 'goto error' + + atf_check -o ignore \ + error err + atf_check -o 'file:expected' cat code.c +} + +atf_test_case mod2 +mod2_body() { + create_file code.m2 \ + 'END.' + create_file err \ + 'File code.m2, line 1: missing BEGIN' + create_file expected \ + '(*###1 [mod2] missing BEGIN%%%*)' \ + 'END.' + + atf_check -o ignore \ + error err + atf_check -o 'file:expected' cat code.m2 +} + +atf_init_test_cases() { + atf_add_test_case cc + atf_add_test_case f77 + atf_add_test_case lint + atf_add_test_case mod2 +} diff --git a/usr.bin/ftp/Makefile b/usr.bin/ftp/Makefile new file mode 100644 index 000000000000..8d47e55379fc --- /dev/null +++ b/usr.bin/ftp/Makefile @@ -0,0 +1,15 @@ +# $NetBSD: Makefile,v 1.1 2024/10/12 22:19:37 riastradh Exp $ + +.include <bsd.own.mk> + +TESTSDIR= ${TESTSBASE}/usr.bin/ftp +TESTS_SH= t_custom_headers + +SCRIPTSDIR= ${TESTSDIR} +SCRIPTS+= custom_headers.sh + +# Keep the .sh suffix because we use it to trigger cgi-bin handling in +# bozohttpd (rather silly but it's easier that way). +SCRIPTSNAME_custom_headers.sh= custom_headers.sh + +.include <bsd.test.mk> diff --git a/usr.bin/ftp/custom_headers.sh b/usr.bin/ftp/custom_headers.sh new file mode 100644 index 000000000000..e364ef0e784e --- /dev/null +++ b/usr.bin/ftp/custom_headers.sh @@ -0,0 +1,36 @@ +#! /bin/sh +# +# $NetBSD: custom_headers.sh,v 1.1 2024/10/12 22:19:37 riastradh Exp $ +# +# Copyright (c) 2024 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Sunil Nimmagadda. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +echo "Content-type: text/plain; charset=utf-8" +echo "" +echo "HTTP_X_ORIGIN=$HTTP_X_ORIGIN" +echo "HTTP_X_RATE_LIMIT=$HTTP_X_RATE_LIMIT" diff --git a/usr.bin/ftp/t_custom_headers.sh b/usr.bin/ftp/t_custom_headers.sh new file mode 100644 index 000000000000..bdf185512f68 --- /dev/null +++ b/usr.bin/ftp/t_custom_headers.sh @@ -0,0 +1,67 @@ +# $NetBSD: t_custom_headers.sh,v 1.1 2024/10/12 22:19:37 riastradh Exp $ +# +# Copyright (c) 2024 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Sunil Nimmagadda. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +atf_test_case custom_headers cleanup +custom_headers_head() +{ + atf_require_prog ftp + atf_set "descr" "Check for custom HTTP headers" +} + +HTTPD_PID=./.__httpd.pid +custom_headers_body() +{ + # start httpd in daemon mode + atf_check -s exit:0 \ + /usr/libexec/httpd -P $HTTPD_PID -I 8080 -b -C .sh /bin/sh \ + -c "$(atf_get_srcdir)" . + + atf_check \ + -o inline:'HTTP_X_ORIGIN=example.com\nHTTP_X_RATE_LIMIT=1000\n' \ + ftp -V -o - \ + -H 'X-Origin: example.com' \ + -H 'X-Rate-Limit: 1000' \ + http://127.0.0.1:8080/cgi-bin/custom_headers.sh +} + +custom_headers_cleanup() +{ + if [ -f "$HTTPD_PID" ]; then + echo kill -9 "$(cat $HTTPD_PID)" + kill -9 "$(cat $HTTPD_PID)" + echo '# wait for httpd to exit' + sleep 1 + fi +} + +atf_init_test_cases() +{ + atf_add_test_case custom_headers +} diff --git a/usr.bin/gcov/Makefile b/usr.bin/gcov/Makefile new file mode 100644 index 000000000000..6828aac4b00e --- /dev/null +++ b/usr.bin/gcov/Makefile @@ -0,0 +1,7 @@ +# $NetBSD: Makefile,v 1.1 2025/01/18 22:31:22 rillig Exp $ + +TESTSDIR= ${TESTSBASE}/usr.bin/gcov + +TESTS_SH= t_gcov + +.include <bsd.test.mk> diff --git a/usr.bin/gcov/t_gcov.sh b/usr.bin/gcov/t_gcov.sh new file mode 100644 index 000000000000..7895a9b9adf0 --- /dev/null +++ b/usr.bin/gcov/t_gcov.sh @@ -0,0 +1,104 @@ +# $NetBSD: t_gcov.sh,v 1.1 2025/01/18 22:31:22 rillig Exp $ +# +# Copyright (c) 2025 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +after_exec_head() +{ +} +after_exec_body() +{ + atf_require_prog cat + atf_require_prog gcc + atf_require_prog gcov + atf_require_prog grep + + cat <<EOF >prog.c +#include <unistd.h> + +int +main(void) +{ + pid_t pid = vfork(); + switch (pid) { + case 0: + execl("/bin/sh", "sh", "-c", ":", (const char *)0); + /* FALLTHROUGH */ + case -1: + write(2, "error\n", 6); + _exit(1); + } + + write(1, "reached\n", 8); + return 0; +} +EOF + + cat <<EOF >prog.c.gcov.expected + -: 0:Source:prog.c + -: 0:Graph:prog.gcno + -: 0:Data:prog.gcda + -: 0:Runs:1 + -: 1:#include <unistd.h> + -: 2: + -: 3:int + 1: 4:main(void) + -: 5:{ + 1: 6: pid_t pid = vfork(); + 1: 7: switch (pid) { + 1: 8: case 0: + 1: 9: execl("/bin/sh", "sh", "-c", ":", (const char *)0); + -: 10: /* FALLTHROUGH */ + #####: 11: case -1: + #####: 12: write(2, "error\n", 6); + #####: 13: _exit(1); + -: 14: } + -: 15: + #####: 16: write(1, "reached\n", 8); + #####: 17: return 0; + -: 18:} +EOF + + atf_check \ + gcc --coverage -c prog.c + atf_check \ + gcc --coverage -o prog prog.o + atf_check -o inline:'reached\n' \ + ./prog + atf_check -o ignore \ + gcov prog.c + + atf_check -o file:prog.c.gcov.expected \ + cat prog.c.gcov + + # FIXME: The code was reached once but is reported as unreached. + atf_check -o ignore \ + grep "#####.*reached" prog.c.gcov +} + +atf_init_test_cases() +{ + atf_add_test_case after_exec +} diff --git a/usr.bin/mtree/Makefile b/usr.bin/mtree/Makefile new file mode 100644 index 000000000000..a7f091f3832f --- /dev/null +++ b/usr.bin/mtree/Makefile @@ -0,0 +1,8 @@ +# $NetBSD: Makefile,v 1.1 2024/01/25 00:30:57 riastradh Exp $ +# + +TESTSDIR= ${TESTSBASE}/usr.bin/mtree + +TESTS_SH+= t_sets + +.include <bsd.test.mk> diff --git a/usr.bin/mtree/t_sets.sh b/usr.bin/mtree/t_sets.sh new file mode 100644 index 000000000000..c9f56956bfdd --- /dev/null +++ b/usr.bin/mtree/t_sets.sh @@ -0,0 +1,126 @@ +# $NetBSD: t_sets.sh,v 1.9 2024/05/10 03:29:47 riastradh Exp $ +# +# Copyright (c) 2024 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +check_mtree() +{ + local set=$1 + + cd / + atf_check -o empty -s exit:0 \ + mtree -e </etc/mtree/set."$set" +} + +set_case() +{ + local set=$1 + + eval "set_${set}_head() { atf_set descr \"/etc/mtree/set.${set}\"; }" + eval "set_${set}_body() { check_mtree ${set}; }" + eval "set_${set}_defined=" +} + +set_case base +set_case base32 +set_case base64 +set_case comp +set_case debug +set_case debug32 +set_case debug64 +set_case dtb +#set_case etc +set_case games +set_case gpufw +set_case man +set_case manhtml +set_case misc +set_case modules +set_case rescue +set_case tests +set_case text +set_case xbase +set_case xcomp +set_case xdebug +#set_case xetc +set_case xfont +set_case xserver + +sets_unknown= + +sets_unknown_head() +{ + atf_set descr "Verify this tests lists all sets" +} +sets_unknown_body() +{ + test -z "$sets_unknown" || atf_fail "Unknown sets: ${sets_unknown}" +} + +atf_init_test_cases() +{ + local mtree set defined + + atf_add_test_case sets_unknown + + # base is always installed -- hard-code this in case we make a + # mistake with the automatic set detection. + atf_add_test_case set_base + + # Test all of the sets that are installed, except for some + # special cases. + for mtree in /etc/mtree/set.*; do + set=${mtree#/etc/mtree/set.} + case $set in + base) # Handled above already. + continue + ;; + dtb) + # contents of this set go to the boot partition, + # which may not be mounted during normal operation + if [ ! -d /boot/dtb ]; then + continue; + fi + ;; + etc|xetc) + # etc and xetc have files that may be modified + # on installation, and also contain log files, + # so let's skip them for now. + continue + ;; + *) ;; + esac + + # If we have a test for this set, add it. Otherwise, + # add it to the unknown list to make the test suite + # fail. + eval 'defined=${set_'"$set"'_defined+yes}' + if [ -n "$defined" ]; then + atf_add_test_case set_"${set}" + else + sets_unknown="${sets_unknown}${sets_unknown:+ }${set}" + fi + done +} diff --git a/usr.bin/netpgpkeys/Makefile b/usr.bin/netpgpkeys/Makefile new file mode 100644 index 000000000000..7852906c3ee7 --- /dev/null +++ b/usr.bin/netpgpkeys/Makefile @@ -0,0 +1,13 @@ +# $NetBSD: Makefile,v 1.2 2026/01/29 16:14:45 wiz Exp $ + +.include <bsd.own.mk> + +TESTSDIR= ${TESTSBASE}/usr.bin/netpgpkeys + +TESTS_SH+= t_netpgpkeys + +FILESDIR= ${TESTSDIR}/data +FILES+= data/testkey-ec.pub +FILES+= data/testkey-rsa.pub + +.include <bsd.test.mk> diff --git a/usr.bin/netpgpkeys/data/testkey-ec.pub b/usr.bin/netpgpkeys/data/testkey-ec.pub Binary files differnew file mode 100644 index 000000000000..aff1af8376da --- /dev/null +++ b/usr.bin/netpgpkeys/data/testkey-ec.pub diff --git a/usr.bin/netpgpkeys/data/testkey-rsa.pub b/usr.bin/netpgpkeys/data/testkey-rsa.pub Binary files differnew file mode 100644 index 000000000000..d4bec383e5ea --- /dev/null +++ b/usr.bin/netpgpkeys/data/testkey-rsa.pub diff --git a/usr.bin/netpgpkeys/t_netpgpkeys.sh b/usr.bin/netpgpkeys/t_netpgpkeys.sh new file mode 100644 index 000000000000..08d01a7fe98e --- /dev/null +++ b/usr.bin/netpgpkeys/t_netpgpkeys.sh @@ -0,0 +1,81 @@ +#! /bin/sh + +# $NetBSD: t_netpgpkeys.sh,v 1.3 2026/01/31 22:35:10 wiz Exp $ + +# +# Copyright (c) 2026 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Thomas Klausner <wiz@NetBSD.org> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +cleanup_core() { + local prog + + prog=$1 + test -f "${prog}.core" || return 0 + readelf -rs "/usr/bin/${prog}" + gdb -batch -ex bt -ex 'info registers' -ex disas \ + "/usr/bin/${prog}" "${prog}.core" +} + +# Test set 1 (rsa key) for netpgpkeys +atf_test_case netpgpkeys_testset_1_rsa_keys + +netpgpkeys_testset_1_rsa_keys_head() { + atf_set "descr" "Test set 1 (rsa_keys) for netpgpkeys" +} +netpgpkeys_testset_1_rsa_keys_body() { + atf_expect_fail "PR bin/59936 - does not support keys generated by gnugp2" + # TODO: fix netpgpkeys so it doesn't need an empty keyring + atf_check touch pubring.gpg + atf_check netpgpkeys --keyring pubring.gpg \ + --import-key "$(atf_get_srcdir)"/data/testkey-rsa.pub +} + +# Test set 2 (elliptic curve keys) for netpgpkeys +atf_test_case netpgpkeys_testset_2_ec_keys cleanup + +netpgpkeys_testset_2_ec_keys_head() { + atf_set "descr" "Test set 2 (ec_keys) for netpgpkeys" +} +netpgpkeys_testset_2_ec_keys_body() { + atf_expect_fail "PR bin/59936 - does not support keys generated by gnugp2 - dumps core for EC keys" + # TODO: fix netpgpkeys so it doesn't need an empty keyring + atf_check touch pubring.gpg + atf_check netpgpkeys --keyring pubring.gpg \ + --import-key "$(atf_get_srcdir)"/data/testkey-ec.pub \ + --coredumps +} + +netpgpkeys_testset_2_ec_keys_cleanup() { + cleanup_core netpgpkeys +} + +# all test sets +atf_init_test_cases() { + atf_add_test_case netpgpkeys_testset_1_rsa_keys + atf_add_test_case netpgpkeys_testset_2_ec_keys +} diff --git a/usr.bin/netpgpverify/data/D5B22A28.pub b/usr.bin/netpgpverify/data/D5B22A28.pub Binary files differnew file mode 100644 index 000000000000..3e41c990e290 --- /dev/null +++ b/usr.bin/netpgpverify/data/D5B22A28.pub diff --git a/usr.bin/netpgpverify/data/D5B22A28.secret b/usr.bin/netpgpverify/data/D5B22A28.secret Binary files differnew file mode 100644 index 000000000000..2c9f1fb35b72 --- /dev/null +++ b/usr.bin/netpgpverify/data/D5B22A28.secret diff --git a/usr.bin/netpgpverify/data/NetBSD-6.0_hashes.asc.gz b/usr.bin/netpgpverify/data/NetBSD-6.0_hashes.asc.gz Binary files differnew file mode 100644 index 000000000000..b1499aaeb80e --- /dev/null +++ b/usr.bin/netpgpverify/data/NetBSD-6.0_hashes.asc.gz diff --git a/usr.bin/netpgpverify/data/a.gpg b/usr.bin/netpgpverify/data/a.gpg Binary files differnew file mode 100644 index 000000000000..4041a0aa61b0 --- /dev/null +++ b/usr.bin/netpgpverify/data/a.gpg diff --git a/usr.bin/netpgpverify/data/b.gpg b/usr.bin/netpgpverify/data/b.gpg Binary files differnew file mode 100644 index 000000000000..6934bddc429a --- /dev/null +++ b/usr.bin/netpgpverify/data/b.gpg diff --git a/usr.bin/netpgpverify/data/det b/usr.bin/netpgpverify/data/det new file mode 100644 index 000000000000..04dc803533a2 --- /dev/null +++ b/usr.bin/netpgpverify/data/det @@ -0,0 +1,16 @@ +To Do +===== +tests with -k sig +detached sigs +DSA + +Done +==== +basics +localise pgp_read_packets +fix lint +WARNS=5 +lib man page +prog man page +do we do it statically linked as well? +multiple files in netpgpverify diff --git a/usr.bin/netpgpverify/data/det.sig b/usr.bin/netpgpverify/data/det.sig Binary files differnew file mode 100644 index 000000000000..5bf66e7878cf --- /dev/null +++ b/usr.bin/netpgpverify/data/det.sig diff --git a/usr.bin/netpgpverify/data/dsa-pubring.gpg b/usr.bin/netpgpverify/data/dsa-pubring.gpg Binary files differnew file mode 100644 index 000000000000..a941a8fa5ee5 --- /dev/null +++ b/usr.bin/netpgpverify/data/dsa-pubring.gpg diff --git a/usr.bin/netpgpverify/data/expected16 b/usr.bin/netpgpverify/data/expected16 new file mode 100644 index 000000000000..958c7b960389 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected16 @@ -0,0 +1,8 @@ +Good signature for b.gpg made Mon Sep 10 00:15:38 2012 +signature 2048/RSA (Encrypt or Sign) 1b68dcfcc0596823 2004-01-12 +fingerprint d415 9deb 336d e4cc cdfa 00cd 1b68 dcfc c059 6823 +uid Alistair Crooks <agc@alistaircrooks.com> +uid Alistair Crooks <agc@pkgsrc.org> +uid Alistair Crooks <agc@netbsd.org> +uid Alistair Crooks <agc@netflix.com> + diff --git a/usr.bin/netpgpverify/data/expected17 b/usr.bin/netpgpverify/data/expected17 new file mode 100644 index 000000000000..0ea49e043f65 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected17 @@ -0,0 +1,10 @@ +Good signature for a.gpg made Sun Sep 9 17:44:11 2012 +signature 2048/RSA (Encrypt or Sign) 1b68dcfcc0596823 2004-01-12 +fingerprint: d415 9deb 336d e4cc cdfa 00cd 1b68 dcfc c059 6823 +uid Alistair Crooks <agc@alistaircrooks.com> +uid Alistair Crooks <agc@pkgsrc.org> +uid Alistair Crooks <agc@netbsd.org> +uid Alistair Crooks <agc@netflix.com> +encryption 2048/RSA (Encrypt or Sign) 79deb61e488eee74 2004-01-12 +fingerprint: 57c0 c1e6 bf71 8845 416b 9522 79de b61e 488e ee74 + diff --git a/usr.bin/netpgpverify/data/expected18 b/usr.bin/netpgpverify/data/expected18 new file mode 100644 index 000000000000..00bfcb1c193e --- /dev/null +++ b/usr.bin/netpgpverify/data/expected18 @@ -0,0 +1,8 @@ +Good signature for a.gpg made Tue May 31 23:29:10 2016 +signature 2048/RSA (Encrypt or Sign) 1b68dcfcc0596823 2004-01-12 +fingerprint d415 9deb 336d e4cc cdfa 00cd 1b68 dcfc c059 6823 +uid Alistair Crooks <agc@alistaircrooks.com> +uid Alistair Crooks <agc@pkgsrc.org> +uid Alistair Crooks <agc@netbsd.org> +uid Alistair Crooks <agc@netflix.com> + diff --git a/usr.bin/netpgpverify/data/expected19 b/usr.bin/netpgpverify/data/expected19 new file mode 100644 index 000000000000..eb96b974c4cd --- /dev/null +++ b/usr.bin/netpgpverify/data/expected19 @@ -0,0 +1,7 @@ +Good signature for NetBSD-6.0_RC2_hashes.asc made Wed Sep 19 07:53:18 2012 +signature 4096/RSA (Encrypt or Sign) 064973ac4c4a706e 2009-06-23 +fingerprint: ddee 2bdb 9c98 a0d1 d4fb dbf7 0649 73ac 4c4a 706e +uid NetBSD Security Officer <security-officer@NetBSD.org> +encryption 4096/RSA (Encrypt or Sign) 9ff2c24fdf2ce620 2009-06-23 [Expiry 2019-06-21] +fingerprint: 1915 0801 fbd8 f45d 89f2 0205 9ff2 c24f df2c e620 + diff --git a/usr.bin/netpgpverify/data/expected20 b/usr.bin/netpgpverify/data/expected20 new file mode 100644 index 000000000000..4715faa78887 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected20 @@ -0,0 +1,18 @@ +1. tag & 0x3f +2. len + +one pass (tag 4) +======== +b version:3 +b sig type +b hash alg +b pubkey alg +8b keyid + +literal data (tag 11) +============= +b binary/text +b length +c string +L mtime +text diff --git a/usr.bin/netpgpverify/data/expected21 b/usr.bin/netpgpverify/data/expected21 new file mode 100644 index 000000000000..4ae923b07724 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected21 @@ -0,0 +1,8 @@ +Good signature for [stdin] made Tue May 31 23:29:10 2016 +signature 2048/RSA (Encrypt or Sign) 1b68dcfcc0596823 2004-01-12 +fingerprint d415 9deb 336d e4cc cdfa 00cd 1b68 dcfc c059 6823 +uid Alistair Crooks <agc@alistaircrooks.com> +uid Alistair Crooks <agc@pkgsrc.org> +uid Alistair Crooks <agc@netbsd.org> +uid Alistair Crooks <agc@netflix.com> + diff --git a/usr.bin/netpgpverify/data/expected22 b/usr.bin/netpgpverify/data/expected22 new file mode 100644 index 000000000000..e9da07566c77 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected22 @@ -0,0 +1,8 @@ +Good signature for [stdin] made Sun Sep 30 10:50:20 2012 +signature 2048/RSA (Encrypt or Sign) 1b68dcfcc0596823 2004-01-12 +fingerprint d415 9deb 336d e4cc cdfa 00cd 1b68 dcfc c059 6823 +uid Alistair Crooks <agc@alistaircrooks.com> +uid Alistair Crooks <agc@pkgsrc.org> +uid Alistair Crooks <agc@netbsd.org> +uid Alistair Crooks <agc@netflix.com> + diff --git a/usr.bin/netpgpverify/data/expected23 b/usr.bin/netpgpverify/data/expected23 new file mode 100644 index 000000000000..096662a89218 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected23 @@ -0,0 +1,7 @@ +Good signature for [stdin] made Wed Sep 19 07:53:18 2012 +signature 4096/RSA (Encrypt or Sign) 064973ac4c4a706e 2009-06-23 +fingerprint: ddee 2bdb 9c98 a0d1 d4fb dbf7 0649 73ac 4c4a 706e +uid NetBSD Security Officer <security-officer@NetBSD.org> +encryption 4096/RSA (Encrypt or Sign) 9ff2c24fdf2ce620 2009-06-23 [Expiry 2019-06-21] +fingerprint: 1915 0801 fbd8 f45d 89f2 0205 9ff2 c24f df2c e620 + diff --git a/usr.bin/netpgpverify/data/expected24 b/usr.bin/netpgpverify/data/expected24 new file mode 100644 index 000000000000..1e9f824d22c7 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected24 @@ -0,0 +1,8 @@ +Good signature for [stdin] made Mon Sep 10 00:15:38 2012 +signature 2048/RSA (Encrypt or Sign) 1b68dcfcc0596823 2004-01-12 +fingerprint d415 9deb 336d e4cc cdfa 00cd 1b68 dcfc c059 6823 +uid Alistair Crooks <agc@alistaircrooks.com> +uid Alistair Crooks <agc@pkgsrc.org> +uid Alistair Crooks <agc@netbsd.org> +uid Alistair Crooks <agc@netflix.com> + diff --git a/usr.bin/netpgpverify/data/expected25 b/usr.bin/netpgpverify/data/expected25 new file mode 100644 index 000000000000..093d9cf4a0d5 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected25 @@ -0,0 +1,7 @@ +Good signature for NetBSD-6.0_RC1_hashes.gpg made Tue Oct 16 08:12:16 2012 +signature 4096/RSA (Encrypt or Sign) 064973ac4c4a706e 2009-06-23 +fingerprint: ddee 2bdb 9c98 a0d1 d4fb dbf7 0649 73ac 4c4a 706e +uid NetBSD Security Officer <security-officer@NetBSD.org> +encryption 4096/RSA (Encrypt or Sign) 9ff2c24fdf2ce620 2009-06-23 [Expiry 2019-06-21] +fingerprint: 1915 0801 fbd8 f45d 89f2 0205 9ff2 c24f df2c e620 + diff --git a/usr.bin/netpgpverify/data/expected26 b/usr.bin/netpgpverify/data/expected26 new file mode 100644 index 000000000000..a97b231f1c2b --- /dev/null +++ b/usr.bin/netpgpverify/data/expected26 @@ -0,0 +1,7 @@ +Good signature for [stdin] made Tue Oct 16 08:12:16 2012 +signature 4096/RSA (Encrypt or Sign) 064973ac4c4a706e 2009-06-23 +fingerprint: ddee 2bdb 9c98 a0d1 d4fb dbf7 0649 73ac 4c4a 706e +uid NetBSD Security Officer <security-officer@NetBSD.org> +encryption 4096/RSA (Encrypt or Sign) 9ff2c24fdf2ce620 2009-06-23 [Expiry 2019-06-21] +fingerprint: 1915 0801 fbd8 f45d 89f2 0205 9ff2 c24f df2c e620 + diff --git a/usr.bin/netpgpverify/data/expected27 b/usr.bin/netpgpverify/data/expected27 new file mode 100644 index 000000000000..aeee21f0bda9 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected27 @@ -0,0 +1,5 @@ +Good signature for [stdin] made Mon Oct 15 09:28:54 2012 +signature 4096/RSA (Encrypt or Sign) 064973ac4c4a706e 2009-06-23 +fingerprint ddee 2bdb 9c98 a0d1 d4fb dbf7 0649 73ac 4c4a 706e +uid NetBSD Security Officer <security-officer@NetBSD.org> + diff --git a/usr.bin/netpgpverify/data/expected28 b/usr.bin/netpgpverify/data/expected28 new file mode 100644 index 000000000000..e67338d8fe2e --- /dev/null +++ b/usr.bin/netpgpverify/data/expected28 @@ -0,0 +1,5 @@ +Good signature for NetBSD-6.0_hashes.asc made Mon Oct 15 09:28:54 2012 +signature 4096/RSA (Encrypt or Sign) 064973ac4c4a706e 2009-06-23 +fingerprint ddee 2bdb 9c98 a0d1 d4fb dbf7 0649 73ac 4c4a 706e +uid NetBSD Security Officer <security-officer@NetBSD.org> + diff --git a/usr.bin/netpgpverify/data/expected29 b/usr.bin/netpgpverify/data/expected29 new file mode 100644 index 000000000000..8eeb1d6dc8dd --- /dev/null +++ b/usr.bin/netpgpverify/data/expected29 @@ -0,0 +1,7 @@ +Good signature for NetBSD-6.0_RC1_hashes_ascii.gpg made Sun Sep 9 17:41:24 2012 +signature 4096/RSA (Encrypt or Sign) 064973ac4c4a706e 2009-06-23 +fingerprint: ddee 2bdb 9c98 a0d1 d4fb dbf7 0649 73ac 4c4a 706e +uid NetBSD Security Officer <security-officer@NetBSD.org> +encryption 4096/RSA (Encrypt or Sign) 9ff2c24fdf2ce620 2009-06-23 [Expiry 2019-06-21] +fingerprint: 1915 0801 fbd8 f45d 89f2 0205 9ff2 c24f df2c e620 + diff --git a/usr.bin/netpgpverify/data/expected30 b/usr.bin/netpgpverify/data/expected30 new file mode 100644 index 000000000000..d1e6d6df6d68 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected30 @@ -0,0 +1,7 @@ +Good signature for [stdin] made Sun Sep 9 17:41:24 2012 +signature 4096/RSA (Encrypt or Sign) 064973ac4c4a706e 2009-06-23 +fingerprint: ddee 2bdb 9c98 a0d1 d4fb dbf7 0649 73ac 4c4a 706e +uid NetBSD Security Officer <security-officer@NetBSD.org> +encryption 4096/RSA (Encrypt or Sign) 9ff2c24fdf2ce620 2009-06-23 [Expiry 2019-06-21] +fingerprint: 1915 0801 fbd8 f45d 89f2 0205 9ff2 c24f df2c e620 + diff --git a/usr.bin/netpgpverify/data/expected31 b/usr.bin/netpgpverify/data/expected31 new file mode 100644 index 000000000000..1d30ff583935 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected31 @@ -0,0 +1,33 @@ +PROG=p +SRCS=parse.c +WARNS=5 +MKMAN=no +CPPFLAGS+=-g -O0 +LDFLAGS+=-g -O0 + +.include <bsd.prog.mk> + +t: ${PROG} + ./${PROG} gpgsigned-a.gpg +PROG=p +SRCS=parse.c +WARNS=5 +MKMAN=no +CPPFLAGS+=-g -O0 +LDFLAGS+=-g -O0 + +.include <bsd.prog.mk> + +t: ${PROG} + ./${PROG} gpgsigned-a.gpg +PROG=p +SRCS=parse.c +WARNS=5 +MKMAN=no +CPPFLAGS+=-g -O0 +LDFLAGS+=-g -O0 + +.include <bsd.prog.mk> + +t: ${PROG} + ./${PROG} gpgsigned-a.gpg diff --git a/usr.bin/netpgpverify/data/expected32 b/usr.bin/netpgpverify/data/expected32 new file mode 100644 index 000000000000..dadff9f794ca --- /dev/null +++ b/usr.bin/netpgpverify/data/expected32 @@ -0,0 +1,24 @@ +Good signature for b.gpg made Mon Sep 10 00:15:38 2012 +signature 2048/RSA (Encrypt or Sign) 1b68dcfcc0596823 2004-01-12 +fingerprint d415 9deb 336d e4cc cdfa 00cd 1b68 dcfc c059 6823 +uid Alistair Crooks <agc@alistaircrooks.com> +uid Alistair Crooks <agc@pkgsrc.org> +uid Alistair Crooks <agc@netbsd.org> +uid Alistair Crooks <agc@netflix.com> + +Good signature for b.gpg made Mon Sep 10 00:15:38 2012 +signature 2048/RSA (Encrypt or Sign) 1b68dcfcc0596823 2004-01-12 +fingerprint d415 9deb 336d e4cc cdfa 00cd 1b68 dcfc c059 6823 +uid Alistair Crooks <agc@alistaircrooks.com> +uid Alistair Crooks <agc@pkgsrc.org> +uid Alistair Crooks <agc@netbsd.org> +uid Alistair Crooks <agc@netflix.com> + +Good signature for b.gpg made Mon Sep 10 00:15:38 2012 +signature 2048/RSA (Encrypt or Sign) 1b68dcfcc0596823 2004-01-12 +fingerprint d415 9deb 336d e4cc cdfa 00cd 1b68 dcfc c059 6823 +uid Alistair Crooks <agc@alistaircrooks.com> +uid Alistair Crooks <agc@pkgsrc.org> +uid Alistair Crooks <agc@netbsd.org> +uid Alistair Crooks <agc@netflix.com> + diff --git a/usr.bin/netpgpverify/data/expected33 b/usr.bin/netpgpverify/data/expected33 new file mode 100644 index 000000000000..1e078bb06e73 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected33 @@ -0,0 +1,40 @@ +PROG=p +SRCS=parse.c +WARNS=5 +MKMAN=no +CPPFLAGS+=-g -O0 +LDFLAGS+=-g -O0 + +.include <bsd.prog.mk> + +t: ${PROG} + ./${PROG} gpgsigned-a.gpg +1. tag & 0x3f +2. len + +one pass (tag 4) +======== +b version:3 +b sig type +b hash alg +b pubkey alg +8b keyid + +literal data (tag 11) +============= +b binary/text +b length +c string +L mtime +text +PROG=p +SRCS=parse.c +WARNS=5 +MKMAN=no +CPPFLAGS+=-g -O0 +LDFLAGS+=-g -O0 + +.include <bsd.prog.mk> + +t: ${PROG} + ./${PROG} gpgsigned-a.gpg diff --git a/usr.bin/netpgpverify/data/expected34 b/usr.bin/netpgpverify/data/expected34 new file mode 100644 index 000000000000..27a6592c3122 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected34 @@ -0,0 +1,8 @@ +Good signature for det.sig made Thu Oct 18 02:12:33 2012 +signature 2048/RSA (Encrypt or Sign) 1b68dcfcc0596823 2004-01-12 +fingerprint d415 9deb 336d e4cc cdfa 00cd 1b68 dcfc c059 6823 +uid Alistair Crooks <agc@alistaircrooks.com> +uid Alistair Crooks <agc@pkgsrc.org> +uid Alistair Crooks <agc@netbsd.org> +uid Alistair Crooks <agc@netflix.com> + diff --git a/usr.bin/netpgpverify/data/expected35 b/usr.bin/netpgpverify/data/expected35 new file mode 100644 index 000000000000..04dc803533a2 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected35 @@ -0,0 +1,16 @@ +To Do +===== +tests with -k sig +detached sigs +DSA + +Done +==== +basics +localise pgp_read_packets +fix lint +WARNS=5 +lib man page +prog man page +do we do it statically linked as well? +multiple files in netpgpverify diff --git a/usr.bin/netpgpverify/data/expected36 b/usr.bin/netpgpverify/data/expected36 new file mode 100644 index 000000000000..6ea2a3d30d68 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected36 @@ -0,0 +1,5 @@ +Good signature for in1.gpg made Mon Oct 22 04:45:41 2012 +signature 2048/DSA 263fe78562e2fc7e 2012-10-21 +fingerprint d2e5 07b6 5d59 33d3 9c8d a618 263f e785 62e2 fc7e +uid David Armstrong (Test DSA key - do not use) <dsa@dsa.com> + diff --git a/usr.bin/netpgpverify/data/expected37 b/usr.bin/netpgpverify/data/expected37 new file mode 100644 index 000000000000..1e6162a68e35 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected37 @@ -0,0 +1,5 @@ +Good signature for [stdin] made Mon Oct 22 04:45:41 2012 +signature 2048/DSA 263fe78562e2fc7e 2012-10-21 +fingerprint d2e5 07b6 5d59 33d3 9c8d a618 263f e785 62e2 fc7e +uid David Armstrong (Test DSA key - do not use) <dsa@dsa.com> + diff --git a/usr.bin/netpgpverify/data/expected38 b/usr.bin/netpgpverify/data/expected38 new file mode 100644 index 000000000000..65f8b1fc90df --- /dev/null +++ b/usr.bin/netpgpverify/data/expected38 @@ -0,0 +1,5 @@ +Good signature for in1.asc made Mon Oct 22 04:45:26 2012 +signature 2048/DSA 263fe78562e2fc7e 2012-10-21 +fingerprint d2e5 07b6 5d59 33d3 9c8d a618 263f e785 62e2 fc7e +uid David Armstrong (Test DSA key - do not use) <dsa@dsa.com> + diff --git a/usr.bin/netpgpverify/data/expected39 b/usr.bin/netpgpverify/data/expected39 new file mode 100644 index 000000000000..b6d57029d3cf --- /dev/null +++ b/usr.bin/netpgpverify/data/expected39 @@ -0,0 +1,5 @@ +Good signature for [stdin] made Mon Oct 22 04:45:26 2012 +signature 2048/DSA 263fe78562e2fc7e 2012-10-21 +fingerprint d2e5 07b6 5d59 33d3 9c8d a618 263f e785 62e2 fc7e +uid David Armstrong (Test DSA key - do not use) <dsa@dsa.com> + diff --git a/usr.bin/netpgpverify/data/expected40 b/usr.bin/netpgpverify/data/expected40 new file mode 100644 index 000000000000..a4bda3c562f9 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected40 @@ -0,0 +1,6 @@ +# .NetBSD: Makefile,v 1.5.10.1 2012/05/06 18:14:16 agc Exp . + +SUBDIR+= lib .WAIT +SUBDIR+= bin + +.include <bsd.subdir.mk> diff --git a/usr.bin/netpgpverify/data/expected41 b/usr.bin/netpgpverify/data/expected41 new file mode 100644 index 000000000000..a4bda3c562f9 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected41 @@ -0,0 +1,6 @@ +# .NetBSD: Makefile,v 1.5.10.1 2012/05/06 18:14:16 agc Exp . + +SUBDIR+= lib .WAIT +SUBDIR+= bin + +.include <bsd.subdir.mk> diff --git a/usr.bin/netpgpverify/data/expected42 b/usr.bin/netpgpverify/data/expected42 new file mode 100644 index 000000000000..a4bda3c562f9 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected42 @@ -0,0 +1,6 @@ +# .NetBSD: Makefile,v 1.5.10.1 2012/05/06 18:14:16 agc Exp . + +SUBDIR+= lib .WAIT +SUBDIR+= bin + +.include <bsd.subdir.mk> diff --git a/usr.bin/netpgpverify/data/expected43 b/usr.bin/netpgpverify/data/expected43 new file mode 100644 index 000000000000..a4bda3c562f9 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected43 @@ -0,0 +1,6 @@ +# .NetBSD: Makefile,v 1.5.10.1 2012/05/06 18:14:16 agc Exp . + +SUBDIR+= lib .WAIT +SUBDIR+= bin + +.include <bsd.subdir.mk> diff --git a/usr.bin/netpgpverify/data/expected44 b/usr.bin/netpgpverify/data/expected44 new file mode 100644 index 000000000000..a8786ee113c9 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected44 @@ -0,0 +1,5 @@ +Good signature for in2.gpg made Mon Oct 22 06:24:09 2012 +signature 2048/DSA 263fe78562e2fc7e 2012-10-21 +fingerprint d2e5 07b6 5d59 33d3 9c8d a618 263f e785 62e2 fc7e +uid David Armstrong (Test DSA key - do not use) <dsa@dsa.com> + diff --git a/usr.bin/netpgpverify/data/expected45 b/usr.bin/netpgpverify/data/expected45 new file mode 100644 index 000000000000..379ffce293e8 --- /dev/null +++ b/usr.bin/netpgpverify/data/expected45 @@ -0,0 +1,5 @@ +Good signature for in2.asc made Mon Oct 22 06:24:26 2012 +signature 2048/DSA 263fe78562e2fc7e 2012-10-21 +fingerprint d2e5 07b6 5d59 33d3 9c8d a618 263f e785 62e2 fc7e +uid David Armstrong (Test DSA key - do not use) <dsa@dsa.com> + diff --git a/usr.bin/netpgpverify/data/expected46 b/usr.bin/netpgpverify/data/expected46 new file mode 100644 index 000000000000..4c262d05b98e --- /dev/null +++ b/usr.bin/netpgpverify/data/expected46 @@ -0,0 +1,8 @@ +Ignoring unusual/reserved signature subpacket 18 +Good signature for NetBSD-6.0_hashes.asc made Mon Oct 15 09:28:54 2012 +signature 4096/RSA (Encrypt or Sign) 064973ac4c4a706e 2009-06-23 +fingerprint: ddee 2bdb 9c98 a0d1 d4fb dbf7 0649 73ac 4c4a 706e +uid NetBSD Security Officer <security-officer@NetBSD.org> +encryption 4096/RSA (Encrypt or Sign) 9ff2c24fdf2ce620 2009-06-23 [Expiry 2019-06-21] +fingerprint: 1915 0801 fbd8 f45d 89f2 0205 9ff2 c24f df2c e620 + diff --git a/usr.bin/netpgpverify/data/in1.asc b/usr.bin/netpgpverify/data/in1.asc new file mode 100644 index 000000000000..d2b79f60f77d --- /dev/null +++ b/usr.bin/netpgpverify/data/in1.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +# .NetBSD: Makefile,v 1.5.10.1 2012/05/06 18:14:16 agc Exp . + +SUBDIR+= lib .WAIT +SUBDIR+= bin + +.include <bsd.subdir.mk> +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.11 (NetBSD) + +iF4EAREIAAYFAlCFMdYACgkQJj/nhWLi/H7CkQEAgDQrFwPD76JC+6FnOKEz/9DP +H7WjRRMoIQNTGC3ZXRsA/1xah8eFePQDmTO1sQGnINbgX9vZ7GAFOgTjW7+tVb7H +=wtKb +-----END PGP SIGNATURE----- diff --git a/usr.bin/netpgpverify/data/in1.gpg b/usr.bin/netpgpverify/data/in1.gpg Binary files differnew file mode 100644 index 000000000000..3e96e861ff56 --- /dev/null +++ b/usr.bin/netpgpverify/data/in1.gpg diff --git a/usr.bin/netpgpverify/data/in2.asc b/usr.bin/netpgpverify/data/in2.asc new file mode 100644 index 000000000000..aaf8e119456c --- /dev/null +++ b/usr.bin/netpgpverify/data/in2.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +# .NetBSD: Makefile,v 1.5.10.1 2012/05/06 18:14:16 agc Exp . + +SUBDIR+= lib .WAIT +SUBDIR+= bin + +.include <bsd.subdir.mk> +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.11 (NetBSD) + +iF4EAREIAAYFAlCFSQoACgkQJj/nhWLi/H6aKAD9HCLTwY8CwiqTXrzKxHZ5lHQn +qEZbcbXjkCxlk+m/PHUA/2Whlc0t5ZtmI221LQy5inTnzpu1U75E5lJvw0YMTdXJ +=v788 +-----END PGP SIGNATURE----- diff --git a/usr.bin/netpgpverify/data/in2.gpg b/usr.bin/netpgpverify/data/in2.gpg Binary files differnew file mode 100644 index 000000000000..83a7dfbe61fc --- /dev/null +++ b/usr.bin/netpgpverify/data/in2.gpg diff --git a/usr.bin/netpgpverify/data/jj.asc b/usr.bin/netpgpverify/data/jj.asc new file mode 100644 index 000000000000..65661d69f8db --- /dev/null +++ b/usr.bin/netpgpverify/data/jj.asc @@ -0,0 +1,32 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +1. tag & 0x3f +2. len + +one pass (tag 4) +======== +b version:3 +b sig type +b hash alg +b pubkey alg +8b keyid + +literal data (tag 11) +============= +b binary/text +b length +c string +L mtime +text +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.11 (NetBSD) + +iQEcBAEBAgAGBQJQaIZcAAoJEBto3PzAWWgj678IALbDHon3Rm6qUhn7k1TFT6D3 +yi/jzf3piSJGsgUg2wEghs175edC/cJK3lG9Gx/3/uQq06R9g37nVRX8I0sK7yT2 +XgR+RHoGh/b+CQxdRNC+ub5QoNb8LcmCb/MQGq2KK9otSExiy4WMUP4K1DblaK5L ++Hg4VTooMot1NVqyFSoB2aZauXc2F4ZVh5q0fn8w5GEw45P+AUUbmzpgbLwXbl+I +tMsX54V1dxyDcCYUs0xUH/VxJUQEeIlDbCOXYMbCVtggYRqKksTr+u/riw/Llnql +jQdq5rBRW1SlD7Ll6z/LF2WBJOWtHzp4qbnBGSq5uB1q37H3mWL28f1tL//TUjM= +=EX8W +-----END PGP SIGNATURE----- diff --git a/usr.bin/netpgpverify/data/message b/usr.bin/netpgpverify/data/message new file mode 100644 index 000000000000..08844f75c649 --- /dev/null +++ b/usr.bin/netpgpverify/data/message @@ -0,0 +1 @@ +This is an example messsage. diff --git a/usr.bin/netpgpverify/data/message.keyring b/usr.bin/netpgpverify/data/message.keyring Binary files differnew file mode 100644 index 000000000000..2ae71b9e2d7f --- /dev/null +++ b/usr.bin/netpgpverify/data/message.keyring diff --git a/usr.bin/netpgpverify/data/message.v1.asc b/usr.bin/netpgpverify/data/message.v1.asc new file mode 100644 index 000000000000..238ee4df345b --- /dev/null +++ b/usr.bin/netpgpverify/data/message.v1.asc @@ -0,0 +1,14 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +This is an example messsage. +-----BEGIN PGP SIGNATURE----- + +iQEcBAEBAgAGBQJpe96fAAoJEIGRNTbVsiooKJAIAI7DdO0v1pqIF/EdCELBLmSk +BlKFeKIl2k5GEh6Z6LUHebiJd1GfpNN7Pf99oqyRm9dg3bDdfZ6BdJkiEJtEQ8kz +PXqoMhdSQ9rtmYxyZBMYVcGFFizl/mpXupwi9Rq7hRogr7NDLaJVFwwDrGrx5mSU +A2pKAeejB0F5l/rbpfzErqnajBeCZmzjCkPlgfKGMSSiVONC2rxTYyJUa6pSLruq +jrfgfsmDk6TLKXA8xNchCyMJoIs3Drtq7XeY9Y7FFPEY9hFH8+YYZmElaK8XOzYy +tLeMCwCdLMwL7mmS2rFAg4U60zIYUzWI1nWBaHBVlv50mtTuiNN83/axIpoI3dE= +=cW1k +-----END PGP SIGNATURE----- diff --git a/usr.bin/netpgpverify/data/message.v1.asc.expected b/usr.bin/netpgpverify/data/message.v1.asc.expected new file mode 100644 index 000000000000..14e76b1ced74 --- /dev/null +++ b/usr.bin/netpgpverify/data/message.v1.asc.expected @@ -0,0 +1,5 @@ +Good signature for message.v1.asc made Thu Jan 29 23:26:39 2026 +signature 2048/RSA (Encrypt or Sign) 81913536d5b22a28 2026-01-29 +fingerprint 5bc4 b091 22be 606e d732 8a08 8191 3536 d5b2 2a28 +uid Test Key <test@example.com> + diff --git a/usr.bin/netpgpverify/data/message.v1.sig b/usr.bin/netpgpverify/data/message.v1.sig Binary files differnew file mode 100644 index 000000000000..c2bc90f3d971 --- /dev/null +++ b/usr.bin/netpgpverify/data/message.v1.sig diff --git a/usr.bin/netpgpverify/data/message.v1.sig.expected b/usr.bin/netpgpverify/data/message.v1.sig.expected new file mode 100644 index 000000000000..362d5f2aaa31 --- /dev/null +++ b/usr.bin/netpgpverify/data/message.v1.sig.expected @@ -0,0 +1,5 @@ +Good signature for message.v1.sig made Thu Jan 29 23:26:23 2026 +signature 2048/RSA (Encrypt or Sign) 81913536d5b22a28 2026-01-29 +fingerprint 5bc4 b091 22be 606e d732 8a08 8191 3536 d5b2 2a28 +uid Test Key <test@example.com> + diff --git a/usr.bin/netpgpverify/data/message.v2.asc b/usr.bin/netpgpverify/data/message.v2.asc new file mode 100644 index 000000000000..abff22db4e15 --- /dev/null +++ b/usr.bin/netpgpverify/data/message.v2.asc @@ -0,0 +1,15 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA256 + +This is an example messsage. +-----BEGIN PGP SIGNATURE----- + +iQEzBAEBCAAdFiEEW8SwkSK+YG7XMooIgZE1NtWyKigFAml730EACgkQgZE1NtWy +KijBCwf/aMxfreT1hNjzwfE9cHFVgjfI+P0pzuf4HVM6Xv3niQAV6Kn8hIn4hlS2 +oyo1aKoqek8EKKBHXWi6oTQ3AjfsJDzte2axE2w1TKCRQucSL7kaJAFpHmTM0gr6 +nQsoba1aFuxIa9ENRs5SsW47IdR5gFTg9QXdX2LepGFHDk9kULOy90xt2aHXpdft +COvz/9KTok97gi+Tc0YsF+IExIQe0/LkadziKVI3GwyEgksaJw6h7aCF5YxA6N5c +R6jgGmBtKzjeDb8IbFH+IRuBZGzt2r7a3CiScgOjm1T3Z/kVETBor7nBYCcb5S6q +dIZlIMOdempGnvznuzBJGZBWLECMxQ== +=5+xC +-----END PGP SIGNATURE----- diff --git a/usr.bin/netpgpverify/data/message.v2.asc.expected b/usr.bin/netpgpverify/data/message.v2.asc.expected new file mode 100644 index 000000000000..358f71d49ae9 --- /dev/null +++ b/usr.bin/netpgpverify/data/message.v2.asc.expected @@ -0,0 +1,5 @@ +Good signature for message.v2.asc made Thu Jan 29 23:29:21 2026 +signature 2048/RSA (Encrypt or Sign) 81913536d5b22a28 2026-01-29 +fingerprint 5bc4 b091 22be 606e d732 8a08 8191 3536 d5b2 2a28 +uid Test Key <test@example.com> + diff --git a/usr.bin/netpgpverify/data/message.v2.sig b/usr.bin/netpgpverify/data/message.v2.sig Binary files differnew file mode 100644 index 000000000000..09cf3957d628 --- /dev/null +++ b/usr.bin/netpgpverify/data/message.v2.sig diff --git a/usr.bin/netpgpverify/data/message.v2.sig.expected b/usr.bin/netpgpverify/data/message.v2.sig.expected new file mode 100644 index 000000000000..0baf1a35684f --- /dev/null +++ b/usr.bin/netpgpverify/data/message.v2.sig.expected @@ -0,0 +1,5 @@ +Good signature for message.v2.sig made Thu Jan 29 23:29:14 2026 +signature 2048/RSA (Encrypt or Sign) 81913536d5b22a28 2026-01-29 +fingerprint 5bc4 b091 22be 606e d732 8a08 8191 3536 d5b2 2a28 +uid Test Key <test@example.com> + diff --git a/usr.bin/netpgpverify/data/pubring.gpg b/usr.bin/netpgpverify/data/pubring.gpg Binary files differnew file mode 100644 index 000000000000..796a40a1398a --- /dev/null +++ b/usr.bin/netpgpverify/data/pubring.gpg diff --git a/usr.bin/shmif_pcapin/Makefile b/usr.bin/shmif_pcapin/Makefile new file mode 100644 index 000000000000..30a9f8347f72 --- /dev/null +++ b/usr.bin/shmif_pcapin/Makefile @@ -0,0 +1,11 @@ +.include <bsd.own.mk> + +TESTSDIR= ${TESTSBASE}/usr.bin/shmif_pcapin +FILESDIR= ${TESTSDIR} + +TESTS_SH+= t_basic +TESTS_SH_SRC_t_basic= ../../net/net_common.sh t_basic.sh + +FILES+= d_pcap.in.bz2.uue d_pcap.out.bz2.uue + +.include <bsd.test.mk> diff --git a/usr.bin/shmif_pcapin/d_pcap.in.bz2.uue b/usr.bin/shmif_pcapin/d_pcap.in.bz2.uue new file mode 100644 index 000000000000..f7bebd31beb4 --- /dev/null +++ b/usr.bin/shmif_pcapin/d_pcap.in.bz2.uue @@ -0,0 +1,27 @@ +begin 644 d_pcap.in.bz2 +M0EIH.3%!6293671X8T@`",M_______TOA>KK]E_____W_____^\C:_:XZKOZ +M]#3:(5__T`/^`.@`&YM"%4,@-`!DQJ````T9&@``````T-!DT`&@```````` +M`:`/*%*@]1^GJHT`!ZAM(```#0T```:`!H:``&@````````````#1"?_ZJJ8 +MF`F```````!,``````````$R8````````$PFF(`T#30:#$R`&AD&C`(`#31D +M!A`9,@R:9-#$9,@-``:,@8F3(```#0`"HI(HU-I)Z0]0]1Z@`&F@:``-H@TR +M#:0\I_ZJ@]1I@@/4:,1ZAM33:FAIM3)ZCU-&F)^IFE/4\D:-E!Z@T:-J;-SK +MR`JJ%4J5)T*)-32B3R*)+)(CJ$2:E1)B(DZE826U/9(DPB3#@JQ9*B2PSSSS +M9LVP9M5FS9LV;-FS9LV;-FS9LV;-FS9YY^B\\0\^J17N5=!4RI/5U,(DK%&* +M+4Q6)$F+99227:0M%1)4F*+2]"26DF2),B\_$F%B2IHRPQ<&+5MEM7SBR),+ +M5NA$EP56V8PDD<U$E)I5'IE.XK)2KZVOS,FEDU^3H9-##$KC#IC=6T`````` +M`````````$!`^\_VJ&P;!ZKK/X\O9-8[E>O%K^>4,BKE+2UEE#G&E557XWT6 +M3)?&:'#=Z_8XKD/#<ISSQ7-=VYYWS6>=<=X3R;:N`W+<OE/FN&[MK/DNM:K5 +M5:B37(DK%Y:L63LU<^WK#KEAW"S0K;L&)$F_]WVR)-HB31I%Y*Z_'P[K:\!$ +MF6Q6N(B3'5:O3LMHB39(DP23<+QU<XI5B#=[S`R4V:)+.3X6#M>!@X2)+/;J +MU(2I$E@62254G\/$Y<AH=2T]`^6^\W3K42:>P?68W+;-5NVC?]BKLE>D1)[! +MAIV+L63:-'9,F.S=SP=#1O&'LU;Y7VE;5]MAL?N,,>Q8=$KE-&_9/NJR[5AT +M:OGJ<Q6[5-A3?.Z='X&@\TYB1NVX=XZIJ.*X;P'>O>NL=>UG?N*_6UW1/!<1 +MQ&V<1X+7<5Q7Q&NZMWW?]LUG\G&>&^DU72O+N4YCO'':6\=HWSKF]=H_JUVT +M8;IXC8."T.1QMN^1^'IG^6R;C>OZ$2<)>2[!I=6\JB2(!0'LHS1`1*+YBP:G +M<^L*HT2-$4:2-E635)24E@E*SFA]Z1`1.%C!!DXL&*2VN*BL9^L*\M)6`ZE7 +M35\PZ>-(A%.BD$,U)2TG'S,O.%EED(0A"(HOTT<OU]O?XC?D```````HI]&B +MI4911111B@:(7\)-.;XQ#&>&(8]>)+$G;[YCYC+M_H;?9NHB5R&HPYOI]5HZ +M>OIO&8((JP?0=@*@/^`GMR#G\",%>3">$0!3L@_2.$DN8QPFL,L#<G,@M@,: +J-JKQW2,:6F)XLZ5PWCHDXS0;&N$ITBCG5:$2?OYN3_XNY(IPH2#H\,:0 +` +end diff --git a/usr.bin/shmif_pcapin/d_pcap.out.bz2.uue b/usr.bin/shmif_pcapin/d_pcap.out.bz2.uue new file mode 100644 index 000000000000..616bf2369559 --- /dev/null +++ b/usr.bin/shmif_pcapin/d_pcap.out.bz2.uue @@ -0,0 +1,13 @@ +begin 644 d_pcap.out.bz2 +M0EIH.3%!62936>CJBS$`#$]?@``00&5_\0@B0``_Y?]@0`*8VP``<_2/4T_U +M4!,``0P1AS_]50(9#31D9&1H9,@)JDDTF*>13U/4&0>IFB:;:H8`9--!D,$- +M,1HQTI'UI>:/S1B,1J3^)&3UD9,D=9'Y(_1'A(_J1RD?*1Y5(]I&2/&1SD<D +M<T??OF9F````````".THE5<[;+;H6@P`!555408@``-!@!SY[[[[[[\_C(\) +M'"D<Y&J1D)=NFVM:^5(Q&D>$C$:1WD<9'K2/YD<N/'-:RY2,KQD95JD9(=9& +M^M]9K4C:D:N$C*OWD962,K_*1OQVUK761DC>1VD=Y''COK6MY'G(VD<,X:UK +MVD;R.'#AK6M4C)&I&LUK6MI&U(R1FVV:UY2.TCTD>,C4C?>S)'61QD;2,D=) +M'I(X2/A(X2.E([2.5(^<C*1\Y'TD;2/*D?1&Z,1B/61]I'_2-I'WI'X1[R,1 +M]I'=&\CI(])'>D>T)>\C>$O@CM2.<CZR-4CA(R1DC$=4=Z1J1VD>Z/Q(^,CS +.1VD?^+N2*<*$AT=468@C +` +end diff --git a/usr.bin/shmif_pcapin/t_basic.sh b/usr.bin/shmif_pcapin/t_basic.sh new file mode 100644 index 000000000000..ef364878e4bd --- /dev/null +++ b/usr.bin/shmif_pcapin/t_basic.sh @@ -0,0 +1,89 @@ +# $NetBSD: t_basic.sh,v 1.1 2024/09/02 05:16:37 ozaki-r Exp $ +# +# Copyright (c) 2017-2018 Internet Initiative Japan Inc. +# Copyright (c) 2011 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +SOCK=unix://commsock +BUS=bus0 + +unpack_file() +{ + + atf_check -s exit:0 uudecode $(atf_get_srcdir)/${1}.bz2.uue + atf_check -s exit:0 bunzip2 -f ${1}.bz2 +} + +atf_test_case pcap cleanup + +pcap_head() +{ + + atf_set "descr" "Write frames from pcap(3) file to shmif(4) interface" +} + +pcap_body() +{ + unpack_file d_pcap.in + unpack_file d_pcap.out + + rump_server_npf_start ${SOCK} # need librumpdev_bpf + rump_server_add_iface ${SOCK} shmif0 ${BUS} + + export RUMP_SERVER=${SOCK} + export LD_PRELOAD=/usr/lib/librumphijack.so + export RUMPHIJACK=path=/rump,socket=all:nolocal,sysctl=yes,,blanket=/dev/bpf + + atf_check -s exit:0 rump.ifconfig shmif0 up + + # Capture frames on shmif0 to examine later. + tcpdump -c 58 -eni shmif0 -w shmif0.in.pcap & + sleep 1 # give shmif0 a change to turn into promiscuous mode + # Write frames to the bus. + atf_check -s exit:0 -o ignore shmif_pcapin d_pcap.in ${BUS} + wait # for tcpdump to exit + + # Check if written frames surely arrives at shmif0. + atf_check -s exit:0 -o match:"input: 58 packets, 5684 bytes" rump.ifconfig -v shmif0 + # Check if frames captured on shmif0 are expected ones. + atf_check -s exit:0 -o file:d_pcap.out -e ignore tcpdump -entr shmif0.in.pcap + + unset LD_PRELOAD + unset RUMP_SERVER +} + +pcap_cleanup() +{ + + $DEBUG && dump + cleanup +} + + +atf_init_test_cases() +{ + + atf_add_test_case pcap +} diff --git a/usr.bin/stat/Makefile b/usr.bin/stat/Makefile new file mode 100644 index 000000000000..9118b2434b8f --- /dev/null +++ b/usr.bin/stat/Makefile @@ -0,0 +1,7 @@ +# $NetBSD: Makefile,v 1.1 2024/03/14 21:00:33 rillig Exp $ + +TESTSDIR= ${TESTSBASE}/usr.bin/stat + +TESTS_SH= t_stat + +.include <bsd.test.mk> diff --git a/usr.bin/stat/t_stat.sh b/usr.bin/stat/t_stat.sh new file mode 100644 index 000000000000..b4bc56320d18 --- /dev/null +++ b/usr.bin/stat/t_stat.sh @@ -0,0 +1,68 @@ +# $NetBSD: t_stat.sh,v 1.2 2024/03/14 21:17:54 rillig Exp $ +# +# Copyright (c) 2024 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Roland Illig. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +atf_test_case string_format +string_format_head() { + atf_set "descr" "Tests the string output format 'S'" +} +string_format_body() { + echo 'äöü' > './Ümläute' + + atf_check -o 'inline:plain <Ümläute>\n' \ + stat -f 'plain <%SN>' 'Ümläute' + + atf_check -o 'inline:right-aligned < Ümläute>\n' \ + stat -f 'right-aligned <%20SN>' 'Ümläute' + + atf_check -o 'inline:left-aligned <Ümläute >\n' \ + stat -f 'left-aligned <%-20SN>' 'Ümläute' + + atf_check -s exit:1 -o ignore -e 'inline:stat: % SN: bad format\n' \ + stat -f 'string-space <% SN>' 'Ümläute' + + atf_check -s exit:1 -o ignore -e 'inline:stat: %+SN: bad format\n' \ + stat -f 'string-plus <%+SN>' 'Ümläute' + + atf_check -s exit:1 -o ignore -e 'inline:stat: %0SN: bad format\n' \ + stat -f 'string-zero <%0SN>' 'Ümläute' + + atf_check -o 'inline:vis <\303\234ml\303\244ute>\n' \ + stat -f 'vis <%#SN>' 'Ümläute' + + atf_check -o 'inline:vis left-aligned <\303\234ml\303\244ute >\n' \ + stat -f 'vis left-aligned <%#-30SN>' 'Ümläute' + + atf_check -o 'inline:vis right-aligned < \303\234ml\303\244ute>\n' \ + stat -f 'vis right-aligned <%#30SN>' 'Ümläute' +} + +atf_init_test_cases() { + atf_add_test_case string_format +} diff --git a/usr.bin/xlint/lint1/expr.c b/usr.bin/xlint/lint1/expr.c new file mode 100644 index 000000000000..77f64ffd00ba --- /dev/null +++ b/usr.bin/xlint/lint1/expr.c @@ -0,0 +1,33 @@ +/* $NetBSD: expr.c,v 1.1 2024/06/08 09:09:20 rillig Exp $ */ +# 3 "expr.c" + +/* + * Miscellaneous tests for expressions. + */ + +/* lint1-extra-flags: -X 351 */ + +struct bit_fields { + unsigned u32: 32; +}; + +unsigned long +expr_cond_cvt(unsigned long ul) +{ + struct bit_fields bits = { 0 }; + // Combining 'unsigned:32' and 'unsigned long' in the ':' operator + // results in 'unsigned long'. + return bits.u32 < ul ? bits.u32 : ul; +} + +// Before tree.c 1.76 from 2014-04-17, lint crashed with an internal error, +// due to an uninitialized right operand of a tree node. +void +crash_in_assignment(void) +{ + /* expect+1: warning: 'x' set but not used in function 'crash_in_assignment' [191] */ + double x = 1; + int foo = 0; + if (foo) + x = 1; +} diff --git a/usr.bin/xlint/lint1/gcc.c b/usr.bin/xlint/lint1/gcc.c new file mode 100644 index 000000000000..a239bfd83220 --- /dev/null +++ b/usr.bin/xlint/lint1/gcc.c @@ -0,0 +1,130 @@ +/* $NetBSD: gcc.c,v 1.7 2026/01/20 23:46:36 rillig Exp $ */ +# 3 "gcc.c" + +/* + * Miscellaneous tests that are specific to lint's GCC mode. + */ + +/* lint1-extra-flags: -chaapbrz -X 351 */ + +// Before C99 introduced __func__, GCC already had __FUNCTION__ with the same +// semantics. +const char * +gcc_function(void) +{ + /* expect+1: error: negative array dimension (-13) [20] */ + typedef int size[-(int)sizeof __FUNCTION__]; + + return __FUNCTION__; +} + +// Before C99 introduced designators in initializers, GCC already had them, +// although with a different syntax for struct/union members and with the +// a...b for ranges of array elements. +int array_range_initializers[256] = { + [2] = 1, + [3] = 2, + [4 ... 5] = 3 +}; + +_Bool dbl_isinf(double); + +// Test that the GCC '__extension__' and '__typeof' are recognized. +void +extension_and_typeof(void) +{ + double __logbw = 1; + if (__extension__(({ + __typeof((__logbw)) x_ = (__logbw); + !dbl_isinf((x_)); + }))) + __logbw = 1; +} + +int +range_in_case_label(int i) +{ + switch (i) { + case 1 ... 40: // This is a GCC extension. + return 1; + default: + return 2; + } +} + +union { + int i; + char *s; +} initialize_union_with_mixed_designators[] = { + { i: 1 }, /* GCC-style */ + { s: "foo" }, /* GCC-style */ + { .i = 1 }, /* C99-style */ + { .s = "foo" } /* C99-style */ +}; + +union { + int i[10]; + short s; +} initialize_union_with_gcc_designators[] = { + { s: 2 }, + { i: { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } }, +}; + +void +declaration_of_variable_array(int i) +{ + int array[i]; + while (i-- > 0) + array[i] = 0; +} + +/* + * Before cgram.y 1.226 from 2021-05-03, lint could not parse typeof(...) if + * there was a statement before it. + */ +void * +typeof_after_statement(void **ptr) +{ + return ({ + if (*ptr != (void *)0) + ptr++; + __typeof__(*ptr) ret = *ptr; + ret; + }); +} + +const char * +auto_type(const char *ptr) +{ + __auto_type pp = &ptr; + return *pp; +} + +void +atomic_functions(void) +{ + static unsigned long long v, *pv; + v = __atomic_load_n(pv, 0); + v = __atomic_exchange_n(pv, 0, 0); + v = __atomic_add_fetch(pv, 0, 0); + v = __atomic_sub_fetch(pv, 0, 0); + v = __atomic_and_fetch(pv, 0, 0); + v = __atomic_xor_fetch(pv, 0, 0); + v = __atomic_or_fetch(pv, 0, 0); + v = __atomic_nand_fetch(pv, 0, 0); + v = __atomic_fetch_add(pv, 0, 0); + v = __atomic_fetch_sub(pv, 0, 0); + v = __atomic_fetch_and(pv, 0, 0); + v = __atomic_fetch_xor(pv, 0, 0); + v = __atomic_fetch_or(pv, 0, 0); + v = __atomic_fetch_nand(pv, 0, 0); + + static char c, *pc; + c = __atomic_load_n(pc, 0); + c = __atomic_exchange_n(pc, 0, 0); + + /* expect+1: warning: conversion from 'unsigned long long' to 'char' may lose accuracy [132] */ + c = __atomic_exchange_n(pv, 0, 0); +} + +__float128 f128 = 0.0; diff --git a/usr.bin/xlint/lint1/init_c99.c b/usr.bin/xlint/lint1/init_c99.c new file mode 100644 index 000000000000..a9a72552bba2 --- /dev/null +++ b/usr.bin/xlint/lint1/init_c99.c @@ -0,0 +1,739 @@ +/* $NetBSD: init_c99.c,v 1.5 2025/04/12 15:49:50 rillig Exp $ */ +# 3 "init_c99.c" + +// Tests for initialization in C99 or later, mainly for designators. +// +// See C99 6.7.8 "Initialization". + +/* lint1-flags: -Sw -X 351 */ + +void use(const void *); + +typedef struct any { + const void *value; +} any; + + +// C99 6.7.8p11 says "optionally enclosed in braces". Whether this wording +// means "a single pair of braces" or "as many pairs of braces as you want" +// is left for interpretation to the reader. +int scalar_without_braces = 3; +int scalar_with_optional_braces = { 3 }; +int scalar_with_too_many_braces = {{ 3 }}; +/* expect+1: error: too many initializers for 'int' [174] */ +int scalar_with_too_many_initializers = { 3, 5 }; + + +// See initialization_expr, 'handing over to INIT'. +void +struct_initialization_via_assignment(any arg) +{ + any local = arg; + use(&local); +} + + +// See initialization_expr, initialization_init_array_from_string. +char static_duration[] = "static duration"; +signed char static_duration_signed[] = "static duration"; +unsigned char static_duration_unsigned[] = "static duration"; +int static_duration_wchar[] = L"static duration"; + +// See init_expr. +void +initialization_by_braced_string(void) +{ + any local = { "hello" }; + use(&local); +} + +void +initialization_by_redundantly_braced_string(void) +{ + any local = {{{{ "hello" }}}}; + use(&local); +} + +/* + * Only scalar expressions and string literals may be enclosed by additional + * braces. Since 'arg' is a struct, this is a compile-time error. + */ +void +initialization_with_too_many_braces(any arg) +{ + /* expect+1: error: cannot initialize 'pointer to const void' from 'struct any' [185] */ + any local = { arg }; + use(&arg); +} + +// Some of the following examples are mentioned in the introduction comment +// in init.c. + +int number = 12345; + +int number_with_braces_and_comma = { + 12345, +}; + +int array_with_fixed_size[3] = { + 111, + 222, + 333, + /* expect+1: error: too many array initializers, expected 3 [173] */ + 444, +}; + +// See update_type_of_array_of_unknown_size. +int array_of_unknown_size[] = { + 111, + 222, + 333, +}; + +int array_flat[2][2] = { + 11, + 12, + 21, + 22 +}; + +int array_nested[2][2] = { + { + 11, + 12 + }, + { + 21, + 22 + } +}; + +int array_with_designators[] = { + ['1'] = 111, + ['5'] = 555, + ['9'] = 999 +}; + +int array_with_some_designators[] = { + ['1'] = 111, + 222, + ['9'] = 999 +}; + +struct point { + int x; + int y; +}; + +struct point point = { + 3, + 4 +}; + +struct point point_with_designators = { + .y = 4, + .x = 3, +}; + +struct point point_with_mixed_designators = { + .x = 3, + 4, + /* expect+1: error: too many struct/union initializers [172] */ + 5, + .x = 3, +}; + +/* + * Before cgram.y 1.230 from 2021-06-20, the grammar allowed either of the + * operators '.' or '->' to be used for the designators and had extra code + * to ensure that only '.' was actually used. + */ +struct point origin = { + .x = 0, + /* expect+1: error: syntax error '->' [249] */ + ->y = 0, +}; + +/* Ensure that the parser can recover from the parse error. */ +struct point pythagoras = { 3, 4 }; + +int array_with_designator[] = { + 111, + /* expect+1: error: syntax error 'designator '.member' is only for struct/union' [249] */ + .member = 222, + 333, +}; + +/* + * C99 6.7.8p11 says that the initializer of a scalar can be "optionally + * enclosed in braces". It does not explicitly set an upper limit on the + * number of braces. It also doesn't restrict the term "initializer" to only + * mean the "outermost initializer". 6.7.8p13 defines that a brace for a + * structure or union always means to descend into the type. Both GCC 10 and + * Clang 8 already warn about these extra braces, nevertheless there is + * real-life code (the Postfix MTA) that exploits this corner case of the + * standard. + */ +struct point scalar_with_several_braces = { + {{{3}}}, + {{{{4}}}}, +}; + +struct rectangle { + struct point top_left; + struct point bottom_right; +}; + +/* C99 6.7.8p18 */ +struct rectangle screen = { + .bottom_right = { + 1920, + 1080, + } +}; + +/* + * C99 6.7.8p22 says: At the _end_ of its initializer list, the array no + * longer has incomplete type. + */ +struct point points[] = { + { + /* + * At this point, the size of the object 'points' is not known + * yet since its type is still incomplete. Lint could warn + * about this, but GCC and Clang already do. + * + * Before init.c 1.179 from 2021.03.30, the type information + * of 'points' was set too early, resulting in a negative + * array size below. + */ + sizeof(int[-(int)sizeof(points)]), + 4 + } +}; + + +struct triangle { + struct point points[3]; +}; + +struct pentagon { + struct point points[5]; +}; + +struct geometry { + struct pentagon pentagons[6]; + struct triangle triangles[10]; + struct point points[3][5][2]; +}; + +/* + * Initialization of a complex struct containing nested arrays and nested + * structs. + */ +struct geometry geometry = { + .pentagons[0].points[4].x = 1, + .points[0][0][0] = { 0, 0 }, + .points[2][4][1] = {301, 302 }, + /* expect+1: error: array subscript 3 cannot be > 2 [168] */ + .points[3][0][0] = {3001, 3002 }, + /* expect+1: error: array subscript 5 cannot be > 4 [168] */ + .points[0][5][0] = {501, 502 }, + /* expect+1: error: array subscript 2 cannot be > 1 [168] */ + .points[0][0][2] = {21, 22 }, +}; + +struct ends_with_unnamed_bit_field { + int member; + int:0; +} ends_with_unnamed_bit_field = { + 12345, + /* expect+1: error: too many struct/union initializers [172] */ + 23456, +}; + +char prefixed_message[] = { + 'E', ':', ' ', + /* expect+1: warning: invalid combination of integer 'char' and pointer 'pointer to char' for 'init' [183] */ + "message\n", +}; + +char message_with_suffix[] = { + "message", + /* The excess character is not detected by lint but by compilers. */ + '\n', +}; + +struct ten { + int i0; + int i1; + int i2; + int i3; + int i4; + int i5; + int i6; + int i7; + int i8; + int i9; +}; + +struct ten ten = { + .i3 = 3, + 4, + 5, + 6, +}; + + +/* + * ISO C99 6.7.8 provides a large list of examples for initialization, + * covering all tricky edge cases. + */ + +/* expect+1: warning: lossy conversion of 3.5 to 'int' [381] */ +int c99_6_7_8_p24_example1_i = 3.5; +double _Complex c99_6_7_8_p24_example1_c = 5 + 3 * 1.0fi; + +int c99_6_7_8_p25_example2[] = { 1, 3, 5 }; + +int c99_6_7_8_p26_example3a[4][3] = { + { 1, 3, 5 }, + { 2, 4, 6 }, + { 3, 5, 7 }, +}; + +int c99_6_7_8_p26_example3b[4][3] = { + 1, 3, 5, 2, 4, 6, 3, 5, 7 +}; + +int c99_6_7_8_p27_example4[4][3] = { + { 1 }, { 2 }, { 3 }, { 4 } +}; + +struct { + int a[3], b; +} c99_6_7_8_p28_example5[] = { + { 1 }, + 2, +}; + +short c99_6_7_8_p29_example6a[4][3][2] = { + { 1 }, + { 2, 3 }, + { 4, 5, 6 }, +}; + +short c99_6_7_8_p29_example6b[4][3][2] = { + 1, 0, 0, 0, 0, 0, + 2, 3, 0, 0, 0, 0, + 4, 5, 6, 0, 0, 0, +}; + +short c99_6_7_8_p29_example6c[4][3][2] = { + { + { 1 }, + }, + { + { 2, 3 }, + }, + { + { 4, 5 }, + { 6 }, + } +}; + +void +c99_6_7_8_p31_example7(void) +{ + typedef int A[]; + + A a = { 1, 2 }, b = { 3, 4, 5 }; + + /* expect+1: error: negative array dimension (-8) [20] */ + typedef int reveal_sizeof_a[-(int)(sizeof(a))]; + /* expect+1: error: negative array dimension (-12) [20] */ + typedef int reveal_sizeof_b[-(int)(sizeof(b))]; +} + +char c99_6_7_8_p32_example8_s1[] = "abc", + c99_6_7_8_p32_example8_t1[3] = "abc"; +char c99_6_7_8_p32_example8_s2[] = { 'a', 'b', 'c', '\0' }, + c99_6_7_8_p32_example8_t2[3] = { 'a', 'b', 'c' }; +char *c99_6_7_8_p32_example8_p = "abc"; + +enum { member_one, member_two }; +const char *c99_6_7_8_p33_example9[] = { + [member_two] = "member two", + [member_one] = "member one", +}; + +struct { + int quot, rem; +} c99_6_7_8_p34_example10 = { .quot = 2, .rem = -1 }; + +struct { int a[3], b; } c99_6_7_8_p35_example11[] = + { [0].a = {1}, [1].a[0] = 2 }; + +int c99_6_7_8_p36_example12a[16] = { + 1, 3, 5, 7, 9, [16-5] = 8, 6, 4, 2, 0 +}; + +int c99_6_7_8_p36_example12b[8] = { + 1, 3, 5, 7, 9, [8-5] = 8, 6, 4, 2, 0 +}; + +union { + int first_member; + void *second_member; + unsigned char any_member; +} c99_6_7_8_p38_example13 = { .any_member = 42 }; + + +/* + * During initialization of an object of type array of unknown size, the type + * information on the symbol is updated in-place. Ensure that this happens on + * a copy of the type. + * + * C99 6.7.8p31 example 7 + */ +void +ensure_array_type_is_not_modified_during_initialization(void) +{ + typedef int array_of_unknown_size[]; + + array_of_unknown_size a1 = { 1, 2, 3}; + + switch (4) { + case sizeof(array_of_unknown_size): + /* expect+1: error: duplicate case '0' in switch [199] */ + case 0: + case 3: + case 4: + case 12: + break; + } + + /* expect+1: error: negative array dimension (-12) [20] */ + typedef int reveal_sizeof_a1[-(int)(sizeof(a1))]; +} + +struct point unknown_member_name_beginning = { + /* expect+1: error: type 'struct point' does not have member 'r' [101] */ + .r = 5, + .x = 4, + .y = 3, +}; + +struct point unknown_member_name_middle = { + .x = 4, + /* expect+1: error: type 'struct point' does not have member 'r' [101] */ + .r = 5, + .y = 3, +}; + +struct point unknown_member_name_end = { + .x = 4, + .y = 3, + /* expect+1: error: type 'struct point' does not have member 'r' [101] */ + .r = 5, +}; + +union value { + int int_value; + void *pointer_value; +}; + +union value unknown_union_member_name_first = { + /* expect+1: error: type 'union value' does not have member 'unknown_value' [101] */ + .unknown_value = 4, + .int_value = 3, +}; + +union value unknown_union_member_name_second = { + .int_value = 3, + /* expect+1: error: type 'union value' does not have member 'unknown_value' [101] */ + .unknown_value = 4, +}; + +struct point subscript_designator_on_struct = { + /* expect+1: error: syntax error 'designator '[...]' is only for arrays' [249] */ + [0] = 3, +}; + +struct point unknown_member_on_struct = { + /* expect+1: error: type 'struct point' does not have member 'member' [101] */ + .member[0][0].member = 4, +}; + +struct point unknown_member_on_scalar = { + /* expect+1: error: syntax error 'scalar type cannot use designator' [249] */ + .x.y.z = 5, +}; + +struct { + int:16; + /* expect+2: warning: 'struct <unnamed>' has no named members [65] */ + /* expect+1: error: cannot initialize struct/union with no named member [179] */ +} struct_with_only_unnamed_members = { + 123, +}; + +union { + int:16; + /* expect+2: warning: 'union <unnamed>' has no named members [65] */ + /* expect+1: error: cannot initialize struct/union with no named member [179] */ +} union_with_only_unnamed_members = { + 123, +}; + +int designator_for_scalar = { + /* expect+1: error: syntax error 'scalar type cannot use designator' [249] */ + .value = 3, +}; + +struct point member_designator_for_scalar_in_struct = { + /* expect+1: error: syntax error 'scalar type cannot use designator' [249] */ + { .x = 3 }, +}; +struct point subscript_designator_for_scalar_in_struct = { + /* expect+1: error: syntax error 'designator '[...]' is only for arrays' [249] */ + { [1] = 4 }, +}; + + +/* Seen in pcidevs_data.h, variable 'pci_words'. */ +const char string_initialized_with_braced_literal[] = { + "initializer", +}; + +// An array of unknown size containing strings. +char weekday_names[][4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +/* nested struct/union initialization */ +struct outer { + int i; + char c; + union inner { + short us; + char uc; + } u; + char *s; +} struct_containing_union[] = { + { + .s = "foo", + .c = 'b', + .u = { + .uc = 'c' + } + }, + { + .i = 1, + .c = 'a', + .u = { + .us = 2 + } + }, +}; + +/* + * The expansion of the offsetof macro may dereference a null pointer. + * Such expressions are allowed in initializers for objects with + * static duration. + */ +struct offset_and_data { + unsigned long offset; + unsigned long data; +}; + +struct offset_and_data offset_and_data = { + (unsigned long)&(((struct offset_and_data *)0)->data), + 0, +}; + +// The size of the array is determined by the maximum index, not by the last +// one mentioned. +int arr_11[] = { [10] = 10, [0] = 0 }; +/* expect+1: error: negative array dimension (-11) [20] */ +typedef int ctassert_11[-(int)(sizeof(arr_11) / sizeof(arr_11[0]))]; + +// Without an explicit subscript designator, the subscript counts up. +int arr_3[] = { [1] = 1, [0] = 0, 1, 2 }; +/* expect+1: error: negative array dimension (-3) [20] */ +typedef int ctassert_3[-(int)(sizeof(arr_3) / sizeof(arr_3[0]))]; + + +// C99 struct initialization using designators. +struct { + int i; + char *s; +} struct_array[] = { + { + .i = 2, + }, + { + .s = "foo" + }, + { + .i = 1, + .s = "bar" + }, + { + .s = "foo", + .i = -1 + }, +}; + +// Ensure that deeply nested structs can be designated in an initializer. +int +init_deeply_nested_struct(void) +{ + struct rgb { + unsigned red; + unsigned green; + unsigned blue; + }; + + struct hobbies { + unsigned dancing: 1; + unsigned running: 1; + unsigned swimming: 1; + }; + + struct person { + struct hobbies hobbies; + struct rgb favorite_color; + }; + + struct city { + struct person mayor; + }; + + struct state { + struct city capital; + }; + + struct state st = { + .capital.mayor.hobbies.dancing = 1, + .capital.mayor.favorite_color.green = 0xFF, + .capital.mayor.favorite_color.red = 0xFF, + }; + return st.capital.mayor.favorite_color.red; +} + +struct { + int i[10]; + char *s; +} struct_array_with_inner_array[] = { + { + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + "foo" + }, +}; + +struct { + int type; + union { + char b[20]; + short s[10]; + long l[5]; + } data; +} array_in_union_in_struct = { + .type = 3, + .data.l[0] = 4 +}; + +// Somewhere between 2005.12.24.20.47.56 and 2006.12.19.19.06.44, lint could +// not initialize named members, see PR bin/20264. +union { + char *p; + int a[1]; +} array_in_union = { + .a = { 7 } +}; + +/* + * Initialization of a nested struct, in which some parts are initialized + * from non-constant expressions of the inner struct type. + * + * In C99, 6.7.8p13 describes exactly this case. + */ +void +init_nested_struct(void) +{ + + typedef enum O1 { + O1C = 101 + } O1; + typedef enum O2 { + O2C = 102 + } O2; + typedef enum O3 { + O3C = 103 + } O3; + typedef enum I1 { + I1C = 201 + } I1; + typedef enum I2 { + I2C = 202 + } I2; + + struct Inner1 { + I1 i1; + }; + + struct Outer3Inner1 { + O1 o1; + struct Inner1 inner; + O3 o3; + }; + + struct Inner1 inner1 = { + I1C + }; + struct Outer3Inner1 o3i1 = { + O1C, + inner1, + O3C + }; + + O1 o1 = o3i1.o1; + + struct Inner2 { + I1 i1; + I2 i2; + }; + + struct Outer3Inner2 { + O1 o1; + struct Inner2 inner; + O3 o3; + }; + + struct Inner2 inner2 = { + I1C, + I2C + }; + struct Outer3Inner2 o3i2 = { + O1C, + inner2, + O3C + }; + o1 = o3i2.o1; + + /* + * For static storage duration, each initializer expression must be a + * constant expression. + */ + static struct Inner2 inner3_static = { + I1C, + I2C + }; + static struct Outer3Inner2 o3i2_static = { + O1C, + /* expect+1: error: non-constant initializer [177] */ + inner3_static, + O3C + }; +} diff --git a/usr.bin/xlint/lint1/lex_utf8.c b/usr.bin/xlint/lint1/lex_utf8.c new file mode 100644 index 000000000000..1146d1eb9511 --- /dev/null +++ b/usr.bin/xlint/lint1/lex_utf8.c @@ -0,0 +1,12 @@ +/* $NetBSD: lex_utf8.c,v 1.3 2024/02/03 10:56:18 rillig Exp $ */ +# 3 "lex_utf8.c" + +/* + * Test lexing of multibyte characters and strings in a UTF-8 locale. + * + * See also: + * lex_wide_string.c (runs in the C locale) + */ + +/* expect+1: error: negative array dimension (-3) [20] */ +typedef int mblen[-(int)(sizeof(L"Ä😄") / sizeof(L""))]; diff --git a/usr.bin/xlint/lint1/msg_079_nongcc.c b/usr.bin/xlint/lint1/msg_079_nongcc.c new file mode 100644 index 000000000000..c0b9a50ce132 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_079_nongcc.c @@ -0,0 +1,26 @@ +/* $NetBSD: msg_079_nongcc.c,v 1.1 2024/02/02 19:07:58 rillig Exp $ */ +# 3 "msg_079_nongcc.c" + +// Test for message: dubious escape \%c [79] + +/* \e is only accepted in GCC mode. */ + +/* lint1-flags: -S -w -X 351 */ + +/* expect+1: warning: dubious escape \e [79] */ +char char_e = '\e'; +/* expect+1: warning: dubious escape \y [79] */ +char char_y = '\y'; +/* expect+1: warning: dubious escape \e [79] */ +int wide_e = L'\e'; +/* expect+1: warning: dubious escape \y [79] */ +int wide_y = L'\y'; + +/* expect+1: warning: dubious escape \e [79] */ +char char_string_e[] = "\e[0m"; +/* expect+1: warning: dubious escape \y [79] */ +char char_string_y[] = "\y[0m"; +/* expect+1: warning: dubious escape \e [79] */ +int wide_string_e[] = L"\e[0m"; +/* expect+1: warning: dubious escape \y [79] */ +int wide_string_y[] = L"\y[0m"; diff --git a/usr.bin/xlint/lint1/msg_118_ilp32.c b/usr.bin/xlint/lint1/msg_118_ilp32.c new file mode 100644 index 000000000000..abd78681305b --- /dev/null +++ b/usr.bin/xlint/lint1/msg_118_ilp32.c @@ -0,0 +1,47 @@ +/* $NetBSD: msg_118_ilp32.c,v 1.1 2025/09/06 20:18:41 rillig Exp $ */ +# 3 "msg_118_ilp32.c" + +/* Test for message: '%s' %s '%s' differs between traditional C and C90 [118] */ + +/* lint1-flags: -hw -X 351 */ +/* lint1-only-if: ilp32 */ + +int si; +unsigned ui; +long sl; +unsigned long ul; + +/* + * On 32-bit platforms both operands of the '<<' operator are first promoted + * individually, and since C90 does not know 'long long', the maximum + * bit-size for an integer type is 32 bits. + */ +void +test_shl(void) +{ + si <<= si; + si <<= ui; + si <<= sl; + si <<= ul; + + si = si << si; + si = si << ui; + si = si << sl; + si = si << ul; +} + +void +test_shr(void) +{ + si >>= si; + si >>= ui; + si >>= sl; + si >>= ul; + + si = si >> si; + /* expect+1: warning: 'int' >> 'unsigned int' differs between traditional C and C90 [118] */ + si = si >> ui; + si = si >> sl; + /* expect+1: warning: 'int' >> 'unsigned long' differs between traditional C and C90 [118] */ + si = si >> ul; +} diff --git a/usr.bin/xlint/lint1/msg_356.c b/usr.bin/xlint/lint1/msg_356.c new file mode 100644 index 000000000000..d7dbd28f4d13 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_356.c @@ -0,0 +1,35 @@ +/* $NetBSD: msg_356.c,v 1.3 2024/03/25 22:37:43 rillig Exp $ */ +# 3 "msg_356.c" + +// Test for message: short octal escape '%.*s' followed by digit '%c' [356] + +/* lint1-extra-flags: -X 351 */ + +// When counting backwards in octal, the number before \040 is not \039 but +// \037. This mistake sometimes happens when encoding the bit numbers for +// snprintb(3) format conversions. + +char snprintb_fmt[] = "\020" + "\0040bit32" // 3-digit octal escapes are fine + "\0039bit31" + "\0038bit30" + + "\040bit32" + /* expect+1: warning: short octal escape '\03' followed by digit '9' [356] */ + "\039bit31" + /* expect+1: warning: short octal escape '\03' followed by digit '8' [356] */ + "\038bit30" + + "\40bit32" + /* expect+1: warning: short octal escape '\3' followed by digit '9' [356] */ + "\39bit31" + /* expect+1: warning: short octal escape '\3' followed by digit '8' [356] */ + "\38bit30" + "\37bit29" +; + +char ok[] = "" + "\3\70" // short octal followed by escaped '8' + "\3\x38" // short octal followed by escaped '8' + "\3" "8" // short octal and '8' are separated +; diff --git a/usr.bin/xlint/lint1/msg_357.c b/usr.bin/xlint/lint1/msg_357.c new file mode 100644 index 000000000000..e8f4d269076d --- /dev/null +++ b/usr.bin/xlint/lint1/msg_357.c @@ -0,0 +1,57 @@ +/* $NetBSD: msg_357.c,v 1.3 2024/11/05 06:23:04 rillig Exp $ */ +# 3 "msg_357.c" + +// Test for message: hex escape '%.*s' mixes uppercase and lowercase digits [357] + +/* + * In the format argument of the snprintb and snprintb_m functions, a bit + * position or field width is written as an octal or hexadecimal escape + * sequence. If the description that follows a hexadecimal escape sequence + * starts with hexadecimal digits (A-Fa-f), these digits are still part of the + * escape sequence instead of the description. + * + * Since the escape sequences are typically written in lowercase and the + * descriptions are typically written in uppercase, a mixture of both cases + * indicates a mismatch. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +examples(unsigned u32, uint64_t u64) +{ + char buf[64]; + + /* expect+5: warning: hex escape '\x0aB' mixes uppercase and lowercase digits [357] */ + /* expect+4: warning: hex escape '\x0aB' has more than 2 digits [358] */ + /* expect+3: warning: bit position '\x0aB' (171) in '\x0aBIT' out of range 1..32 [371] */ + snprintb(buf, sizeof(buf), + "\020\x0aBIT", + u32); + + // This mismatch goes undetected as it has only 2 digits, does not mix + // case and is in bounds. A spellchecker could mark the unknown word + // 'ield' to give a hint. + snprintb(buf, sizeof(buf), + "\020\x1FIELD", + u32); + + // If the input value is restricted further, the unintended hexadecimal + // escape sequence is detected, although with a less obvious message. + /* expect+3: warning: conversion '\x1FIELD' is unreachable by input value [378] */ + snprintb(buf, sizeof(buf), + "\020\x1FIELD", + u32 & 0xffff); + + /* expect+5: warning: hex escape '\x0aB' mixes uppercase and lowercase digits [357] */ + /* expect+4: warning: hex escape '\x0aB' has more than 2 digits [358] */ + /* expect+3: warning: bit position '\x0aB' (171) in 'b\x0aBIT\0' out of range 0..63 [371] */ + snprintb(buf, sizeof(buf), + "\177\020b\x0aBIT\0", + u64); +} diff --git a/usr.bin/xlint/lint1/msg_358.c b/usr.bin/xlint/lint1/msg_358.c new file mode 100644 index 000000000000..3e3799ff07a2 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_358.c @@ -0,0 +1,65 @@ +/* $NetBSD: msg_358.c,v 1.4 2024/11/05 06:23:04 rillig Exp $ */ +# 3 "msg_358.c" + +// Test for message: hex escape '%.*s' has more than 2 digits [358] + +/* + * In the format argument of the snprintb and snprintb_m functions, a bit + * position or field width is written as an octal or hexadecimal escape + * sequence. If the description that follows a hexadecimal escape sequence + * starts with hexadecimal digits (A-Fa-f), these digits are still part of the + * escape sequence instead of the description. + * + * All platforms supported by lint have 8-bit char, so using more than the + * maximum necessary 2 hexadecimal digits in an escape sequence is suspicious + * of being unintended. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +examples(unsigned u32, uint64_t u64) +{ + char buf[64]; + + /* expect+3: warning: hex escape '\x01B' has more than 2 digits [358] */ + snprintb(buf, sizeof(buf), + "\020\x01BIT", + u32); + + /* expect+3: warning: hex escape '\x01b' has more than 2 digits [358] */ + snprintb(buf, sizeof(buf), + "\020\x01bit", + u32); + + // This mismatch goes undetected as it has only 2 digits, does not mix + // case and is in bounds. A spellchecker could mark the unknown word + // 'ield' to give a hint. + snprintb(buf, sizeof(buf), + "\020\x1FIELD", + u32); + + /* expect+3: warning: hex escape '\x01b' has more than 2 digits [358] */ + snprintb(buf, sizeof(buf), + "\177\020b\x01bit\0", + u64); + + /* expect+3: warning: hex escape '\x02b' has more than 2 digits [358] */ + snprintb(buf, sizeof(buf), + "\177\020f\x00\x02bit\0", + u64); + + // In this example from the snprintb manual page, the descriptions + // that start with a hexadecimal digit must be separated from the + // hexadecimal escape sequence for the bit position. + snprintb(buf, sizeof(buf), + "\20\x10NOTBOOT\x0f" "FPP\x0eSDVMA\x0cVIDEO" + "\x0bLORES\x0a" "FPA\x09" "DIAG\x07" "CACHE" + "\x06IOCACHE\x05LOOPBACK\x04" "DBGCACHE", + u32); +} diff --git a/usr.bin/xlint/lint1/msg_359.c b/usr.bin/xlint/lint1/msg_359.c new file mode 100644 index 000000000000..eb26e6093f19 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_359.c @@ -0,0 +1,29 @@ +/* $NetBSD: msg_359.c,v 1.3 2024/11/05 06:23:04 rillig Exp $ */ +# 3 "msg_359.c" + +// Test for message: missing new-style '\177' or old-style number base [359] + +/* + * The first or second character of the snprintb format specifies the number + * base. It must be an octal or hexadecimal escape sequence, as the characters + * 2, 10 and 16 are not printable, and writing '\n' instead of '\x0a' would be + * misleading. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +old_style_number_base(void) +{ + char buf[64]; + + /* expect+1: warning: missing new-style '\177' or old-style number base [359] */ + snprintb(buf, sizeof(buf), "", 0); + snprintb(buf, sizeof(buf), "\010", 0); + snprintb(buf, sizeof(buf), "" "\177\020" "", 0); +} diff --git a/usr.bin/xlint/lint1/msg_360.c b/usr.bin/xlint/lint1/msg_360.c new file mode 100644 index 000000000000..dc3f208a36a7 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_360.c @@ -0,0 +1,28 @@ +/* $NetBSD: msg_360.c,v 1.4 2024/11/05 06:23:04 rillig Exp $ */ +# 3 "msg_360.c" + +// Test for message: missing new-style number base after '\177' [360] + +/* + * The new-style format requires the number base as the second character. + * This check is merely a byproduct of the implementation, it provides little + * value of its own. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +new_style_number_base(void) +{ + char buf[64]; + + /* expect+1: warning: missing new-style number base after '\177' [360] */ + snprintb(buf, sizeof(buf), "\177", 0); + /* expect+1: warning: number base '\002' is 2, must be 8, 10 or 16 [361] */ + snprintb(buf, sizeof(buf), "\177\002", 0); +} diff --git a/usr.bin/xlint/lint1/msg_361.c b/usr.bin/xlint/lint1/msg_361.c new file mode 100644 index 000000000000..08b3c733ccb2 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_361.c @@ -0,0 +1,52 @@ +/* $NetBSD: msg_361.c,v 1.4 2024/11/05 06:23:04 rillig Exp $ */ +# 3 "msg_361.c" + +// Test for message: number base '%.*s' is %ju, must be 8, 10 or 16 [361] + +/* + * The first or second character of the snprintb format specifies the number + * base. It must be given as an octal or hexadecimal escape sequence. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +old_style_number_base(void) +{ + char buf[64]; + + /* expect+1: warning: missing new-style '\177' or old-style number base [359] */ + snprintb(buf, sizeof(buf), "", 0); + /* expect+1: warning: number base '\002' is 2, must be 8, 10 or 16 [361] */ + snprintb(buf, sizeof(buf), "\002", 0); + snprintb(buf, sizeof(buf), "\010", 0); + snprintb(buf, sizeof(buf), "\n", 0); + snprintb(buf, sizeof(buf), "\020", 0); + /* expect+1: warning: number base '\014' is 12, must be 8, 10 or 16 [361] */ + snprintb(buf, sizeof(buf), "" "\014" "", 0); + snprintb(buf, sizeof(buf), "" "\020" "", 0); +} + +void +new_style_number_base(void) +{ + char buf[64]; + + /* expect+1: warning: missing new-style number base after '\177' [360] */ + snprintb(buf, sizeof(buf), "\177", 0); + /* expect+1: warning: number base '\0' is 0, must be 8, 10 or 16 [361] */ + snprintb(buf, sizeof(buf), "\177\0", 0); + /* expect+1: warning: number base '\002' is 2, must be 8, 10 or 16 [361] */ + snprintb(buf, sizeof(buf), "\177\002", 0); + snprintb(buf, sizeof(buf), "\177\010", 0); + snprintb(buf, sizeof(buf), "\177\n", 0); + snprintb(buf, sizeof(buf), "\177\020", 0); + /* expect+1: warning: number base '\014' is 12, must be 8, 10 or 16 [361] */ + snprintb(buf, sizeof(buf), "" "\177\014" "", 0); + snprintb(buf, sizeof(buf), "" "\177\020" "", 0); +} diff --git a/usr.bin/xlint/lint1/msg_362.c b/usr.bin/xlint/lint1/msg_362.c new file mode 100644 index 000000000000..58da2bd219e2 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_362.c @@ -0,0 +1,33 @@ +/* $NetBSD: msg_362.c,v 1.4 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_362.c" + +// Test for message: conversion '%.*s' should not be escaped [362] + +/* + * Since the characters used for the conversion type were chosen to be easily + * readable, it doesn't make sense to obfuscate them. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(unsigned u32) +{ + char buf[64]; + + /* expect+9: warning: conversion '\142' should not be escaped [362] */ + /* expect+8: warning: bit position 'o' in '\142old-style-lsb\0' should be escaped as octal or hex [369] */ + /* expect+7: warning: bit position 'o' (111) in '\142old-style-lsb\0' out of range 0..63 [371] */ + /* expect+6: warning: unknown conversion '\001', must be one of 'bfF=:*' [374] */ + snprintb(buf, sizeof(buf), + "\177\020" + "\142old-style-lsb\0" + "\001old-style-lsb\0" + "\142\000old-style-lsb\0", + u32); +} diff --git a/usr.bin/xlint/lint1/msg_363.c b/usr.bin/xlint/lint1/msg_363.c new file mode 100644 index 000000000000..41a0e06845f2 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_363.c @@ -0,0 +1,64 @@ +/* $NetBSD: msg_363.c,v 1.7 2024/11/05 06:23:04 rillig Exp $ */ +# 3 "msg_363.c" + +// Test for message: escaped character '%.*s' in description of conversion '%.*s' [363] + +/* + * The purpose of snprintb is to produce a printable, visible representation + * of a binary number, therefore the description should consist of simple + * characters only, and these should not need to be escaped. If they are, + * it's often due to a typo, such as a missing terminating '\0'. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +old_style_description(unsigned u32) +{ + char buf[64]; + + /* expect+6: warning: bit position '\t' in '\tprint' should be escaped as octal or hex [369] */ + /* expect+5: warning: escaped character '\377' in description of conversion '\nable\377' [363] */ + /* expect+4: warning: bit position '\n' in '\nable\377' should be escaped as octal or hex [369] */ + snprintb(buf, sizeof(buf), + "\020" + "\001non\tprint\nable\377", + u32); + + // In the new format, the description can technically contain + // arbitrary characters, but having non-printable characters would + // produce confusing output, so any escaped characters are suspicious + // of being unintended. + /* expect+6: warning: escaped character '\t' in description of conversion 'b\000non\t' [363] */ + /* expect+5: warning: escaped character '\n' in description of conversion 'b\000non\tprint\n' [363] */ + /* expect+4: warning: escaped character '\377' in description of conversion 'b\000non\tprint\nable\377' [363] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\000non\tprint\nable\377\0", + u32); + + /* expect+10: warning: escaped character '\177' in description of conversion '\002""\177' [363] */ + /* expect+9: warning: escaped character '\177' in description of conversion '\003aa""""\177' [363] */ + /* expect+8: warning: escaped character '\177' in description of conversion '\004""bb""\177' [363] */ + /* expect+7: warning: escaped character '\177' in description of conversion '\005""""cc\177' [363] */ + snprintb(buf, sizeof(buf), + "\020" + "\002""\177" + "\003aa""""\177" + "\004""bb""\177" + "\005""""cc\177", + u32); + + /* expect+6: warning: bit position '\000' (0) in '\000print' out of range 1..32 [371] */ + /* expect+5: warning: bit position '\n' in '\nable' should be escaped as octal or hex [369] */ + /* expect+4: warning: redundant '\0' at the end of the format [377] */ + snprintb(buf, sizeof(buf), + "\020" + "\001non\000print\nable\0", + u32); +} diff --git a/usr.bin/xlint/lint1/msg_364.c b/usr.bin/xlint/lint1/msg_364.c new file mode 100644 index 000000000000..61e24d4aa235 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_364.c @@ -0,0 +1,35 @@ +/* $NetBSD: msg_364.c,v 1.4 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_364.c" + +// Test for message: missing bit position after '%.*s' [364] + +/* + * The conversions 'b', 'f' and 'F' require a bit position as their first + * argument. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(unsigned u32) +{ + char buf[64]; + + /* expect+4: warning: missing bit position after 'b' [364] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b", + u32); + + /* expect+5: warning: empty description in 'b\007' [367] */ + /* expect+4: warning: missing '\0' at the end of 'b\007' [366] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\007", + u32); +} diff --git a/usr.bin/xlint/lint1/msg_365.c b/usr.bin/xlint/lint1/msg_365.c new file mode 100644 index 000000000000..f77fdc121a77 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_365.c @@ -0,0 +1,34 @@ +/* $NetBSD: msg_365.c,v 1.4 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_365.c" + +// Test for message: missing field width after '%.*s' [365] + +/* + * The conversions 'f' and 'F' require a field width as their second argument. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(unsigned u32) +{ + char buf[64]; + + /* expect+4: warning: missing field width after 'f\000' [365] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f\000", + u32); + + /* expect+5: warning: empty description in 'f\007\010' [367] */ + /* expect+4: warning: missing '\0' at the end of 'f\007\010' [366] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f\007\010", + u32); +} diff --git a/usr.bin/xlint/lint1/msg_366.c b/usr.bin/xlint/lint1/msg_366.c new file mode 100644 index 000000000000..d6fd1884b302 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_366.c @@ -0,0 +1,70 @@ +/* $NetBSD: msg_366.c,v 1.5 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_366.c" + +// Test for message: missing '\0' at the end of '%.*s' [366] + +/* + * In the new-style format, each conversion ends with a '\0'. If that's not + * the case, snprintb will read beyond the end of the format argument, looking + * for the terminating '\0'. In the most common case where the format comes + * from a string literal, the '\0' from the conversion needs to be spelled + * out, while the '\0' that terminates the sequence of conversions is provided + * by the C compiler. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(unsigned u32) +{ + char buf[64]; + + /* expect+4: warning: redundant '\0' at the end of the format [377] */ + snprintb(buf, sizeof(buf), + "\177\020" + "\0", + u32); + + /* expect+5: warning: empty description in 'b\007' [367] */ + /* expect+4: warning: missing '\0' at the end of 'b\007' [366] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\007", + u32); + + /* expect+5: warning: empty description in 'f\007\000' [367] */ + /* expect+4: warning: missing '\0' at the end of 'f\007\000' [366] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f\007\000", + u32); + + /* expect+4: warning: missing '\0' at the end of 'F\007\000' [366] */ + snprintb(buf, sizeof(buf), + "\177\020" + "F\007\000", + u32); + + /* expect+4: warning: missing '\0' at the end of '=\007value' [366] */ + snprintb(buf, sizeof(buf), + "\177\020" + "=\007value", + u32); + + /* expect+4: warning: missing '\0' at the end of ':\007value' [366] */ + snprintb(buf, sizeof(buf), + "\177\020" + ":\007value", + u32); + + /* expect+4: warning: missing '\0' at the end of '*default' [366] */ + snprintb(buf, sizeof(buf), + "\177\020" + "*default", + u32); +} diff --git a/usr.bin/xlint/lint1/msg_367.c b/usr.bin/xlint/lint1/msg_367.c new file mode 100644 index 000000000000..5965098443e6 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_367.c @@ -0,0 +1,120 @@ +/* $NetBSD: msg_367.c,v 1.4 2025/08/31 20:43:27 rillig Exp $ */ +# 3 "msg_367.c" + +// Test for message: empty description in '%.*s' [367] + +/* + * Each bit or field or comparison value gets a description. If such a + * description is empty, the generated output will contain empty angle + * brackets or multiple adjacent commas or commas adjacent to an angle + * bracket, such as '<,,,,>'. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +old_style(unsigned u32) +{ + char buf[64]; + + /* expect+10: warning: empty description in '\001' [367] */ + /* expect+9: warning: empty description in '\002' [367] */ + /* expect+8: warning: empty description in '\003' [367] */ + /* expect+7: warning: empty description in '\004' [367] */ + snprintb(buf, sizeof(buf), + "\020" + "\001" + "\002" + "\003" + "\004", + u32); + + /* expect+10: warning: empty description in '\001' [367] */ + /* expect+9: warning: empty description in '\002' [367] */ + /* expect+8: warning: empty description in '\003' [367] */ + /* expect+7: warning: empty description in '\004' [367] */ + snprintb(buf, sizeof(buf), + "\020" + "\001" "" "" + "\002" "" "" + "\003" "" "" + "\004" "" "", + u32); + + // Single-letter descriptions are not empty. + snprintb(buf, sizeof(buf), + "\020" + "\001a" + "\002b" + "\003c" + "\004d", + u32); +} + +void +new_style(uint64_t u64) +{ + char buf[64]; + + /* expect+4: warning: empty description in 'b\000\0' [367] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\000\0", + u64); + + /* expect+4: warning: empty description in 'f\000\010\0' [367] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f\000\010\0", + u64); + + // No warning, as 'F' does not take a description. + // If there were a description, it would simply be skipped. + snprintb(buf, sizeof(buf), + "\177\020" + "F\000\010\0", + u64); + + /* expect+4: warning: empty description in '=\000\0' [367] */ + snprintb(buf, sizeof(buf), + "\177\020" + "=\000\0", + u64); + + /* expect+4: warning: empty description in ':\000\0' [367] */ + snprintb(buf, sizeof(buf), + "\177\020" + ":\000\0", + u64); + + /* expect+4: warning: empty description in '*\0' [367] */ + snprintb(buf, sizeof(buf), + "\177\020" + "*\0", + u64); + + // Single-letter descriptions are not empty. + snprintb(buf, sizeof(buf), + "\177\020" + "b\000b\0" + "f\001\001f\0" + "F\002\002F\0" + "=\000z\0" + ":\001o\0" + "*d\0", + /* expect+1: warning: conversion '=' does not mix with 'F' [386] */ + u64 >> 1); + + /* expect+6: warning: empty description in 'b\001""""""\0' [367] */ + /* expect+5: warning: empty description in 'b\003""""""\0' [367] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\001" "" "" "\0" + "b\003" "" "" "\0", + u64); +} diff --git a/usr.bin/xlint/lint1/msg_368.c b/usr.bin/xlint/lint1/msg_368.c new file mode 100644 index 000000000000..fd752f7cbbbf --- /dev/null +++ b/usr.bin/xlint/lint1/msg_368.c @@ -0,0 +1,34 @@ +/* $NetBSD: msg_368.c,v 1.3 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_368.c" + +// Test for message: missing comparison value after conversion '%.*s' [368] + +/* + * The conversions '=' and ':' require a comparison value as their argument, + * followed by the description and the terminating null character. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(uint64_t val) +{ + char buf[64]; + + /* expect+4: warning: missing comparison value after conversion '=' [368] */ + snprintb(buf, sizeof(buf), + "\177\020" + "=", + val); + + /* expect+4: warning: missing comparison value after conversion ':' [368] */ + snprintb(buf, sizeof(buf), + "\177\020" + ":", + val); +} diff --git a/usr.bin/xlint/lint1/msg_369.c b/usr.bin/xlint/lint1/msg_369.c new file mode 100644 index 000000000000..8129dc7b359b --- /dev/null +++ b/usr.bin/xlint/lint1/msg_369.c @@ -0,0 +1,52 @@ +/* $NetBSD: msg_369.c,v 1.3 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_369.c" + +// Test for message: bit position '%.*s' in '%.*s' should be escaped as octal or hex [369] + +/* + * To distinguish bit positions from the description text, they should use + * octal or hex escape sequences. Of these, octal escape sequences are less + * error-prone, as they consist of at most 3 octal digits, whereas hex escape + * sequences consume as many digits as available. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(unsigned u32, uint64_t u64) +{ + char buf[64]; + + /* expect+8: warning: bit position ' ' in ' space' should be escaped as octal or hex [369] */ + /* expect+7: warning: bit position '\t' in '\ttab' should be escaped as octal or hex [369] */ + /* expect+6: warning: bit position '\n' in '\nnewline' should be escaped as octal or hex [369] */ + snprintb(buf, sizeof(buf), + "\020" + " space" + "\ttab" + "\nnewline", + u32); + + /* expect+8: warning: bit position ' ' in 'b space\0' should be escaped as octal or hex [369] */ + /* expect+7: warning: bit position '\t' in 'b\ttab\0' should be escaped as octal or hex [369] */ + /* expect+6: warning: bit position '\n' in 'b\nnewline\0' should be escaped as octal or hex [369] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b space\0" + "b\ttab\0" + "b\nnewline\0", + u64); + + /* expect+6: warning: bit position '\t' in 'f\t\001tab\0' should be escaped as octal or hex [369] */ + /* expect+5: warning: bit position '\n' in 'F\n\001newline\0' should be escaped as octal or hex [369] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f\t\001tab\0" + "F\n\001newline\0", + u64); +} diff --git a/usr.bin/xlint/lint1/msg_370.c b/usr.bin/xlint/lint1/msg_370.c new file mode 100644 index 000000000000..e8c762c8deec --- /dev/null +++ b/usr.bin/xlint/lint1/msg_370.c @@ -0,0 +1,52 @@ +/* $NetBSD: msg_370.c,v 1.3 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_370.c" + +// Test for message: field width '%.*s' in '%.*s' should be escaped as octal or hex [370] + +/* + * To distinguish field widths from the description text, they should use + * octal or hex escape sequences. Of these, octal escape sequences are less + * error-prone, as they consist of at most 3 octal digits, whereas hex escape + * sequences consume as many digits as available. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(uint64_t u64) +{ + char buf[64]; + + /* expect+11: warning: bit position ' ' in 'f space\0' should be escaped as octal or hex [369] */ + /* expect+10: warning: field width ' ' in 'f space\0' should be escaped as octal or hex [370] */ + /* expect+9: warning: bit position '\t' in 'f\t\ttab\0' should be escaped as octal or hex [369] */ + /* expect+8: warning: field width '\t' in 'f\t\ttab\0' should be escaped as octal or hex [370] */ + /* expect+7: warning: bit position '\n' in 'f\n\nnewline\0' should be escaped as octal or hex [369] */ + /* expect+6: warning: field width '\n' in 'f\n\nnewline\0' should be escaped as octal or hex [370] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f space\0" + "f\t\ttab\0" + "f\n\nnewline\0", + u64); + /* expect-1: warning: 'f\n\nnewline\0' overlaps earlier 'f\t\ttab\0' on bit 10 [376] */ + + /* expect+11: warning: bit position ' ' in 'F space\0' should be escaped as octal or hex [369] */ + /* expect+10: warning: field width ' ' in 'F space\0' should be escaped as octal or hex [370] */ + /* expect+9: warning: bit position '\t' in 'F\t\ttab\0' should be escaped as octal or hex [369] */ + /* expect+8: warning: field width '\t' in 'F\t\ttab\0' should be escaped as octal or hex [370] */ + /* expect+7: warning: bit position '\n' in 'F\n\nnewline\0' should be escaped as octal or hex [369] */ + /* expect+6: warning: field width '\n' in 'F\n\nnewline\0' should be escaped as octal or hex [370] */ + snprintb(buf, sizeof(buf), + "\177\020" + "F space\0" + "F\t\ttab\0" + "F\n\nnewline\0", + u64); + /* expect-1: warning: 'F\n\nnewline\0' overlaps earlier 'F\t\ttab\0' on bit 10 [376] */ +} diff --git a/usr.bin/xlint/lint1/msg_371.c b/usr.bin/xlint/lint1/msg_371.c new file mode 100644 index 000000000000..cb6ffdd54f20 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_371.c @@ -0,0 +1,62 @@ +/* $NetBSD: msg_371.c,v 1.3 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_371.c" + +// Test for message: bit position '%.*s' (%ju) in '%.*s' out of range %u..%u [371] + +/* + * In old-style formats, bit positions are 1-based and must be in the range + * from 1 to 32. In new-style formats, bit positions are 0-based and must be + * in the range from 0 to 63. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(unsigned u32, uint64_t u64) +{ + char buf[64]; + + /* expect+12: warning: bit position '\000' (0) in '\000zero' out of range 1..32 [371] */ + /* expect+11: warning: escaped character '\041' in description of conversion '\040bit32""\041' [363] */ + /* expect+10: warning: escaped character '\177' in description of conversion '\040bit32""\041bit33""\177' [363] */ + /* expect+9: warning: escaped character '\377' in description of conversion '\040bit32""\041bit33""\177bit127""\377' [363] */ + snprintb(buf, sizeof(buf), + "\020" + "\000zero" + "\001bit1" + "\040bit32" + "\041bit33" + "\177bit127" + "\377bit255", + u32); + + /* expect+10: warning: bit position '\100' (64) in 'b\100bit64\0' out of range 0..63 [371] */ + /* expect+9: warning: bit position '\177' (127) in 'b\177bit127\0' out of range 0..63 [371] */ + /* expect+8: warning: bit position '\377' (255) in 'b\377bit255\0' out of range 0..63 [371] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\000bit0\0" + "b\077bit63\0" + "b\100bit64\0" + "b\177bit127\0" + "b\377bit255\0", + u64); + + /* expect+11: warning: bit position '\100' (64) in 'F\100\000none\0' out of range 0..63 [371] */ + /* expect+10: warning: bit position '\100' (64) in 'f\100\001oob\0' out of range 0..63 [371] */ + /* expect+9: warning: bit field end 65 in 'f\100\001oob\0' out of range 0..64 [373] */ + /* expect+8: warning: bit position '\101' (65) in 'F\101\001oob\0' out of range 0..63 [371] */ + /* expect+7: warning: bit field end 66 in 'F\101\001oob\0' out of range 0..64 [373] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f\077\001msb\0" + "F\100\000none\0" + "f\100\001oob\0" + "F\101\001oob\0", + u64); +} diff --git a/usr.bin/xlint/lint1/msg_372.c b/usr.bin/xlint/lint1/msg_372.c new file mode 100644 index 000000000000..b4c914d75f64 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_372.c @@ -0,0 +1,36 @@ +/* $NetBSD: msg_372.c,v 1.4 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_372.c" + +// Test for message: field width '%.*s' (%ju) in '%.*s' out of range 0..64 [372] + +/* + * In new-style formats, the width of a bit-field must be between 0 (an empty + * bit-field) and 64 (a bit-field spanning the whole value). + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(uint64_t u64) +{ + char buf[64]; + + /* expect+12: warning: field width '\101' (65) in 'f\000\101all+1\0' out of range 0..64 [372] */ + /* expect+11: warning: bit field end 65 in 'f\000\101all+1\0' out of range 0..64 [373] */ + /* expect+10: warning: bit field end 65 in 'f\001\100oob64\0' out of range 0..64 [373] */ + /* expect+9: warning: 'f\001\100oob64\0' overlaps earlier 'f\000\100all\0' on bit 1 [376] */ + /* expect+8: warning: field width '\377' (255) in 'f\010\377oob64\0' out of range 0..64 [372] */ + /* expect+7: warning: bit field end 263 in 'f\010\377oob64\0' out of range 0..64 [373] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f\000\100all\0" + "f\000\101all+1\0" + "f\001\100oob64\0" + "f\010\377oob64\0", + u64); +} diff --git a/usr.bin/xlint/lint1/msg_373.c b/usr.bin/xlint/lint1/msg_373.c new file mode 100644 index 000000000000..5eded6ff9e02 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_373.c @@ -0,0 +1,44 @@ +/* $NetBSD: msg_373.c,v 1.4 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_373.c" + +// Test for message: bit field end %ju in '%.*s' out of range 0..64 [373] + +/* + * A bit-field may start in the middle of the value. When its end goes beyond + * 64, this means the uppermost bits will always be 0, and a narrower + * bit-field would have the same effect. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(uint64_t u64) +{ + char buf[64]; + + /* expect+12: warning: field width '\101' (65) in 'f\000\101all+1\0' out of range 0..64 [372] */ + /* expect+11: warning: bit field end 65 in 'f\000\101all+1\0' out of range 0..64 [373] */ + /* expect+10: warning: bit field end 65 in 'f\001\100oob64\0' out of range 0..64 [373] */ + /* expect+9: warning: 'f\001\100oob64\0' overlaps earlier 'f\000\100all\0' on bit 1 [376] */ + /* expect+8: warning: field width '\377' (255) in 'f\010\377oob64\0' out of range 0..64 [372] */ + /* expect+7: warning: bit field end 263 in 'f\010\377oob64\0' out of range 0..64 [373] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f\000\100all\0" + "f\000\101all+1\0" + "f\001\100oob64\0" + "f\010\377oob64\0", + u64); + + /* expect+5: warning: bit position '\377' (255) in 'f\377\002wrap-around\0' out of range 0..63 [371] */ + /* expect+4: warning: bit field end 257 in 'f\377\002wrap-around\0' out of range 0..64 [373] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f\377\002wrap-around\0", + u64); +} diff --git a/usr.bin/xlint/lint1/msg_374.c b/usr.bin/xlint/lint1/msg_374.c new file mode 100644 index 000000000000..1d4312623e58 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_374.c @@ -0,0 +1,49 @@ +/* $NetBSD: msg_374.c,v 1.6 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_374.c" + +// Test for message: unknown conversion '%.*s', must be one of 'bfF=:*' [374] + +/* + * In the new-style format, an unknown conversion is assumed to have a single + * argument, followed by a null-terminated description. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(uint64_t u64) +{ + char buf[64]; + + /* expect+4: warning: unknown conversion 'x', must be one of 'bfF=:*' [374] */ + snprintb(buf, sizeof(buf), + "\177\020" + "x12345\0", + u64); + + /* expect+4: warning: unknown conversion '\000', must be one of 'bfF=:*' [374] */ + snprintb(buf, sizeof(buf), + "\177\020" + "\00012345\0", + u64); + + /* expect+5: warning: redundant '\0' at the end of the format [377] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\00012345\0" + "\0", + u64); + + // Real-life example: the '\b' is a typo. + // + /* expect+4: warning: unknown conversion '\b', must be one of 'bfF=:*' [374] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\15ENCNT\0b\16" "TC\0\b\20DSBL_CSR_DRN\0", + u64); +} diff --git a/usr.bin/xlint/lint1/msg_375.c b/usr.bin/xlint/lint1/msg_375.c new file mode 100644 index 000000000000..f8251c101d71 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_375.c @@ -0,0 +1,38 @@ +/* $NetBSD: msg_375.c,v 1.4 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_375.c" + +// Test for message: comparison value '%.*s' (%ju) exceeds maximum field value %ju [375] + +/* + * When a bit field can take the values 0 to 15, there is no point comparing + * it to 16. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(uint64_t u64) +{ + char buf[64]; + + /* expect+14: warning: comparison value '\020' (16) exceeds maximum field value 15 [375] */ + /* expect+13: warning: comparison value '\377' (255) exceeds maximum field value 15 [375] */ + /* expect+12: warning: comparison value '\020' (16) exceeds maximum field value 15 [375] */ + /* expect+11: warning: comparison value '\377' (255) exceeds maximum field value 15 [375] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f\000\004low\0" + "=\01715\0" + "=\02016\0" + "=\37716\0" + "F\004\004low\0" + ":\01715\0" + ":\02016\0" + ":\37716\0", + u64); +} diff --git a/usr.bin/xlint/lint1/msg_376.c b/usr.bin/xlint/lint1/msg_376.c new file mode 100644 index 000000000000..2e2135e869ae --- /dev/null +++ b/usr.bin/xlint/lint1/msg_376.c @@ -0,0 +1,58 @@ +/* $NetBSD: msg_376.c,v 1.4 2024/08/31 06:57:31 rillig Exp $ */ +# 3 "msg_376.c" + +// Test for message: '%.*s' overlaps earlier '%.*s' on bit %u [376] + +/* + * When bits and fields overlap, it's often due to typos or off-by-one errors. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(unsigned u32, uint64_t u64) +{ + char buf[64]; + + // In the old-style format, bit positions are 1-based. + snprintb(buf, sizeof(buf), + "\020" + "\001lsb" + "\x01lsb" + "\040msb" + "\x20msb" + "\041oob" + "\x21oob", + /* expect+4: warning: '\x01lsb' overlaps earlier '\001lsb' on bit 1 [376] */ + /* expect+3: warning: escaped character '\041' in description of conversion '\x20msb""\041' [363] */ + /* expect+2: warning: escaped character '\x21' in description of conversion '\x20msb""\041oob""\x21' [363] */ + /* expect+1: warning: '\x20msb""\041oob""\x21oob' overlaps earlier '\040msb' on bit 32 [376] */ + u32); + + // In the new-style format, bit positions are 0-based. + /* expect+10: warning: 'b\x00lsb\0' overlaps earlier 'b\000lsb\0' on bit 0 [376] */ + /* expect+9: warning: 'b\x3fmsb\0' overlaps earlier 'b\077msb\0' on bit 63 [376] */ + /* expect+8: warning: bit position '\x40' (64) in 'b\x40oob\0' out of range 0..63 [371] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\000lsb\0" + "b\x00lsb\0" + "b\077msb\0" + "b\x3fmsb\0" + "b\x40oob\0", + u64); + + /* expect+7: warning: 'F\014\010f2\0' overlaps earlier 'f\010\010f1\0' on bit 12 [376] */ + /* expect+6: warning: 'f\020\010f3\0' overlaps earlier 'F\014\010f2\0' on bit 16 [376] */ + snprintb(buf, sizeof(buf), + "\177\020" + "f\010\010f1\0" + "F\014\010f2\0" + "f\020\010f3\0", + u64); +} diff --git a/usr.bin/xlint/lint1/msg_377.c b/usr.bin/xlint/lint1/msg_377.c new file mode 100644 index 000000000000..0416ea6c1bb2 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_377.c @@ -0,0 +1,41 @@ +/* $NetBSD: msg_377.c,v 1.5 2024/08/31 06:57:32 rillig Exp $ */ +# 3 "msg_377.c" + +// Test for message: redundant '\0' at the end of the format [377] + +/* + * Each conversion in the new-style format ends with a '\0' that needs to be + * spelled out. + * + * In both old-style and new-style formats, the '\0' that ends the whole + * format is provided by the compiler as part of the string literal. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(unsigned u32, uint64_t u64) +{ + char buf[64]; + + /* expect+7: warning: bit position '\000' (0) in '\000out-of-range' out of range 1..32 [371] */ + /* expect+6: warning: redundant '\0' at the end of the format [377] */ + snprintb(buf, sizeof(buf), + "\020" + "\005bit" + "\000out-of-range" + "\0", + u32); + + /* expect+5: warning: redundant '\0' at the end of the format [377] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\005bit\0" + "\0", + u64); +} diff --git a/usr.bin/xlint/lint1/msg_378.c b/usr.bin/xlint/lint1/msg_378.c new file mode 100644 index 000000000000..4698e99a9e9e --- /dev/null +++ b/usr.bin/xlint/lint1/msg_378.c @@ -0,0 +1,52 @@ +/* $NetBSD: msg_378.c,v 1.3 2024/08/31 06:57:32 rillig Exp $ */ +# 3 "msg_378.c" + +// Test for message: conversion '%.*s' is unreachable by input value [378] + +/* + * The typical use case of snprintb is to have a format that is specifically + * tailored to a particular input value. Often, a format is only used in a + * single place. Therefore, bits that are unreachable are redundant and may + * hint at typos. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof(0)) size_t; +typedef unsigned long long uint64_t; + +int snprintb(char *, size_t, const char *, uint64_t); + +void +example(unsigned u32, uint64_t u64) +{ + char buf[64]; + + /* expect+5: warning: conversion '\040bit32' is unreachable by input value [378] */ + snprintb(buf, sizeof(buf), + "\020" + "\037bit31" + "\040bit32", + u32 >> 1); + + /* expect+5: warning: conversion 'b\075bit61\0' is unreachable by input value [378] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\074bit60\0" + "b\075bit61\0", + u64 >> 3); + + /* expect+12: warning: conversion 'b\000bit0\0' is unreachable by input value [378] */ + /* expect+11: warning: conversion 'b\011bit9\0' is unreachable by input value [378] */ + /* expect+10: warning: conversion 'f\017\002bits15-16\0' is unreachable by input value [378] */ + /* expect+9: warning: conversion 'f\050\030bits40-63\0' is unreachable by input value [378] */ + snprintb(buf, sizeof(buf), + "\177\020" + "b\000bit0\0" + "b\010bit8\0" + "b\011bit9\0" + "f\012\002bits10-11\0" + "f\017\002bits15-16\0" + "f\050\030bits40-63\0", + (u32 & 0xaa55aa55) << 8); +} diff --git a/usr.bin/xlint/lint1/msg_379.c b/usr.bin/xlint/lint1/msg_379.c new file mode 100644 index 000000000000..bb2b98917867 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_379.c @@ -0,0 +1,31 @@ +/* $NetBSD: msg_379.c,v 1.2 2024/11/13 04:32:50 rillig Exp $ */ +# 3 "msg_379.c" + +// Test for message: comparing integer '%s' to floating point constant %Lg [379] + +/* + * Comparing an integer expression to a floating point constant mixes + * different kinds of types. This mixture is more complicated than necessary, + * thus confusing human readers. + * + * The compilers are fine with this kind of expression: GCC treats the + * constant as an integer even at -O0 while Clang needs at least -O. + */ + +/* lint1-extra-flags: -X 351 */ + +int +comparisons(int x) +{ + if (3 > 123.0) + /* expect+1: warning: 'return' statement not reached [193] */ + return 0; + /* expect+1: warning: comparing integer 'int' to floating point constant 123 [379] */ + if (x > 123.0) + return 1; + + // Yoda-style comparisons are unusual enough to not warn about them. + if (123.0 > x) + return 2; + return 3; +} diff --git a/usr.bin/xlint/lint1/msg_380.c b/usr.bin/xlint/lint1/msg_380.c new file mode 100644 index 000000000000..b729380789a3 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_380.c @@ -0,0 +1,71 @@ +/* $NetBSD: msg_380.c,v 1.2 2024/06/22 06:24:46 rillig Exp $ */ +# 3 "msg_380.c" + +// Test for message: lossy conversion of %Lg to '%s', arg #%d [380] + +/* lint1-extra-flags: -X 351 */ + +void take_s32(int); +void take_u32(unsigned int); +void take_s64(long long); +void take_u64(unsigned long long); + +void +conversions(void) +{ + /* expect+1: warning: lossy conversion of -2.14748e+09 to 'int', arg #1 [380] */ + take_s32(-2147483649.0); + take_s32(-2147483648.0); + /* expect+1: warning: lossy conversion of 3.141 to 'int', arg #1 [380] */ + take_s32(3.141); + take_s32(2147483647.0); + /* expect+1: warning: lossy conversion of 2.14748e+09 to 'int', arg #1 [380] */ + take_s32(2147483648.0); + + /* expect+1: warning: lossy conversion of -1 to 'unsigned int', arg #1 [380] */ + take_u32(-1.0); + take_u32(-0.0); + take_u32(0.0); + /* expect+1: warning: lossy conversion of 3.141 to 'unsigned int', arg #1 [380] */ + take_u32(3.141); + take_u32(4294967295.0); + /* expect+1: warning: lossy conversion of 4.29497e+09 to 'unsigned int', arg #1 [380] */ + take_u32(4294967296.0); + + /* expect+1: warning: lossy conversion of -9.22337e+18 to 'long long', arg #1 [380] */ + take_s64(-9223372036854776833.0); + /* The constant ...809 is rounded down to ...808, thus no warning. */ + take_s64(-9223372036854775809.0); + take_s64(-9223372036854775808.0); + /* expect+1: warning: lossy conversion of 3.141 to 'long long', arg #1 [380] */ + take_s64(3.141); + /* expect+1: warning: lossy conversion of 9.22337e+18 to 'long long', arg #1 [380] */ + take_s64(9223372036854775807.0); + /* expect+1: warning: lossy conversion of 9.22337e+18 to 'long long', arg #1 [380] */ + take_s64(9223372036854775808.0); + + /* expect+1: warning: lossy conversion of -1 to 'unsigned long long', arg #1 [380] */ + take_u64(-1.0); + take_u64(-0.0); + take_u64(0.0); + /* expect+1: warning: lossy conversion of 3.141 to 'unsigned long long', arg #1 [380] */ + take_u64(3.141); + + // Warning on: alpha + // No warning on: aarch64 aarch64-compat32 arm i386 mips powerpc riscv64 sh3 sparc x86_64 + // Unknown: coldfire hppa ia64 m68000 m68k mips64 mipsn64 or1k powerpc64 riscv32 sparc64 vax + // + // warning: lossy conversion of 1.84467e+19 to 'unsigned long long', arg #1 [380] + //take_u64(18446744073709550591.0); + + // Warning on: aarch64 alpha arm i386 mips riscv64 sparc x86_64 + // No warning on: aarch64-compat32 powerpc sh3 + // Unknown: coldfire hppa ia64 m68000 m68k mips64 mipsn64 or1k powerpc64 riscv32 sparc64 vax + // + // warning: lossy conversion of 1.84467e+19 to 'unsigned long long', arg #1 [380] + //take_u64(18446744073709550592.0); + // warning: lossy conversion of 1.84467e+19 to 'unsigned long long', arg #1 [380] + //take_u64(18446744073709551615.0); + // warning: lossy conversion of 1.84467e+19 to 'unsigned long long', arg #1 [380] + //take_u64(18446744073709551616.0); +} diff --git a/usr.bin/xlint/lint1/msg_381.c b/usr.bin/xlint/lint1/msg_381.c new file mode 100644 index 000000000000..4bf64e3cf895 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_381.c @@ -0,0 +1,71 @@ +/* $NetBSD: msg_381.c,v 1.2 2024/06/22 06:24:46 rillig Exp $ */ +# 3 "msg_381.c" + +// Test for message: lossy conversion of %Lg to '%s' [381] + +/* lint1-extra-flags: -X 351 */ + +int s32; +unsigned int u32; +long long s64; +unsigned long long u64; + +void +conversions(void) +{ + /* expect+1: warning: lossy conversion of -2.14748e+09 to 'int' [381] */ + s32 = -2147483649.0; + s32 = -2147483648.0; + /* expect+1: warning: lossy conversion of 3.141 to 'int' [381] */ + s32 = 3.141; + s32 = 2147483647.0; + /* expect+1: warning: lossy conversion of 2.14748e+09 to 'int' [381] */ + s32 = 2147483648.0; + + /* expect+1: warning: lossy conversion of -1 to 'unsigned int' [381] */ + u32 = -1.0; + u32 = -0.0; + u32 = 0.0; + /* expect+1: warning: lossy conversion of 3.141 to 'unsigned int' [381] */ + u32 = 3.141; + u32 = 4294967295.0; + /* expect+1: warning: lossy conversion of 4.29497e+09 to 'unsigned int' [381] */ + u32 = 4294967296.0; + + /* expect+1: warning: lossy conversion of -9.22337e+18 to 'long long' [381] */ + s64 = -9223372036854776833.0; + /* The constant ...809 is rounded down to ...808, thus no warning. */ + s64 = -9223372036854775809.0; + s64 = -9223372036854775808.0; + /* expect+1: warning: lossy conversion of 3.141 to 'long long' [381] */ + s64 = 3.141; + /* expect+1: warning: lossy conversion of 9.22337e+18 to 'long long' [381] */ + s64 = 9223372036854775807.0; + /* expect+1: warning: lossy conversion of 9.22337e+18 to 'long long' [381] */ + s64 = 9223372036854775808.0; + + /* expect+1: warning: lossy conversion of -1 to 'unsigned long long' [381] */ + u64 = -1.0; + u64 = -0.0; + u64 = 0.0; + /* expect+1: warning: lossy conversion of 3.141 to 'unsigned long long' [381] */ + u64 = 3.141; + + // Warning on: alpha + // No warning on: aarch64 aarch64-compat32 arm i386 mips powerpc riscv64 sh3 sparc x86_64 + // Unknown: coldfire hppa ia64 m68000 m68k mips64 mipsn64 or1k powerpc64 riscv32 sparc64 vax + // + // warning: lossy conversion of 1.84467e+19 to 'unsigned long long' [381] + //u64 = 18446744073709550591.0; + + // Warning on: aarch64 alpha arm i386 mips riscv64 sparc x86_64 + // No warning on: aarch64-compat32 powerpc sh3 + // Unknown: coldfire hppa ia64 m68000 m68k mips64 mipsn64 or1k powerpc64 riscv32 sparc64 vax + // + // warning: lossy conversion of 1.84467e+19 to 'unsigned long long' [381] + //u64 = 18446744073709550592.0; + // warning: lossy conversion of 1.84467e+19 to 'unsigned long long' [381] + //u64 = 18446744073709551615.0; + // warning: lossy conversion of 1.84467e+19 to 'unsigned long long' [381] + //u64 = 18446744073709551616.0; +} diff --git a/usr.bin/xlint/lint1/msg_382.c b/usr.bin/xlint/lint1/msg_382.c new file mode 100644 index 000000000000..6b72ce0c4071 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_382.c @@ -0,0 +1,42 @@ +/* $NetBSD: msg_382.c,v 1.2 2025/04/12 17:22:50 rillig Exp $ */ +# 3 "msg_382.c" + +// Test for message: constant assignment of type '%s' in operand of '%s' always evaluates to '%s' [382] + +/* + * Outside strict bool mode, an assignment can be used as a condition, but + * that is generally wrong. Especially if a constant is assigned to a + * variable, the condition always evaluates to that constant value, which + * indicates a typo, as '==' makes more sense than '=' in a condition. + */ + +/* lint1-extra-flags: -X 351 */ + +int +conversions(int a, int b) +{ + /* expect+1: warning: constant assignment of type 'int' in operand of '!' always evaluates to 'true' [382] */ + if (!(a = 13)) + return 1; + /* expect+1: warning: constant assignment of type 'int' in operand of '!' always evaluates to 'false' [382] */ + if (!(b = 0)) + return 2; + if (!(a = a + 1)) + return 3; + + /* expect+1: warning: constant assignment of type 'int' in operand of '&&' always evaluates to 'true' [382] */ + if ((a = 13) && (b == 14)) + return 4; + /* expect+1: warning: constant assignment of type 'int' in operand of '&&' always evaluates to 'true' [382] */ + if ((a == 13) && (b = 14)) + return 5; + + /* expect+1: warning: constant assignment of type 'int' in operand of '||' always evaluates to 'true' [382] */ + if ((a = 13) || (b == 14)) + return 4; + /* expect+1: warning: constant assignment of type 'int' in operand of '||' always evaluates to 'true' [382] */ + if ((a == 13) || (b = 14)) + return 5; + + return a; +} diff --git a/usr.bin/xlint/lint1/msg_383.c b/usr.bin/xlint/lint1/msg_383.c new file mode 100644 index 000000000000..7bfee2d6d34d --- /dev/null +++ b/usr.bin/xlint/lint1/msg_383.c @@ -0,0 +1,56 @@ +/* $NetBSD: msg_383.c,v 1.4 2025/05/04 09:40:03 rillig Exp $ */ +# 3 "msg_383.c" + +// Test for message: passing '%s' as argument %d to '%s' discards '%s' [383] + +/* lint1-extra-flags: -X 351 */ + +void sink_char(char *, const char *, volatile char *, const volatile char *); +void sink_int(int *, const int *, volatile int *, const volatile int *); + +void (*indirect_char)(char *, const char *, volatile char *, const volatile char *); + +struct { + void (*member_char)(char *, const char *, volatile char *, const volatile char *); +} doubly_indirect; + +void +caller(const volatile char *cvcp, const volatile int *cvip, int (*fn)(void)) +{ + /* expect+3: warning: passing 'pointer to const volatile char' as argument 1 to 'sink_char' discards 'const volatile' [383] */ + /* expect+2: warning: passing 'pointer to const volatile char' as argument 2 to 'sink_char' discards 'volatile' [383] */ + /* expect+1: warning: passing 'pointer to const volatile char' as argument 3 to 'sink_char' discards 'const' [383] */ + sink_char(cvcp, cvcp, cvcp, cvcp); + /* expect+3: warning: passing 'pointer to const volatile int' as argument 1 to 'sink_int' discards 'const volatile' [383] */ + /* expect+2: warning: passing 'pointer to const volatile int' as argument 2 to 'sink_int' discards 'volatile' [383] */ + /* expect+1: warning: passing 'pointer to const volatile int' as argument 3 to 'sink_int' discards 'const' [383] */ + sink_int(cvip, cvip, cvip, cvip); + /* expect+4: warning: converting 'pointer to function(void) returning int' to incompatible 'pointer to char' for argument 1 [153] */ + /* expect+3: warning: converting 'pointer to function(void) returning int' to incompatible 'pointer to const char' for argument 2 [153] */ + /* expect+2: warning: converting 'pointer to function(void) returning int' to incompatible 'pointer to volatile char' for argument 3 [153] */ + /* expect+1: warning: converting 'pointer to function(void) returning int' to incompatible 'pointer to const volatile char' for argument 4 [153] */ + sink_char(fn, fn, fn, fn); + + /* expect+3: warning: passing 'pointer to const volatile char' as argument 1 to 'indirect_char' discards 'const volatile' [383] */ + /* expect+2: warning: passing 'pointer to const volatile char' as argument 2 to 'indirect_char' discards 'volatile' [383] */ + /* expect+1: warning: passing 'pointer to const volatile char' as argument 3 to 'indirect_char' discards 'const' [383] */ + indirect_char(cvcp, cvcp, cvcp, cvcp); + + /* expect+3: warning: passing 'pointer to const volatile char' as argument 1 to 'function(pointer to char, pointer to const char, pointer to volatile char, pointer to const volatile char) returning void' discards 'const volatile' [383] */ + /* expect+2: warning: passing 'pointer to const volatile char' as argument 2 to 'function(pointer to char, pointer to const char, pointer to volatile char, pointer to const volatile char) returning void' discards 'volatile' [383] */ + /* expect+1: warning: passing 'pointer to const volatile char' as argument 3 to 'function(pointer to char, pointer to const char, pointer to volatile char, pointer to const volatile char) returning void' discards 'const' [383] */ + doubly_indirect.member_char(cvcp, cvcp, cvcp, cvcp); +} + + +typedef int array[8]; +typedef const int *pointer_to_const_array; + +// The 'const' applies to the pointer target, making it 'const int *'. +int const_array_callee(const array); + +static inline int +const_array_caller(pointer_to_const_array ptr) +{ + return const_array_callee(ptr); +} diff --git a/usr.bin/xlint/lint1/msg_384.c b/usr.bin/xlint/lint1/msg_384.c new file mode 100644 index 000000000000..9c7d21377c26 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_384.c @@ -0,0 +1,26 @@ +/* $NetBSD: msg_384.c,v 1.2 2025/01/03 03:14:47 rillig Exp $ */ +# 3 "msg_384.c" + +// Test for message: function definition for '%s' with identifier list is obsolete in C23 [384] + +/* lint1-extra-flags: -X 351 */ + +/* + * In traditional C, defining a function by listing its parameter names first, + * followed by declarations, was usual. This practice has been obsoleted in + * favor of defining the parameter types right in the declarator. + */ + +static inline int +/* expect+1: warning: function definition for 'function_with_identifier_list' with identifier list is obsolete in C23 [384] */ +function_with_identifier_list(a, b) + int a, b; +{ + return a + b; +} + +static inline int +function_with_prototype(int a, int b) +{ + return a + b; +} diff --git a/usr.bin/xlint/lint1/msg_385.c b/usr.bin/xlint/lint1/msg_385.c new file mode 100644 index 000000000000..fdc749066e06 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_385.c @@ -0,0 +1,58 @@ +/* $NetBSD: msg_385.c,v 1.2 2025/03/10 22:08:36 rillig Exp $ */ +# 3 "msg_385.c" + +// Test for message: do-while macro '%.*s' ends with semicolon [385] + +/* + * A function-like macro that consists of a do-while statement is intended to + * expand to a single statement, but without the trailing semicolon, as the + * semicolon is already provided by the calling site. When the macro expansion + * ends with a semicolon, there are two semicolons, which can lead to syntax + * errors. + */ + +/* lint1-extra-flags: -X 351 */ + +/* expect+1: warning: do-while macro 'wrong_stmt' ends with semicolon [385] */ +#define wrong_stmt() do { } while (0); + +#define correct_stmt() do { } while (0) + +/* expect+5: warning: do-while macro 'wrong_stmt_with_comment' ends with semicolon [385] */ +#define wrong_stmt_with_comment() do { } while (0); /* +a +b +c +*/ + +#define correct_stmt_with_comment() do { } while (0) /* +a +b +c +*/ + +/* The comment marker inside the string literal does not start a comment. */ +#define stmt_with_string() do { print("/*"); } while (0) + +void +call_wrong_stmt(int x) +{ + if (x > 0) + do { } while (0);; + /* expect+1: error: syntax error 'else' [249] */ + else + do { } while (0);; +} + +void +call_correct_stmt(int x) +{ + if (x < 0) + do { } while (0); + else + do { } while (0); +} + +// The macro expansion does start with "do", but not with the keyword "do", +// so don't warn in this case. +#define unrelated() do_something(); diff --git a/usr.bin/xlint/lint1/msg_386.c b/usr.bin/xlint/lint1/msg_386.c new file mode 100644 index 000000000000..fd46580be6c7 --- /dev/null +++ b/usr.bin/xlint/lint1/msg_386.c @@ -0,0 +1,34 @@ +/* $NetBSD: msg_386.c,v 1.1 2025/08/31 20:43:27 rillig Exp $ */ +# 3 "msg_386.c" + +// Test for message: conversion '%.*s' does not mix with '%c' [386] + +/* + * In the snprintb format string, the conversions 'f' and '=' mix well, and so + * do 'F' and ':'. But 'f' doesn't mix with ':', and neither does 'F' mix with + * '='. + */ + +/* lint1-extra-flags: -X 351 */ + +typedef typeof(sizeof 0) size_t; + +void snprintb(char *, size_t, const char *, unsigned long long); + +void +test_snprintb(void) +{ + char buf[50]; + + snprintb(buf, sizeof buf, + "\177\020" + "f\000\020" "field\0" + "" "=\000" "mix\0" + "" ":\001" "no-mix\0" + "F\020\020" "field\0" + "" "=\000" "no-mix\0" + "" ":\000" "mix\0", + /* expect+2: warning: conversion ':' does not mix with 'f' [386] */ + /* expect+1: warning: conversion '=' does not mix with 'F' [386] */ + 0xffffffff); +} diff --git a/usr.bin/xlint/lint1/platform_ilp32_c90.c b/usr.bin/xlint/lint1/platform_ilp32_c90.c new file mode 100644 index 000000000000..73702b2c3f58 --- /dev/null +++ b/usr.bin/xlint/lint1/platform_ilp32_c90.c @@ -0,0 +1,243 @@ +/* $NetBSD: platform_ilp32_c90.c,v 1.3 2024/01/28 08:26:07 rillig Exp $ */ +# 3 "platform_ilp32_c90.c" + +/* + * Tests that are specific to ILP32 platforms and the language level C90. + */ + +/* lint1-flags: -sw -X 351 */ +/* lint1-only-if: ilp32 */ + +void *lex_integer[] = { + /* expect+1: ... integer 'int' ... */ + 2147483647, + /* expect+1: ... integer 'int' ... */ + 0x7fffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 2147483648, + /* expect+1: ... integer 'unsigned int' ... */ + 0x80000000, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 4294967295, + /* expect+1: ... integer 'unsigned int' ... */ + 0xffffffff, + /* expect+1: warning: integer constant out of range [252] */ + 4294967296, + /* expect+1: warning: integer constant out of range [252] */ + 0x0000000100000000, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775807, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffffffffff, + /* expect+1: warning: integer constant out of range [252] */ + 9223372036854775808, + /* expect+1: warning: integer constant out of range [252] */ + 0x8000000000000000, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551615, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551616, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000, + + /* expect+1: ... integer 'unsigned int' ... */ + 2147483647U, + /* expect+1: ... integer 'unsigned int' ... */ + 0x7fffffffU, + /* expect+1: ... integer 'unsigned int' ... */ + 2147483648U, + /* expect+1: ... integer 'unsigned int' ... */ + 0x80000000U, + /* expect+1: ... integer 'unsigned int' ... */ + 4294967295U, + /* expect+1: ... integer 'unsigned int' ... */ + 0xffffffffU, + /* expect+1: warning: integer constant out of range [252] */ + 4294967296U, + /* expect+1: warning: integer constant out of range [252] */ + 0x0000000100000000U, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775807U, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffffffffffU, + /* expect+1: warning: integer constant out of range [252] */ + 9223372036854775808U, + /* expect+1: warning: integer constant out of range [252] */ + 0x8000000000000000U, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551615U, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffffU, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551616U, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000U, + + /* expect+1: ... integer 'long' ... */ + 2147483647L, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 2147483648L, + /* expect+1: ... integer 'unsigned long' ... */ + 0x80000000L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 4294967295L, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffL, + /* expect+1: warning: integer constant out of range [252] */ + 4294967296L, + /* expect+1: warning: integer constant out of range [252] */ + 0x0000000100000000L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775807L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffffffffffL, + /* expect+1: warning: integer constant out of range [252] */ + 9223372036854775808L, + /* expect+1: warning: integer constant out of range [252] */ + 0x8000000000000000L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551615L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551616L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000L, + + /* expect+1: ... integer 'unsigned long' ... */ + 2147483647UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffUL, + /* expect+1: ... integer 'unsigned long' ... */ + 2147483648UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x80000000UL, + /* expect+1: ... integer 'unsigned long' ... */ + 4294967295UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffUL, + /* expect+1: warning: integer constant out of range [252] */ + 4294967296UL, + /* expect+1: warning: integer constant out of range [252] */ + 0x0000000100000000UL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775807UL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffffffffffUL, + /* expect+1: warning: integer constant out of range [252] */ + 9223372036854775808UL, + /* expect+1: warning: integer constant out of range [252] */ + 0x8000000000000000UL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551615UL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffffUL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551616UL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000UL, + + /* expect+1: ... integer 'long long' ... */ + 2147483647LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffLL, + /* expect+1: ... integer 'long long' ... */ + 2147483648LL, + /* expect+1: ... integer 'long long' ... */ + 0x80000000LL, + /* expect+1: ... integer 'long long' ... */ + 4294967295LL, + /* expect+1: ... integer 'long long' ... */ + 0xffffffffLL, + /* expect+1: ... integer 'long long' ... */ + 4294967296LL, + /* expect+1: ... integer 'long long' ... */ + 0x0000000100000000LL, + /* expect+1: ... integer 'long long' ... */ + 9223372036854775807LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808LL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615LL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000LL, + + /* expect+1: ... integer 'unsigned long long' ... */ + 2147483647ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x7fffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 2147483648ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x80000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 4294967295ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 4294967296ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x0000000100000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775807ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x7fffffffffffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffffULL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616ULL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000ULL, +}; diff --git a/usr.bin/xlint/lint1/platform_ilp32_c99.c b/usr.bin/xlint/lint1/platform_ilp32_c99.c new file mode 100644 index 000000000000..94126a816eb2 --- /dev/null +++ b/usr.bin/xlint/lint1/platform_ilp32_c99.c @@ -0,0 +1,227 @@ +/* $NetBSD: platform_ilp32_c99.c,v 1.3 2024/01/28 08:26:07 rillig Exp $ */ +# 3 "platform_ilp32_c99.c" + +/* + * Tests that are specific to ILP32 platforms and the language level C99. + */ + +/* lint1-flags: -Sw -X 351 */ +/* lint1-only-if: ilp32 */ + +void *lex_integer[] = { + /* expect+1: ... integer 'int' ... */ + 2147483647, + /* expect+1: ... integer 'int' ... */ + 0x7fffffff, + /* expect+1: ... integer 'long long' ... */ + 2147483648, + /* expect+1: ... integer 'unsigned int' ... */ + 0x80000000, + /* expect+1: ... integer 'long long' ... */ + 4294967295, + /* expect+1: ... integer 'unsigned int' ... */ + 0xffffffff, + /* expect+1: ... integer 'long long' ... */ + 4294967296, + /* expect+1: ... integer 'long long' ... */ + 0x0000000100000000, + /* expect+1: ... integer 'long long' ... */ + 9223372036854775807, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffffffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000, + + /* expect+1: ... integer 'unsigned int' ... */ + 2147483647U, + /* expect+1: ... integer 'unsigned int' ... */ + 0x7fffffffU, + /* expect+1: ... integer 'unsigned int' ... */ + 2147483648U, + /* expect+1: ... integer 'unsigned int' ... */ + 0x80000000U, + /* expect+1: ... integer 'unsigned int' ... */ + 4294967295U, + /* expect+1: ... integer 'unsigned int' ... */ + 0xffffffffU, + /* expect+1: ... integer 'unsigned long long' ... */ + 4294967296U, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x0000000100000000U, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775807U, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x7fffffffffffffffU, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808U, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000U, + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615U, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffffU, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616U, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000U, + + /* expect+1: ... integer 'long' ... */ + 2147483647L, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffL, + /* expect+1: ... integer 'long long' ... */ + 2147483648L, + /* expect+1: ... integer 'unsigned long' ... */ + 0x80000000L, + /* expect+1: ... integer 'long long' ... */ + 4294967295L, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffL, + /* expect+1: ... integer 'long long' ... */ + 4294967296L, + /* expect+1: ... integer 'long long' ... */ + 0x0000000100000000L, + /* expect+1: ... integer 'long long' ... */ + 9223372036854775807L, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffffffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808L, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615L, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000L, + + /* expect+1: ... integer 'unsigned long' ... */ + 2147483647UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffUL, + /* expect+1: ... integer 'unsigned long' ... */ + 2147483648UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x80000000UL, + /* expect+1: ... integer 'unsigned long' ... */ + 4294967295UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffUL, + /* expect+1: ... integer 'unsigned long long' ... */ + 4294967296UL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x0000000100000000UL, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775807UL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x7fffffffffffffffUL, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808UL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000UL, + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615UL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffffUL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616UL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000UL, + + /* expect+1: ... integer 'long long' ... */ + 2147483647LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffLL, + /* expect+1: ... integer 'long long' ... */ + 2147483648LL, + /* expect+1: ... integer 'long long' ... */ + 0x80000000LL, + /* expect+1: ... integer 'long long' ... */ + 4294967295LL, + /* expect+1: ... integer 'long long' ... */ + 0xffffffffLL, + /* expect+1: ... integer 'long long' ... */ + 4294967296LL, + /* expect+1: ... integer 'long long' ... */ + 0x0000000100000000LL, + /* expect+1: ... integer 'long long' ... */ + 9223372036854775807LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808LL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615LL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000LL, + + /* expect+1: ... integer 'unsigned long long' ... */ + 2147483647ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x7fffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 2147483648ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x80000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 4294967295ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 4294967296ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x0000000100000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775807ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x7fffffffffffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffffULL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616ULL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000ULL, +}; diff --git a/usr.bin/xlint/lint1/platform_ilp32_trad.c b/usr.bin/xlint/lint1/platform_ilp32_trad.c new file mode 100644 index 000000000000..a8cc6fdafdc5 --- /dev/null +++ b/usr.bin/xlint/lint1/platform_ilp32_trad.c @@ -0,0 +1,130 @@ +/* $NetBSD: platform_ilp32_trad.c,v 1.4 2024/02/07 22:59:28 rillig Exp $ */ +# 3 "platform_ilp32_trad.c" + +/* + * Tests that are specific to ILP32 platforms and traditional C. + */ + +/* lint1-flags: -tw -X 351 */ +/* lint1-only-if: ilp32 */ + +void *lex_integer[] = { + /* expect+1: ... integer 'int' ... */ + 2147483647, + /* expect+1: ... integer 'int' ... */ + 0x7fffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 2147483648, + /* expect+1: ... integer 'long' ... */ + 0x80000000, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 4294967295, + /* expect+1: ... integer 'long' ... */ + 0xffffffff, + /* expect+1: warning: integer constant out of range [252] */ + 4294967296, + /* expect+1: warning: integer constant out of range [252] */ + 0x0000000100000000, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 9223372036854775807, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 0x7fffffffffffffff, + /* expect+1: warning: integer constant out of range [252] */ + 9223372036854775808, + /* expect+1: warning: integer constant out of range [252] */ + 0x8000000000000000, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 18446744073709551615, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 0xffffffffffffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 18446744073709551616, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 0x00010000000000000000, + + /* expect+1: ... integer 'long' ... */ + 2147483647L, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 2147483648L, + /* expect+1: ... integer 'long' ... */ + 0x80000000L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 4294967295L, + /* expect+1: ... integer 'long' ... */ + 0xffffffffL, + /* expect+1: warning: integer constant out of range [252] */ + 4294967296L, + /* expect+1: warning: integer constant out of range [252] */ + 0x0000000100000000L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 9223372036854775807L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 0x7fffffffffffffffL, + /* expect+1: warning: integer constant out of range [252] */ + 9223372036854775808L, + /* expect+1: warning: integer constant out of range [252] */ + 0x8000000000000000L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 18446744073709551615L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 0xffffffffffffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 18446744073709551616L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 0x00010000000000000000L, + + /* expect+1: ... integer 'long long' ... */ + 2147483647LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffLL, + /* expect+1: ... integer 'long long' ... */ + 2147483648LL, + /* expect+1: ... integer 'long long' ... */ + 0x80000000LL, + /* expect+1: ... integer 'long long' ... */ + 4294967295LL, + /* expect+1: ... integer 'long long' ... */ + 0xffffffffLL, + /* expect+1: ... integer 'long long' ... */ + 4294967296LL, + /* expect+1: ... integer 'long long' ... */ + 0x0000000100000000LL, + /* expect+1: ... integer 'long long' ... */ + 9223372036854775807LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long long' ... */ + 9223372036854775808LL, + /* expect+1: ... integer 'long long' ... */ + 0x8000000000000000LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long long' ... */ + 18446744073709551615LL, + /* expect+1: ... integer 'long long' ... */ + 0xffffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long long' ... */ + 18446744073709551616LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long long' ... */ + 0x00010000000000000000LL, +}; diff --git a/usr.bin/xlint/lint1/platform_lp64_c90.c b/usr.bin/xlint/lint1/platform_lp64_c90.c new file mode 100644 index 000000000000..27868ccd8241 --- /dev/null +++ b/usr.bin/xlint/lint1/platform_lp64_c90.c @@ -0,0 +1,227 @@ +/* $NetBSD: platform_lp64_c90.c,v 1.3 2024/01/28 08:17:27 rillig Exp $ */ +# 3 "platform_lp64_c90.c" + +/* + * Tests that are specific to LP64 platforms and the language level C90. + */ + +/* lint1-flags: -sw -X 351 */ +/* lint1-only-if: lp64 */ + +void *lex_integer[] = { + /* expect+1: ... integer 'int' ... */ + 2147483647, + /* expect+1: ... integer 'int' ... */ + 0x7fffffff, + /* expect+1: ... integer 'long' ... */ + 2147483648, + /* expect+1: ... integer 'unsigned int' ... */ + 0x80000000, + /* expect+1: ... integer 'long' ... */ + 4294967295, + /* expect+1: ... integer 'unsigned int' ... */ + 0xffffffff, + /* expect+1: ... integer 'long' ... */ + 4294967296, + /* expect+1: ... integer 'long' ... */ + 0x0000000100000000, + /* expect+1: ... integer 'long' ... */ + 9223372036854775807, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffffffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775808, + /* expect+1: ... integer 'unsigned long' ... */ + 0x8000000000000000, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551615, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551616, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000, + + /* expect+1: ... integer 'unsigned int' ... */ + 2147483647U, + /* expect+1: ... integer 'unsigned int' ... */ + 0x7fffffffU, + /* expect+1: ... integer 'unsigned int' ... */ + 2147483648U, + /* expect+1: ... integer 'unsigned int' ... */ + 0x80000000U, + /* expect+1: ... integer 'unsigned int' ... */ + 4294967295U, + /* expect+1: ... integer 'unsigned int' ... */ + 0xffffffffU, + /* expect+1: ... integer 'unsigned long' ... */ + 4294967296U, + /* expect+1: ... integer 'unsigned long' ... */ + 0x0000000100000000U, + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775807U, + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffffffffffU, + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775808U, + /* expect+1: ... integer 'unsigned long' ... */ + 0x8000000000000000U, + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551615U, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffffU, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551616U, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000U, + + /* expect+1: ... integer 'long' ... */ + 2147483647L, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffL, + /* expect+1: ... integer 'long' ... */ + 2147483648L, + /* expect+1: ... integer 'long' ... */ + 0x80000000L, + /* expect+1: ... integer 'long' ... */ + 4294967295L, + /* expect+1: ... integer 'long' ... */ + 0xffffffffL, + /* expect+1: ... integer 'long' ... */ + 4294967296L, + /* expect+1: ... integer 'long' ... */ + 0x0000000100000000L, + /* expect+1: ... integer 'long' ... */ + 9223372036854775807L, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffffffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775808L, + /* expect+1: ... integer 'unsigned long' ... */ + 0x8000000000000000L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551615L, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551616L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000L, + + /* expect+1: ... integer 'unsigned long' ... */ + 2147483647UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffUL, + /* expect+1: ... integer 'unsigned long' ... */ + 2147483648UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x80000000UL, + /* expect+1: ... integer 'unsigned long' ... */ + 4294967295UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffUL, + /* expect+1: ... integer 'unsigned long' ... */ + 4294967296UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x0000000100000000UL, + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775807UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffffffffffUL, + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775808UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x8000000000000000UL, + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551615UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffffUL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551616UL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000UL, + + /* expect+1: ... integer 'long long' ... */ + 2147483647LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffLL, + /* expect+1: ... integer 'long long' ... */ + 2147483648LL, + /* expect+1: ... integer 'long long' ... */ + 0x80000000LL, + /* expect+1: ... integer 'long long' ... */ + 4294967295LL, + /* expect+1: ... integer 'long long' ... */ + 0xffffffffLL, + /* expect+1: ... integer 'long long' ... */ + 4294967296LL, + /* expect+1: ... integer 'long long' ... */ + 0x0000000100000000LL, + /* expect+1: ... integer 'long long' ... */ + 9223372036854775807LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808LL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615LL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000LL, + + /* expect+1: ... integer 'unsigned long long' ... */ + 2147483647ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x7fffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 2147483648ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x80000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 4294967295ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 4294967296ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x0000000100000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775807ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x7fffffffffffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffffULL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616ULL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000ULL, +}; diff --git a/usr.bin/xlint/lint1/platform_lp64_c99.c b/usr.bin/xlint/lint1/platform_lp64_c99.c new file mode 100644 index 000000000000..007ad2a020c7 --- /dev/null +++ b/usr.bin/xlint/lint1/platform_lp64_c99.c @@ -0,0 +1,227 @@ +/* $NetBSD: platform_lp64_c99.c,v 1.3 2024/01/28 08:17:27 rillig Exp $ */ +# 3 "platform_lp64_c99.c" + +/* + * Tests that are specific to LP64 platforms and the language level C99. + */ + +/* lint1-flags: -Sw -X 351 */ +/* lint1-only-if: lp64 */ + +void *lex_integer[] = { + /* expect+1: ... integer 'int' ... */ + 2147483647, + /* expect+1: ... integer 'int' ... */ + 0x7fffffff, + /* expect+1: ... integer 'long' ... */ + 2147483648, + /* expect+1: ... integer 'unsigned int' ... */ + 0x80000000, + /* expect+1: ... integer 'long' ... */ + 4294967295, + /* expect+1: ... integer 'unsigned int' ... */ + 0xffffffff, + /* expect+1: ... integer 'long' ... */ + 4294967296, + /* expect+1: ... integer 'long' ... */ + 0x0000000100000000, + /* expect+1: ... integer 'long' ... */ + 9223372036854775807, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffffffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808, + /* expect+1: ... integer 'unsigned long' ... */ + 0x8000000000000000, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000, + + /* expect+1: ... integer 'unsigned int' ... */ + 2147483647U, + /* expect+1: ... integer 'unsigned int' ... */ + 0x7fffffffU, + /* expect+1: ... integer 'unsigned int' ... */ + 2147483648U, + /* expect+1: ... integer 'unsigned int' ... */ + 0x80000000U, + /* expect+1: ... integer 'unsigned int' ... */ + 4294967295U, + /* expect+1: ... integer 'unsigned int' ... */ + 0xffffffffU, + /* expect+1: ... integer 'unsigned long' ... */ + 4294967296U, + /* expect+1: ... integer 'unsigned long' ... */ + 0x0000000100000000U, + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775807U, + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffffffffffU, + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775808U, + /* expect+1: ... integer 'unsigned long' ... */ + 0x8000000000000000U, + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551615U, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffffU, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551616U, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000U, + + /* expect+1: ... integer 'long' ... */ + 2147483647L, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffL, + /* expect+1: ... integer 'long' ... */ + 2147483648L, + /* expect+1: ... integer 'long' ... */ + 0x80000000L, + /* expect+1: ... integer 'long' ... */ + 4294967295L, + /* expect+1: ... integer 'long' ... */ + 0xffffffffL, + /* expect+1: ... integer 'long' ... */ + 4294967296L, + /* expect+1: ... integer 'long' ... */ + 0x0000000100000000L, + /* expect+1: ... integer 'long' ... */ + 9223372036854775807L, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffffffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808L, + /* expect+1: ... integer 'unsigned long' ... */ + 0x8000000000000000L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615L, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000L, + + /* expect+1: ... integer 'unsigned long' ... */ + 2147483647UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffUL, + /* expect+1: ... integer 'unsigned long' ... */ + 2147483648UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x80000000UL, + /* expect+1: ... integer 'unsigned long' ... */ + 4294967295UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffUL, + /* expect+1: ... integer 'unsigned long' ... */ + 4294967296UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x0000000100000000UL, + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775807UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x7fffffffffffffffUL, + /* expect+1: ... integer 'unsigned long' ... */ + 9223372036854775808UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0x8000000000000000UL, + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551615UL, + /* expect+1: ... integer 'unsigned long' ... */ + 0xffffffffffffffffUL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 18446744073709551616UL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long' ... */ + 0x00010000000000000000UL, + + /* expect+1: ... integer 'long long' ... */ + 2147483647LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffLL, + /* expect+1: ... integer 'long long' ... */ + 2147483648LL, + /* expect+1: ... integer 'long long' ... */ + 0x80000000LL, + /* expect+1: ... integer 'long long' ... */ + 4294967295LL, + /* expect+1: ... integer 'long long' ... */ + 0xffffffffLL, + /* expect+1: ... integer 'long long' ... */ + 4294967296LL, + /* expect+1: ... integer 'long long' ... */ + 0x0000000100000000LL, + /* expect+1: ... integer 'long long' ... */ + 9223372036854775807LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808LL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615LL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000LL, + + /* expect+1: ... integer 'unsigned long long' ... */ + 2147483647ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x7fffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 2147483648ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x80000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 4294967295ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 4294967296ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x0000000100000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775807ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x7fffffffffffffffULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 9223372036854775808ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0x8000000000000000ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551615ULL, + /* expect+1: ... integer 'unsigned long long' ... */ + 0xffffffffffffffffULL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 18446744073709551616ULL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'unsigned long long' ... */ + 0x00010000000000000000ULL, +}; diff --git a/usr.bin/xlint/lint1/platform_lp64_trad.c b/usr.bin/xlint/lint1/platform_lp64_trad.c new file mode 100644 index 000000000000..a57db68ceb2e --- /dev/null +++ b/usr.bin/xlint/lint1/platform_lp64_trad.c @@ -0,0 +1,122 @@ +/* $NetBSD: platform_lp64_trad.c,v 1.4 2024/02/07 07:42:50 rillig Exp $ */ +# 3 "platform_lp64_trad.c" + +/* + * Tests that are specific to LP64 platforms and traditional C. + */ + +/* lint1-flags: -tw -X 351 */ +/* lint1-only-if: lp64 */ + +void *lex_integer[] = { + /* expect+1: ... integer 'int' ... */ + 2147483647, + /* expect+1: ... integer 'int' ... */ + 0x7fffffff, + /* expect+1: ... integer 'long' ... */ + 2147483648, + /* expect+1: ... integer 'long' ... */ + 0x80000000, + /* expect+1: ... integer 'long' ... */ + 4294967295, + /* expect+1: ... integer 'long' ... */ + 0xffffffff, + /* expect+1: ... integer 'long' ... */ + 4294967296, + /* expect+1: ... integer 'long' ... */ + 0x0000000100000000, + /* expect+1: ... integer 'long' ... */ + 9223372036854775807, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffffffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 9223372036854775808, + /* expect+1: ... integer 'long' ... */ + 0x8000000000000000, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 18446744073709551615, + /* expect+1: ... integer 'long' ... */ + 0xffffffffffffffff, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 18446744073709551616, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 0x00010000000000000000, + + /* expect+1: ... integer 'long' ... */ + 2147483647L, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffL, + /* expect+1: ... integer 'long' ... */ + 2147483648L, + /* expect+1: ... integer 'long' ... */ + 0x80000000L, + /* expect+1: ... integer 'long' ... */ + 4294967295L, + /* expect+1: ... integer 'long' ... */ + 0xffffffffL, + /* expect+1: ... integer 'long' ... */ + 4294967296L, + /* expect+1: ... integer 'long' ... */ + 0x0000000100000000L, + /* expect+1: ... integer 'long' ... */ + 9223372036854775807L, + /* expect+1: ... integer 'long' ... */ + 0x7fffffffffffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 9223372036854775808L, + /* expect+1: ... integer 'long' ... */ + 0x8000000000000000L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 18446744073709551615L, + /* expect+1: ... integer 'long' ... */ + 0xffffffffffffffffL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 18446744073709551616L, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long' ... */ + 0x00010000000000000000L, + + /* expect+1: ... integer 'long long' ... */ + 2147483647LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffLL, + /* expect+1: ... integer 'long long' ... */ + 2147483648LL, + /* expect+1: ... integer 'long long' ... */ + 0x80000000LL, + /* expect+1: ... integer 'long long' ... */ + 4294967295LL, + /* expect+1: ... integer 'long long' ... */ + 0xffffffffLL, + /* expect+1: ... integer 'long long' ... */ + 4294967296LL, + /* expect+1: ... integer 'long long' ... */ + 0x0000000100000000LL, + /* expect+1: ... integer 'long long' ... */ + 9223372036854775807LL, + /* expect+1: ... integer 'long long' ... */ + 0x7fffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long long' ... */ + 9223372036854775808LL, + /* expect+1: ... integer 'long long' ... */ + 0x8000000000000000LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long long' ... */ + 18446744073709551615LL, + /* expect+1: ... integer 'long long' ... */ + 0xffffffffffffffffLL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long long' ... */ + 18446744073709551616LL, + /* expect+2: warning: integer constant out of range [252] */ + /* expect+1: ... integer 'long long' ... */ + 0x00010000000000000000LL, +}; diff --git a/usr.sbin/certctl/Makefile b/usr.sbin/certctl/Makefile new file mode 100644 index 000000000000..962a472cb281 --- /dev/null +++ b/usr.sbin/certctl/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 05:27:14 riastradh Exp $ +# + +.include "Makefile.inc" # TESTSDIR + +SUBDIR= certs1 certs2 certs3 certs4 + +TESTS_SH= t_certctl + +.include <bsd.test.mk> diff --git a/usr.sbin/certctl/Makefile.inc b/usr.sbin/certctl/Makefile.inc new file mode 100644 index 000000000000..b3c142bf5aba --- /dev/null +++ b/usr.sbin/certctl/Makefile.inc @@ -0,0 +1,6 @@ +# $NetBSD: Makefile.inc,v 1.1 2023/08/26 05:27:14 riastradh Exp $ +# + +TESTSDIR= ${TESTSBASE}/usr.sbin/certctl + +.include <bsd.own.mk> diff --git a/usr.sbin/certctl/certs1/DigiCert_Global_Root_CA.pem b/usr.sbin/certctl/certs1/DigiCert_Global_Root_CA.pem new file mode 100644 index 000000000000..fd4341df2663 --- /dev/null +++ b/usr.sbin/certctl/certs1/DigiCert_Global_Root_CA.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- diff --git a/usr.sbin/certctl/certs1/Explicitly_Distrust_DigiNotar_Root_CA.pem b/usr.sbin/certctl/certs1/Explicitly_Distrust_DigiNotar_Root_CA.pem new file mode 100644 index 000000000000..ab60ad25fe99 --- /dev/null +++ b/usr.sbin/certctl/certs1/Explicitly_Distrust_DigiNotar_Root_CA.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQD////////////////////zANBgkqhkiG9w0BAQUFADBf +MQswCQYDVQQGEwJOTDESMBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdp +Tm90YXIgUm9vdCBDQTEgMB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmww +HhcNMDcwNzI3MTcxOTM3WhcNMjUwMzMxMTgxOTIyWjBfMQswCQYDVQQGEwJOTDES +MBAGA1UEChMJRGlnaU5vdGFyMRowGAYDVQQDExFEaWdpTm90YXIgUm9vdCBDQTEg +MB4GCSqGSIb3DQEJARYRaW5mb0BkaWdpbm90YXIubmwwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCssFjBAL3YIQgLK5r+blYwBZ8bd5AQQVzDDYcRd46B +8cp86Yxq7Th0Nbva3/m7wAk3tJZzgX0zGpg595NvlX89ubF1h7pRSOiLcD6VBMXY +tsMW2YiwsYcdcNqGtA8Ui3rPENF0NqISe3eGSnnme98CEWilToauNFibJBN4ViIl +HgGLS1Fx+4LMWZZpiFpoU8W5DQI3y0u8ZkqQfioLBQftFl9VkHXYRskbg+IIvvEj +zJkd1ioPgyAVWCeCLvriIsJJsbkBgWqdbZ1Ad2h2TiEqbYRAhU52mXyC8/O3AlnU +JgEbjt+tUwbRrhjd4rI6y9eIOI6sWym5GdOY+RgDz0iChmYLG2kPyes4iHomGgVM +ktck1JbyrFIto0fVUvY//s6EBnCmqj6i8rZWNBhXouSBbefK8GrTx5FrAoNBfBXv +a5pkXuPQPOWx63tdhvvL5ndJzaNl3Pe5nLjkC1+Tz8wwGjIczhxjlaX56uF0i57p +K6kwe6AYHw4YC+VbqdPRbB4HZ4+RS6mKvNJmqpMBiLKR+jFc1abBUggJzQpjotMi +puih2TkGl/VujQKQjBR7P4DNG5y6xFhyI6+2Vp/GekIzKQc/gsnmHwUNzUwoNovT +yD4cxojvXu6JZOkd69qJfjKmadHdzIif0dDJZiHcBmfFlHqabWJMfczgZICynkeO +owIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUiGi/4I41xDs4a2L3KDuEgcgM100wDQYJKoZIhvcNAQEFBQADggIBADsC +jcs8MOhuoK3yc7NfniUTBAXT9uOLuwt5zlPe5JbF0a9zvNXD0EBVfEB/zRtfCdXy +fJ9oHbtdzno5wozWmHvFg1Wo1X1AyuAe94leY12hE8JdiraKfADzI8PthV9xdvBo +Y6pFITlIYXg23PFDk9Qlx/KAZeFTAnVR/Ho67zerhChXDNjU1JlWbOOi/lmEtDHo +M/hklJRRl6s5xUvt2t2AC298KQ3EjopyDedTFLJgQT2EkTFoPSdE2+Xe9PpjRchM +Ppj1P0G6Tss3DbpmmPHdy59c91Q2gmssvBNhl0L4eLvMyKKfyvBovWsdst+Nbwed +2o5nx0ceyrm/KkKRt2NTZvFCo+H0Wk1Ya7XkpDOtXHAd3ODy63MUkZoDweoAZbwH +/M8SESIsrqC9OuCiKthZ6SnTGDWkrBFfGbW1G/8iSlzGeuQX7yCpp/Q/rYqnmgQl +nQ7KN+ZQ/YxCKQSa7LnPS3K94gg2ryMvYuXKAdNw23yCIywWMQzGNgeQerEfZ1jE +O1hZibCMjFCz2IbLaKPECudpSyDOwR5WS5WpI2jYMNjD67BVUc3l/Su49bsRn1NU +9jQZjHkJNsphFyUXC4KYcwx3dMPVDceoEkzHp1RxRy4sGn3J4ys7SN4nhKdjNrN9 +j6BkOSQNPXuHr2ZcdBtLc7LljPCGmbjlxd+Ewbfr +-----END CERTIFICATE----- diff --git a/usr.sbin/certctl/certs1/Makefile b/usr.sbin/certctl/certs1/Makefile new file mode 100644 index 000000000000..b75066c9a7b9 --- /dev/null +++ b/usr.sbin/certctl/certs1/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 05:27:14 riastradh Exp $ +# + +FILESDIR= ${TESTSDIR}/certs1 + +FILES+= DigiCert_Global_Root_CA.pem +FILES+= Explicitly_Distrust_DigiNotar_Root_CA.pem + +.include <bsd.files.mk> +.include <bsd.inc.mk> diff --git a/usr.sbin/certctl/certs2/GTS_Root_R1.pem b/usr.sbin/certctl/certs2/GTS_Root_R1.pem new file mode 100644 index 000000000000..a13aa0564117 --- /dev/null +++ b/usr.sbin/certctl/certs2/GTS_Root_R1.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE----- diff --git a/usr.sbin/certctl/certs2/GlobalSign_Root_CA_-_R3.pem b/usr.sbin/certctl/certs2/GlobalSign_Root_CA_-_R3.pem new file mode 100644 index 000000000000..8afb219058fb --- /dev/null +++ b/usr.sbin/certctl/certs2/GlobalSign_Root_CA_-_R3.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- diff --git a/usr.sbin/certctl/certs2/Makefile b/usr.sbin/certctl/certs2/Makefile new file mode 100644 index 000000000000..8b046afd6ad5 --- /dev/null +++ b/usr.sbin/certctl/certs2/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 05:27:14 riastradh Exp $ +# + +FILESDIR= ${TESTSDIR}/certs2 + +FILES+= GTS_Root_R1.pem +FILES+= GlobalSign_Root_CA_-_R3.pem + +.include <bsd.files.mk> +.include <bsd.inc.mk> diff --git a/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.1.pem b/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.1.pem new file mode 100644 index 000000000000..842652306722 --- /dev/null +++ b/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.1.pem @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 +MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc +tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd +IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC +AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw +ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m +iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF +Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ +hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P +Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE +EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV +1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t +CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR +5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw +f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 +ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK +GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE----- diff --git a/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem b/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem new file mode 100644 index 000000000000..de97f841cbfa --- /dev/null +++ b/usr.sbin/certctl/certs3/Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem @@ -0,0 +1,35 @@ +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- diff --git a/usr.sbin/certctl/certs3/Makefile b/usr.sbin/certctl/certs3/Makefile new file mode 100644 index 000000000000..c9721ef7aa2a --- /dev/null +++ b/usr.sbin/certctl/certs3/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 05:27:14 riastradh Exp $ +# + +FILESDIR= ${TESTSDIR}/certs3 + +FILES+= Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.1.pem +FILES+= Autoridad_de_Certificacion_Firmaprofesional_CIF_A62634068.pem + +.include <bsd.files.mk> +.include <bsd.inc.mk> diff --git a/usr.sbin/certctl/certs4/AC_RAIZ_FNMT-RCM.pem b/usr.sbin/certctl/certs4/AC_RAIZ_FNMT-RCM.pem new file mode 100644 index 000000000000..666cf67c32be --- /dev/null +++ b/usr.sbin/certctl/certs4/AC_RAIZ_FNMT-RCM.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- diff --git a/usr.sbin/certctl/certs4/DigiCert_Global_Root_CA.pem b/usr.sbin/certctl/certs4/DigiCert_Global_Root_CA.pem new file mode 100644 index 000000000000..fd4341df2663 --- /dev/null +++ b/usr.sbin/certctl/certs4/DigiCert_Global_Root_CA.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- diff --git a/usr.sbin/certctl/certs4/Makefile b/usr.sbin/certctl/certs4/Makefile new file mode 100644 index 000000000000..6fe3a4d5f118 --- /dev/null +++ b/usr.sbin/certctl/certs4/Makefile @@ -0,0 +1,10 @@ +# $NetBSD: Makefile,v 1.1 2023/08/26 05:27:15 riastradh Exp $ +# + +FILESDIR= ${TESTSDIR}/certs4 + +FILES+= AC_RAIZ_FNMT-RCM.pem +FILES+= DigiCert_Global_Root_CA.pem + +.include <bsd.files.mk> +.include <bsd.inc.mk> diff --git a/usr.sbin/certctl/t_certctl.sh b/usr.sbin/certctl/t_certctl.sh new file mode 100644 index 000000000000..d14a57283404 --- /dev/null +++ b/usr.sbin/certctl/t_certctl.sh @@ -0,0 +1,486 @@ +#!/bin/sh + +# $NetBSD: t_certctl.sh,v 1.10 2023/09/05 12:32:30 riastradh Exp $ +# +# Copyright (c) 2023 The NetBSD Foundation, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +CERTCTL="certctl -C certs.conf -c certs -u untrusted" + +# setupconf <subdir>... +# +# Create certs/ and set up certs.conf to search the specified +# subdirectories of the source directory. +# +setupconf() +{ + local sep subdir dir + + mkdir certs + cat <<EOF >certs.conf +netbsd-certctl 20230816 + +# comment at line start + # comment not at line start, plus some intentional whitespace + +# THE WHITESPACE ABOVE IS INTENTIONAL, DO NOT DELETE +EOF + # Start with a continuation line separator; then switch to + # non-continuation lines. + sep=$(printf ' \\\n\t') + for subdir; do + dir=$(atf_get_srcdir)/$subdir + cat <<EOF >>certs.conf +path$sep$(printf '%s' "$dir" | vis -M) +EOF + sep=' ' + done +} + +# check_empty +# +# Verify the certs directory is empty after dry runs or after +# clearing the directory. +# +check_empty() +{ + local why + + why=${1:-dry run} + for x in certs/*; do + if [ -e "$x" -o -h "$x" ]; then + atf_fail "certs/ should be empty after $why" + fi + done +} + +# check_nonempty +# +# Verify the certs directory is nonempty. +# +check_nonempty() +{ + for x in certs/*.0; do + test -e "$x" && test -h "$x" && return + done + atf_fail "certs/ should be nonempty" +} + +# checks <certsN>... +# +# Run various checks with certctl. +# +checks() +{ + local certs1 diginotar_base diginotar diginotar_hash subdir srcdir + + certs1=$(atf_get_srcdir)/certs1 + diginotar_base=Explicitly_Distrust_DigiNotar_Root_CA.pem + diginotar=$certs1/$diginotar_base + diginotar_hash=$(openssl x509 -hash -noout <$diginotar) + + # Do a dry run of rehash and make sure the directory is still + # empty. + atf_check -s exit:0 $CERTCTL -n rehash + check_empty + + # Distrust and trust one CA, as a dry run. The trust should + # fail because it's not currently distrusted. + atf_check -s exit:0 $CERTCTL -n untrust "$diginotar" + check_empty + atf_check -s not-exit:0 -e match:currently \ + $CERTCTL -n trust "$diginotar" + check_empty + + # Do a real rehash, not a dry run. + atf_check -s exit:0 $CERTCTL rehash + + # Make sure all the certificates are trusted. + for subdir; do + case $subdir in + /*) srcdir=$subdir;; + *) srcdir=$(atf_get_srcdir)/$subdir;; + esac + for cert in "$srcdir"/*.pem; do + # Verify the certificate is linked by its base name. + certbase=$(basename "$cert") + atf_check -s exit:0 -o inline:"$cert" \ + readlink -n "certs/$certbase" + + # Verify the certificate is linked by a hash. + hash=$(openssl x509 -hash -noout <$cert) + counter=0 + found=false + while [ $counter -lt 10 ]; do + if cmp -s "certs/$hash.$counter" "$cert"; then + found=true + break + fi + counter=$((counter + 1)) + done + if ! $found; then + atf_fail "missing $cert" + fi + + # Delete both links. + rm "certs/$certbase" + rm "certs/$hash.$counter" + done + done + + # Verify the certificate bundle is there with the right + # permissions (0644) and delete it. + # + # XXX Verify its content. + atf_check -s exit:0 test -f certs/ca-certificates.crt + atf_check -s exit:0 test ! -h certs/ca-certificates.crt + atf_check -s exit:0 -o inline:'100644\n' \ + stat -f %p certs/ca-certificates.crt + rm certs/ca-certificates.crt + + # Make sure after deleting everything there's nothing left. + check_empty "removing all expected certificates" + + # Distrust, trust, and re-distrust one CA, and verify that it + # ceases to appear, reappears, and again ceases to appear. + # (This one has no subject hash collisions to worry about, so + # we hard-code the `.0' suffix.) + atf_check -s exit:0 $CERTCTL untrust "$diginotar" + atf_check -s exit:0 test -e "untrusted/$diginotar_base" + atf_check -s exit:0 test -h "untrusted/$diginotar_base" + atf_check -s exit:0 test ! -e "certs/$diginotar_base" + atf_check -s exit:0 test ! -h "certs/$diginotar_base" + atf_check -s exit:0 test ! -e "certs/$diginotar_hash.0" + atf_check -s exit:0 test ! -h "certs/$diginotar_hash.0" + check_nonempty + + atf_check -s exit:0 $CERTCTL trust "$diginotar" + atf_check -s exit:0 test ! -e "untrusted/$diginotar_base" + atf_check -s exit:0 test ! -h "untrusted/$diginotar_base" + atf_check -s exit:0 test -e "certs/$diginotar_base" + atf_check -s exit:0 test -h "certs/$diginotar_base" + atf_check -s exit:0 test -e "certs/$diginotar_hash.0" + atf_check -s exit:0 test -h "certs/$diginotar_hash.0" + rm "certs/$diginotar_base" + rm "certs/$diginotar_hash.0" + check_nonempty + + atf_check -s exit:0 $CERTCTL untrust "$diginotar" + atf_check -s exit:0 test -e "untrusted/$diginotar_base" + atf_check -s exit:0 test -h "untrusted/$diginotar_base" + atf_check -s exit:0 test ! -e "certs/$diginotar_base" + atf_check -s exit:0 test ! -h "certs/$diginotar_base" + atf_check -s exit:0 test ! -e "certs/$diginotar_hash.0" + atf_check -s exit:0 test ! -h "certs/$diginotar_hash.0" + check_nonempty +} + +atf_test_case empty +empty_head() +{ + atf_set "descr" "Test empty certificates store" +} +empty_body() +{ + setupconf # no directories + check_empty "empty cert path" + atf_check -s exit:0 $CERTCTL -n rehash + check_empty + atf_check -s exit:0 $CERTCTL rehash + atf_check -s exit:0 test -f certs/ca-certificates.crt + atf_check -s exit:0 test \! -h certs/ca-certificates.crt + atf_check -s exit:0 test \! -s certs/ca-certificates.crt + atf_check -s exit:0 rm certs/ca-certificates.crt + check_empty "empty cert path" +} + +atf_test_case onedir +onedir_head() +{ + atf_set "descr" "Test one certificates directory" +} +onedir_body() +{ + setupconf certs1 + checks certs1 +} + +atf_test_case twodir +twodir_head() +{ + atf_set "descr" "Test two certificates directories" +} +twodir_body() +{ + setupconf certs1 certs2 + checks certs1 certs2 +} + +atf_test_case collidehash +collidehash_head() +{ + atf_set "descr" "Test colliding hashes" +} +collidehash_body() +{ + # certs3 has two certificates with the same subject hash + setupconf certs1 certs3 + checks certs1 certs3 +} + +atf_test_case collidebase +collidebase_head() +{ + atf_set "descr" "Test colliding base names" +} +collidebase_body() +{ + # certs1 and certs4 both have DigiCert_Global_Root_CA.pem, + # which should cause list and rehash to fail and mention + # duplicates. + setupconf certs1 certs4 + atf_check -s not-exit:0 -o ignore -e match:duplicate $CERTCTL list + atf_check -s not-exit:0 -o ignore -e match:duplicate $CERTCTL rehash +} + +atf_test_case manual +manual_head() +{ + atf_set "descr" "Test manual operation" +} +manual_body() +{ + local certs1 diginotar_base diginotar diginotar_hash + + certs1=$(atf_get_srcdir)/certs1 + diginotar_base=Explicitly_Distrust_DigiNotar_Root_CA.pem + diginotar=$certs1/$diginotar_base + diginotar_hash=$(openssl x509 -hash -noout <$diginotar) + + setupconf certs1 certs2 + cat <<EOF >>certs.conf +manual +EOF + touch certs/bogus.pem + ln -s bogus.pem certs/0123abcd.0 + + # Listing shouldn't mention anything in the certs/ cache. + atf_check -s exit:0 -o not-match:bogus $CERTCTL list + atf_check -s exit:0 -o not-match:bogus $CERTCTL untrusted + + # Rehashing and changing the configuration should succeed, but + # mention `manual' in a warning message and should not touch + # the cache. + atf_check -s exit:0 -e match:manual $CERTCTL rehash + atf_check -s exit:0 -e match:manual $CERTCTL untrust "$diginotar" + atf_check -s exit:0 -e match:manual $CERTCTL trust "$diginotar" + + # The files we created should still be there. + atf_check -s exit:0 test -f certs/bogus.pem + atf_check -s exit:0 test -h certs/0123abcd.0 +} + +atf_test_case evilcertsdir +evilcertsdir_head() +{ + atf_set "descr" "Test certificate directory with evil characters" +} +evilcertsdir_body() +{ + local certs1 diginotar_base diginotar evilcertsdir evildistrustdir + + certs1=$(atf_get_srcdir)/certs1 + diginotar_base=Explicitly_Distrust_DigiNotar_Root_CA.pem + diginotar=$certs1/$diginotar_base + + evilcertsdir=$(printf '-evil certs\n.') + evilcertsdir=${evilcertsdir%.} + evildistrustdir=$(printf '-evil untrusted\n.') + evildistrustdir=${evildistrustdir%.} + + setupconf certs1 + + # initial (re)hash, nonexistent certs directory + atf_check -s exit:0 $CERTCTL rehash + atf_check -s exit:0 certctl -C certs.conf \ + -c "$evilcertsdir" -u "$evildistrustdir" \ + rehash + atf_check -s exit:0 diff -ruN -- certs "$evilcertsdir" + atf_check -s exit:0 test ! -e untrusted + atf_check -s exit:0 test ! -h untrusted + atf_check -s exit:0 test ! -e "$evildistrustdir" + atf_check -s exit:0 test ! -h "$evildistrustdir" + + # initial (re)hash, empty certs directory + atf_check -s exit:0 rm -rf -- certs + atf_check -s exit:0 rm -rf -- "$evilcertsdir" + atf_check -s exit:0 mkdir -- certs + atf_check -s exit:0 mkdir -- "$evilcertsdir" + atf_check -s exit:0 $CERTCTL rehash + atf_check -s exit:0 certctl -C certs.conf \ + -c "$evilcertsdir" -u "$evildistrustdir" \ + rehash + atf_check -s exit:0 diff -ruN -- certs "$evilcertsdir" + atf_check -s exit:0 test ! -e untrusted + atf_check -s exit:0 test ! -h untrusted + atf_check -s exit:0 test ! -e "$evildistrustdir" + atf_check -s exit:0 test ! -h "$evildistrustdir" + + # test distrusting a CA + atf_check -s exit:0 $CERTCTL untrust "$diginotar" + atf_check -s exit:0 certctl -C certs.conf \ + -c "$evilcertsdir" -u "$evildistrustdir" \ + untrust "$diginotar" + atf_check -s exit:0 diff -ruN -- certs "$evilcertsdir" + atf_check -s exit:0 diff -ruN -- untrusted "$evildistrustdir" + + # second rehash + atf_check -s exit:0 $CERTCTL rehash + atf_check -s exit:0 certctl -C certs.conf \ + -c "$evilcertsdir" -u "$evildistrustdir" \ + rehash + atf_check -s exit:0 diff -ruN -- certs "$evilcertsdir" + atf_check -s exit:0 diff -ruN -- untrusted "$evildistrustdir" +} + +atf_test_case evilpath +evilpath_head() +{ + atf_set "descr" "Test certificate paths with evil characters" +} +evilpath_body() +{ + local evildir + + evildir=$(printf 'evil\n.') + evildir=${evildir%.} + mkdir "$evildir" + + cp -p "$(atf_get_srcdir)/certs2"/*.pem "$evildir"/ + + setupconf certs1 + cat <<EOF >>certs.conf +path $(printf '%s' "$(pwd)/$evildir" | vis -M) +EOF + checks certs1 "$(pwd)/$evildir" +} + +atf_test_case missingconf +missingconf_head() +{ + atf_set "descr" "Test certctl with missing certs.conf" +} +missingconf_body() +{ + mkdir certs + atf_check -s exit:0 test ! -e certs.conf + atf_check -s not-exit:0 -e match:'certs\.conf' \ + $CERTCTL rehash +} + +atf_test_case nonexistentcertsdir +nonexistentcertsdir_head() +{ + atf_set "descr" "Test certctl succeeds when certsdir is nonexistent" +} +nonexistentcertsdir_body() +{ + setupconf certs1 + rmdir certs + checks certs1 +} + +atf_test_case symlinkcertsdir +symlinkcertsdir_head() +{ + atf_set "descr" "Test certctl fails when certsdir is a symlink" +} +symlinkcertsdir_body() +{ + setupconf certs1 + rmdir certs + mkdir empty + ln -sfn empty certs + + atf_check -s not-exit:0 -e match:symlink $CERTCTL -n rehash + atf_check -s not-exit:0 -e match:symlink $CERTCTL rehash + atf_check -s exit:0 rmdir empty +} + +atf_test_case regularfilecertsdir +regularfilecertsdir_head() +{ + atf_set "descr" "Test certctl fails when certsdir is a regular file" +} +regularfilecertsdir_body() +{ + setupconf certs1 + rmdir certs + echo 'hello world' >certs + + atf_check -s not-exit:0 -e match:directory $CERTCTL -n rehash + atf_check -s not-exit:0 -e match:directory $CERTCTL rehash + atf_check -s exit:0 rm certs +} + +atf_test_case prepopulatedcerts +prepopulatedcerts_head() +{ + atf_set "descr" "Test certctl fails when directory is prepopulated" +} +prepopulatedcerts_body() +{ + local cert certbase target + + setupconf certs1 + ln -sfn "$(atf_get_srcdir)/certs2"/*.pem certs/ + + atf_check -s not-exit:0 -e match:manual $CERTCTL -n rehash + atf_check -s not-exit:0 -e match:manual $CERTCTL rehash + for cert in "$(atf_get_srcdir)/certs2"/*.pem; do + certbase=$(basename "$cert") + atf_check -s exit:0 -o inline:"$cert" \ + readlink -n "certs/$certbase" + rm "certs/$certbase" + done + check_empty +} + +atf_init_test_cases() +{ + atf_add_test_case collidebase + atf_add_test_case collidehash + atf_add_test_case empty + atf_add_test_case evilcertsdir + atf_add_test_case evilpath + atf_add_test_case manual + atf_add_test_case missingconf + atf_add_test_case nonexistentcertsdir + atf_add_test_case onedir + atf_add_test_case prepopulatedcerts + atf_add_test_case regularfilecertsdir + atf_add_test_case symlinkcertsdir + atf_add_test_case twodir +} diff --git a/usr.sbin/makefs/Makefile b/usr.sbin/makefs/Makefile new file mode 100644 index 000000000000..c614c26b6208 --- /dev/null +++ b/usr.sbin/makefs/Makefile @@ -0,0 +1,8 @@ +# $NetBSD: Makefile,v 1.1 2024/10/18 23:22:52 christos Exp $ + +.include <bsd.own.mk> + +TESTSDIR= ${TESTSBASE}/usr.sbin/makefs +TESTS_SH= t_makefs + +.include <bsd.test.mk> diff --git a/usr.sbin/makefs/t_makefs.sh b/usr.sbin/makefs/t_makefs.sh new file mode 100644 index 000000000000..cf5d6fda54e3 --- /dev/null +++ b/usr.sbin/makefs/t_makefs.sh @@ -0,0 +1,65 @@ +# $NetBSD: t_makefs.sh,v 1.1 2024/10/18 23:22:52 christos Exp $ +# +# Copyright (c) 2024 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Christos Zoulas +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + + +# replace +# +atf_test_case replace replace_cleanup + +replace_head() { + atf_require_prog makefs + atf_set "descr" "Test replacing a single file (PR/58759)" +} + +replace_body() { + export PATH=/sbin:/bin:/usr/sbin:/usr/bin + mkdir -p 1 2/1 + echo foo > 1/foo + echo bar > 2/1/foo + makefs -r -d 0xf0 -s 1m -t ffs foo.img 1 2/1 + dump 0f foo.dump -F foo.img + restore -rf foo.dump + if [ ! -f foo ]; then + atf_fail "file foo does not exist" + fi + x=$(cat foo) + if [ "$x" != "bar" ]; then + atf_fail "file foo does not contain bar, but $x" + fi + atf_pass +} + +replace_cleanup() { + rm -fr 1 2 foo foo.dump foo.img +} + +atf_init_test_cases() { + atf_add_test_case replace +} |
