From 2d507aaee4fe57f123e267bf1f8ee50b666c12da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Mon, 14 Nov 2016 12:55:33 +0100 Subject: [PATCH] Implement our own assert() and, more importantly, assertf(). --- include/cryb/Makefile.am | 2 + include/cryb/assert.h | 69 ++++++++++++++++++++++ lib/core/Makefile.am | 6 +- lib/core/cryb_assert.c | 53 +++++++++++++++++ lib/test/cryb_t_malloc.c | 2 +- t/.gitignore | 1 + t/Makefile.am | 2 + t/t_assert.c | 121 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 253 insertions(+), 3 deletions(-) create mode 100644 include/cryb/assert.h create mode 100644 lib/core/cryb_assert.c create mode 100644 t/t_assert.c diff --git a/include/cryb/Makefile.am b/include/cryb/Makefile.am index e1afcb5..1c0655d 100644 --- a/include/cryb/Makefile.am +++ b/include/cryb/Makefile.am @@ -13,6 +13,8 @@ endif CRYB_CIPHER if CRYB_CORE cryb_HEADERS += \ algorithm.h \ + assert.h \ + attributes.h \ bitwise.h \ core.h \ ctype.h \ diff --git a/include/cryb/assert.h b/include/cryb/assert.h new file mode 100644 index 0000000..842b7b5 --- /dev/null +++ b/include/cryb/assert.h @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2016 Dag-Erling Smørgrav + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * 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. + */ + +#ifndef CRYB_ASSERT_H_INCLUDED +#define CRYB_ASSERT_H_INCLUDED + +#ifndef CRYB_TO +#include +#endif + +#ifndef CRYB_COVERAGE +#include +#endif + +#define assertion_failed cryb_assertion_failed + +void assertion_failed(const char *, const char *, unsigned int, + const char *, ...) CRYB_NORETURN; + +#ifndef CRYB_NDEBUG + +#define assertf(exp, ...) \ + do { \ + CRYB_DISABLE_COVERAGE \ + if (!(exp)) \ + assertion_failed(__func__, __FILE__, \ + __LINE__, __VA_ARGS__); \ + CRYB_RESTORE_COVERAGE \ + } while (0) + +#define assert(exp) \ + assertf(exp, "%s", #exp) + +#else + +#define assertf(exp, ...) \ + ((void)0) +#define assert(exp) \ + ((void)0) + +#endif + +#endif diff --git a/lib/core/Makefile.am b/lib/core/Makefile.am index 654462b..facc4e2 100644 --- a/lib/core/Makefile.am +++ b/lib/core/Makefile.am @@ -3,7 +3,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include lib_LTLIBRARIES = libcryb-core.la libcryb_core_la_SOURCES = \ - cryb_core.c \ + cryb_assert.c \ cryb_memset_s.c \ cryb_string.c \ cryb_strlcat.c \ @@ -12,7 +12,9 @@ libcryb_core_la_SOURCES = \ cryb_wcslcat.c \ cryb_wcslcmp.c \ cryb_wcslcpy.c \ - cryb_wstring.c + cryb_wstring.c \ + \ + cryb_core.c EXTRA_DIST = cryb_string_impl.c diff --git a/lib/core/cryb_assert.c b/lib/core/cryb_assert.c new file mode 100644 index 0000000..ae5b142 --- /dev/null +++ b/lib/core/cryb_assert.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2016 Dag-Erling Smørgrav + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * 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. + */ + +#include "cryb/impl.h" + +#include +#include +#include + +#include + +void +assertion_failed(const char *func, const char *file, unsigned int line, + const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "assertion failed in %s() on %s:%u\n", + func, file, line); + if (fmt != NULL) { + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + } + abort(); +} diff --git a/lib/test/cryb_t_malloc.c b/lib/test/cryb_t_malloc.c index 53b58e4..ddb81c7 100644 --- a/lib/test/cryb_t_malloc.c +++ b/lib/test/cryb_t_malloc.c @@ -49,13 +49,13 @@ #endif #endif -#include #include #include #include #include #include +#include #include /* diff --git a/t/.gitignore b/t/.gitignore index 790abef..a8ab2b6 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -2,6 +2,7 @@ /*.trs /t_adler /t_aes +/t_assert /t_cipher /t_core /t_ctype diff --git a/t/Makefile.am b/t/Makefile.am index 88d3bad..d407aac 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -46,6 +46,8 @@ endif CRYB_CIPHER if CRYB_CORE TESTS += t_core t_core_LDADD = $(libt) $(libcore) +TESTS += t_assert +t_assert_LDADD = $(libt) $(libcore) TESTS += t_ctype t_endian t_memset_s t_strlcat t_strlcmp t_strlcpy t_ctype_LDADD = $(libt) $(libcore) t_endian_LDADD = $(libt) $(libcore) diff --git a/t/t_assert.c b/t/t_assert.c new file mode 100644 index 0000000..5822852 --- /dev/null +++ b/t/t_assert.c @@ -0,0 +1,121 @@ +/*- + * Copyright (c) 2016 Dag-Erling Smørgrav + * 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. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * 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. + */ + +#include "cryb/impl.h" + +#include +#include + +#if HAVE_SYS_RESOURCE_H +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#include + +/* + * Verify that an assertion failure causes a SIGABRT. Note that we can't + * just catch the signal, because abort(3) has other side effects (such as + * flushing and closing streams) from which we couldn't recover. + */ +static void +t_assert_child(void) +{ +#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE) + struct rlimit crl = { 0, 0 }; +#endif + + /* reset SIGABRT handler in case of shenanigans */ + signal(SIGABRT, SIG_DFL); +#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_CORE) + /* prevent core dump */ + if (setrlimit(RLIMIT_CORE, &crl) != 0) + t_verbose("failed to disable core dump\n"); +#endif + /* suppress assertion message */ + fclose(stderr); + assert(0); +} + +int +t_assert_fail(char **desc CRYB_UNUSED, void *arg CRYB_UNUSED) +{ + pid_t pid; + int signo, status; + + t_assert((pid = fork()) != -1); + if (pid == 0) { + t_assert_child(); + _exit(1); + } + t_assert(waitpid(pid, &status, 0) == pid); + if (!WIFSIGNALED(status)) { + t_verbose("expected child to raise a signal\n"); + return (0); + } +#ifdef WCOREDUMP + if (WCOREDUMP(status)) + t_verbose("warning: child dumped core\n"); +#endif + if ((signo = WTERMSIG(status)) != SIGABRT) { + t_verbose("expected child to raise signal %d (SIGABRT), " + "got signal %d\n", SIGABRT, signo); + return (0); + } + return (1); +} + + +/*************************************************************************** + * Boilerplate + */ + +static int +t_prepare(int argc, char *argv[]) +{ + + (void)argc; + (void)argv; + t_add_test(t_assert_fail, NULL, "assertion failed"); + return (0); +} + +int +main(int argc, char *argv[]) +{ + + t_main(t_prepare, NULL, argc, argv); +}