Browse Source

[core] move backtrace and assert macros to ck.[ch]

master
Glenn Strauss 4 months ago
parent
commit
1cd73b08a6
  1. 4
      src/CMakeLists.txt
  2. 8
      src/Makefile.am
  3. 81
      src/buffer.c
  4. 14
      src/buffer.h
  5. 101
      src/ck.c
  6. 25
      src/ck.h
  7. 8
      src/meson.build
  8. 3
      src/mod_deflate.c
  9. 3
      src/network_write.c
  10. 17
      src/rand.c
  11. 10
      src/sys-crypto-md.h

4
src/CMakeLists.txt

@ -847,12 +847,14 @@ add_executable(test_array
t/test_array.c
array.c
buffer.c
ck.c
)
add_test(NAME test_array COMMAND test_array)
add_executable(test_buffer
t/test_buffer.c
buffer.c
ck.c
)
add_test(NAME test_buffer COMMAND test_buffer)
@ -861,6 +863,7 @@ add_executable(test_burl
burl.c
buffer.c
base64.c
ck.c
)
add_test(NAME test_burl COMMAND test_burl)
@ -868,6 +871,7 @@ add_executable(test_base64
t/test_base64.c
buffer.c
base64.c
ck.c
)
add_test(NAME test_base64 COMMAND test_base64)

8
src/Makefile.am

@ -636,16 +636,16 @@ lighttpd_LDFLAGS = -export-dynamic
endif
t_test_array_SOURCES = t/test_array.c array.c buffer.c
t_test_array_SOURCES = t/test_array.c array.c buffer.c ck.c
t_test_array_LDADD = $(LIBUNWIND_LIBS)
t_test_buffer_SOURCES = t/test_buffer.c buffer.c
t_test_buffer_SOURCES = t/test_buffer.c buffer.c ck.c
t_test_buffer_LDADD = $(LIBUNWIND_LIBS)
t_test_base64_SOURCES = t/test_base64.c base64.c buffer.c
t_test_base64_SOURCES = t/test_base64.c base64.c buffer.c ck.c
t_test_base64_LDADD = $(LIBUNWIND_LIBS)
t_test_burl_SOURCES = t/test_burl.c burl.c buffer.c base64.c
t_test_burl_SOURCES = t/test_burl.c burl.c buffer.c base64.c ck.c
t_test_burl_LDADD = $(LIBUNWIND_LIBS)
t_test_configfile_SOURCES = t/test_configfile.c buffer.c array.c data_config.c http_header.c http_kv.c vector.c log.c sock_addr.c ck.c

81
src/buffer.c

@ -915,84 +915,3 @@ void buffer_to_upper(buffer * const b) {
if (light_islower(s[i])) s[i] &= 0xdf;
}
}
#include <stdio.h>
#ifdef HAVE_LIBUNWIND
# define UNW_LOCAL_ONLY
# include <libunwind.h>
static void print_backtrace(FILE *file) {
unw_cursor_t cursor;
unw_context_t context;
int ret;
unsigned int frame = 0;
if (0 != (ret = unw_getcontext(&context))) goto error;
if (0 != (ret = unw_init_local(&cursor, &context))) goto error;
fprintf(file, "Backtrace:\n");
while (0 < (ret = unw_step(&cursor))) {
unw_word_t proc_ip = 0;
unw_proc_info_t procinfo;
char procname[256];
unw_word_t proc_offset = 0;
if (0 != (ret = unw_get_reg(&cursor, UNW_REG_IP, &proc_ip))) goto error;
if (0 == proc_ip) {
/* without an IP the other functions are useless; unw_get_proc_name would return UNW_EUNSPEC */
++frame;
fprintf(file, "%u: (nil)\n", frame);
continue;
}
if (0 != (ret = unw_get_proc_info(&cursor, &procinfo))) goto error;
if (0 != (ret = unw_get_proc_name(&cursor, procname, sizeof(procname), &proc_offset))) {
switch (-ret) {
case UNW_ENOMEM:
memset(procname + sizeof(procname) - 4, '.', 3);
procname[sizeof(procname) - 1] = '\0';
break;
case UNW_ENOINFO:
procname[0] = '?';
procname[1] = '\0';
proc_offset = 0;
break;
default:
snprintf(procname, sizeof(procname), "?? (unw_get_proc_name error %d)", -ret);
break;
}
}
++frame;
fprintf(file, "%u: %s (+0x%x) [%p]\n",
frame,
procname,
(unsigned int) proc_offset,
(void*)(uintptr_t)proc_ip);
}
if (0 != ret) goto error;
return;
error:
fprintf(file, "Error while generating backtrace: unwind error %i\n", (int) -ret);
}
#else
static void print_backtrace(FILE *file) {
UNUSED(file);
}
#endif
void log_failed_assert(const char *filename, unsigned int line, const char *msg) {
/* can't use buffer here; could lead to recursive assertions */
fprintf(stderr, "%s.%u: %s\n", filename, line, msg);
print_backtrace(stderr);
fflush(stderr);
abort();
}

14
src/buffer.h

@ -262,14 +262,6 @@ static inline int buffer_has_pathsep_suffix (const buffer * const b);
#define CONST_STR_LEN(x) x, (uint32_t)sizeof(x) - 1
#define LI_NORETURN __attribute_noreturn__
__attribute_cold__
void log_failed_assert(const char *filename, unsigned int line, const char *msg) LI_NORETURN;
#define force_assert(x) do { if (!(x)) log_failed_assert(__FILE__, __LINE__, "assertion failed: " #x); } while(0)
#define SEGFAULT() log_failed_assert(__FILE__, __LINE__, "aborted");
/* inline implementations */
__attribute_nonnull__
@ -408,4 +400,10 @@ static inline void buffer_string_set_length(buffer *b, uint32_t len) {
}
#include "ck.h"
#define force_assert(x) ck_assert(x)
#define log_failed_assert(file,line,msg) ck_bt_abort((file),(line),(msg))
#define SEGFAULT() ck_bt_abort(__FILE__, __LINE__, "aborted")
#endif

101
src/ck.c

@ -20,7 +20,7 @@
#include "ck.h"
#include <stdlib.h> /* getenv() getenv_s() */
#include <stdlib.h> /* abort() getenv() getenv_s() */
#include <string.h> /* memcpy() memset() memset_s() explicit_bzero()
* strerror() strerror_r() strerror_s() strlen() */
@ -299,3 +299,102 @@ ck_memeq_const_time_fixed_len (const void *a, const void *b, const size_t len)
}
return (0 == diff);
}
#include <stdio.h> /* fflush() fprintf() snprintf() */
#ifdef HAVE_LIBUNWIND
#define UNW_LOCAL_ONLY
#include <libunwind.h>
__attribute_cold__
__attribute_noinline__
static void
ck_backtrace (FILE *fp)
{
int rc;
unsigned int frame = 0;
unw_word_t ip;
unw_word_t offset;
unw_cursor_t cursor;
unw_context_t context;
unw_proc_info_t procinfo;
char name[256];
rc = unw_getcontext(&context);
if (0 != rc) goto error;
rc = unw_init_local(&cursor, &context);
if (0 != rc) goto error;
fprintf(fp, "Backtrace:\n");
while (0 < (rc = unw_step(&cursor))) {
++frame;
ip = 0;
rc = unw_get_reg(&cursor, UNW_REG_IP, &ip);
if (0 != rc) break;
if (0 == ip) {
/* without an IP the other functions are useless;
* unw_get_proc_name would return UNW_EUNSPEC */
fprintf(fp, "%u: (nil)\n", frame);
continue;
}
rc = unw_get_proc_info(&cursor, &procinfo);
if (0 != rc) break;
offset = 0;
rc = unw_get_proc_name(&cursor, name, sizeof(name), &offset);
if (0 != rc) {
switch (-rc) {
case UNW_ENOMEM:
memcpy(name + sizeof(name) - 4, "...", 4);
break;
case UNW_ENOINFO:
name[0] = '?';
name[1] = '\0';
break;
default:
snprintf(name, sizeof(name),
"?? (unw_get_proc_name error %d)", -rc);
break;
}
}
fprintf(fp, "%u: %s (+0x%x) [%p]\n",
frame, name, (unsigned int)offset, (void *)(uintptr_t)ip);
}
if (0 == rc)
return;
error:
fprintf(fp, "Error while generating backtrace: unwind error %i\n",(int)-rc);
}
#endif
__attribute_noreturn__
void
ck_bt_abort (const char *filename, unsigned int line, const char *msg)
{
fprintf(stderr, "%s.%u: %s\n", filename, line, msg);
#ifdef HAVE_LIBUNWIND
ck_backtrace(stderr);
#endif
fflush(stderr);
abort();
}
__attribute_noreturn__
void ck_assert_failed(const char *filename, unsigned int line, const char *msg)
{
/* same as ck_bt_abort() but add "assertion failed: " prefix here
* to avoid bloating string tables in callers */
fprintf(stderr, "%s.%u: assertion failed: %s\n", filename, line, msg);
#ifdef HAVE_LIBUNWIND
ck_backtrace(stderr);
#endif
fflush(stderr);
abort();
}

25
src/ck.h

@ -4,7 +4,7 @@
* ck is also an abbreviation for "check".
* These are validating, checking functions.
*
* Copyright(c) 2016 Glenn Strauss gstrauss()gluelogic.com All rights reserved
* Copyright(c) 2016,2021 Glenn Strauss gstrauss()gluelogic.com All rights reserved
* License: BSD 3-clause (same as lighttpd)
*/
#ifndef INCLUDED_CK_H
@ -46,13 +46,36 @@ errno_t ck_strerror_s (char *s, rsize_t maxsize, errno_t errnum);
* constant time memory compare for equality
* rounds to next multiple of 64 to avoid potentially leaking exact
* string lengths when subject to high precision timing attacks */
__attribute_nonnull__
int ck_memeq_const_time (const void *a, size_t alen, const void *b, size_t blen);
/*(ck_memeq_const_time_fixed_len() is not from C11 Annex K)
* constant time memory compare for equality for fixed len (e.g. digests)
* (padding not necessary for digests, which have fixed, defined lengths) */
__attribute_nonnull__
int ck_memeq_const_time_fixed_len (const void *a, const void *b, size_t len);
/*(ck_bt_abort() is not from C11 Annex K)
* ck_bt_abort() prints backtrace to stderr and calls abort() */
__attribute_cold__
__attribute_nonnull__
__attribute_noreturn__
void ck_bt_abort(const char *filename, unsigned int line, const char *msg);
/*(ck_assert() and ck_assert_failed() are not from C11 Annex K)
* ck_assert() executes a runtime assertion test or aborts
* ck_assert() *is not* optimized away if defined(NDEBUG)
* (unlike standard assert(), which *is* optimized away if defined(NDEBUG)) */
__attribute_cold__
__attribute_nonnull__
__attribute_noreturn__
void ck_assert_failed(const char *filename, unsigned int line, const char *msg);
#define ck_assert(x) \
do { if (!(x)) ck_assert_failed(__FILE__, __LINE__, #x); } while (0)
__END_DECLS

8
src/meson.build

@ -859,25 +859,25 @@ executable('lighttpd', configparser,
)
test('test_array', executable('test_array',
sources: ['t/test_array.c', 'array.c', 'buffer.c'],
sources: ['t/test_array.c', 'array.c', 'buffer.c', 'ck.c'],
dependencies: common_flags + libunwind,
build_by_default: false,
))
test('test_buffer', executable('test_buffer',
sources: ['t/test_buffer.c', 'buffer.c'],
sources: ['t/test_buffer.c', 'buffer.c', 'ck.c'],
dependencies: common_flags + libunwind,
build_by_default: false,
))
test('test_burl', executable('test_burl',
sources: ['t/test_burl.c', 'burl.c', 'buffer.c', 'base64.c'],
sources: ['t/test_burl.c', 'burl.c', 'buffer.c', 'base64.c', 'ck.c'],
dependencies: common_flags + libunwind,
build_by_default: false,
))
test('test_base64', executable('test_base64',
sources: ['t/test_base64.c', 'buffer.c', 'base64.c'],
sources: ['t/test_base64.c', 'buffer.c', 'base64.c', 'ck.c'],
dependencies: common_flags + libunwind,
build_by_default: false,
))

3
src/mod_deflate.c

@ -110,6 +110,7 @@
#include <unistd.h> /* getpid() read() unlink() write() */
#include "base.h"
#include "ck.h"
#include "fdevent.h"
#include "log.h"
#include "buffer.h"
@ -162,7 +163,7 @@ static sigjmp_buf sigbus_jmp;
static void sigbus_handler(int sig) {
UNUSED(sig);
if (sigbus_jmp_valid) siglongjmp(sigbus_jmp, 1);
log_failed_assert(__FILE__, __LINE__, "SIGBUS");
ck_bt_abort(__FILE__, __LINE__, "SIGBUS");
}
#endif

3
src/network_write.c

@ -3,6 +3,7 @@
#include "network_write.h"
#include "base.h"
#include "ck.h"
#include "log.h"
#include <sys/types.h>
@ -205,7 +206,7 @@ static sigjmp_buf sigbus_jmp;
static void sigbus_handler(int sig) {
UNUSED(sig);
if (sigbus_jmp_valid) siglongjmp(sigbus_jmp, 1);
log_failed_assert(__FILE__, __LINE__, "SIGBUS");
ck_bt_abort(__FILE__, __LINE__, "SIGBUS");
}
/* next chunk must be FILE_CHUNK. send mmap()ed file with write() */

17
src/rand.c

@ -7,7 +7,6 @@
#include "first.h"
#include "rand.h"
#include "buffer.h"
#include "ck.h"
#include "fdevent.h"
@ -206,8 +205,8 @@ li_arcfour_init_random_key_hashed(struct arcfour_ctx *ctx)
uint8_t key[ARCFOUR_KEY_SIZE];
const size_t length = sizeof(key);
if (1 != li_rand_device_bytes(key, (int)sizeof(key))) {
log_failed_assert(__FILE__, __LINE__,
"gathering entropy for arcfour seed failed");
ck_bt_abort(__FILE__, __LINE__,
"gathering entropy for arcfour seed failed");
}
memset(ctx, 0, sizeof(*ctx));
@ -270,8 +269,7 @@ static void li_rand_init (void)
/* xsubi[] is small, so use wc_InitRng() instead of wc_InitRngNonce()
* to get default behavior of a larger internally-generated nonce */
if (0 != wolfCrypt_Init() || 0 != wc_InitRng(&wolf_globalRNG))
log_failed_assert(__FILE__, __LINE__,
"wolfCrypt_Init or wc_InitRng() failed");
ck_bt_abort(__FILE__,__LINE__,"wolfCrypt_Init or wc_InitRng() failed");
#endif
#ifdef USE_OPENSSL_CRYPTO
RAND_poll();
@ -286,13 +284,13 @@ static void li_rand_init (void)
mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(unsigned char *)xsubi, sizeof(xsubi));
if (0 != rc) /*(not expecting built-in entropy function to fail)*/
log_failed_assert(__FILE__, __LINE__, "mbedtls_ctr_drbg_seed() failed");
ck_bt_abort(__FILE__, __LINE__, "mbedtls_ctr_drbg_seed() failed");
#endif
#endif
#endif
#ifdef USE_NSS_CRYPTO
if (!NSS_IsInitialized() && NSS_NoDB_Init(NULL) < 0)
SEGFAULT();
ck_bt_abort(__FILE__, __LINE__, "aborted");
PK11_RandomUpdate(xsubi, sizeof(xsubi));
#endif
}
@ -314,13 +312,12 @@ void li_rand_reseed (void)
(const byte *)xsubi,
(word32)sizeof(xsubi)))
/*(not expecting this to fail)*/
log_failed_assert(__FILE__, __LINE__,
"wc_RNG_DRBG_Reseed() failed");
ck_bt_abort(__FILE__, __LINE__, "wc_RNG_DRBG_Reseed() failed");
}
#else
wc_FreeRng(&wolf_globalRNG);
if (0 != wc_InitRng(&wolf_globalRNG))
log_failed_assert(__FILE__, __LINE__, "wc_InitRng() failed");
ck_bt_abort(__FILE__, __LINE__, "wc_InitRng() failed");
#endif
return;
}

10
src/sys-crypto-md.h

@ -612,7 +612,7 @@ EVP_SHA512_Update(EVP_SHA512_CTX *ctx, const void *data, size_t length)
#elif defined(USE_GNUTLS_CRYPTO)
#include <gnutls/crypto.h>
#include "buffer.h" /* SEGFAULT() */
#include "ck.h"
#define USE_LIB_CRYPTO_MD5
typedef gnutls_hash_hd_t MD5_CTX;
@ -620,7 +620,7 @@ static inline int
MD5_Init(MD5_CTX *ctx)
{
if (gnutls_hash_init(ctx, GNUTLS_DIG_MD5) < 0)
SEGFAULT();
ck_bt_abort(__FILE__, __LINE__, "aborted");
return 1;
}
static inline int
@ -642,7 +642,7 @@ static inline int
SHA1_Init(SHA_CTX *ctx)
{
if (gnutls_hash_init(ctx, GNUTLS_DIG_SHA1) < 0)
SEGFAULT();
ck_bt_abort(__FILE__, __LINE__, "aborted");
return 1;
}
static inline int
@ -664,7 +664,7 @@ static inline int
SHA256_Init(SHA256_CTX *ctx)
{
if (gnutls_hash_init(ctx, GNUTLS_DIG_SHA256) < 0)
SEGFAULT();
ck_bt_abort(__FILE__, __LINE__, "aborted");
return 1;
}
static inline int
@ -686,7 +686,7 @@ static inline int
SHA512_Init(SHA512_CTX *ctx)
{
if (gnutls_hash_init(ctx, GNUTLS_DIG_SHA512) < 0)
SEGFAULT();
ck_bt_abort(__FILE__, __LINE__, "aborted");
return 1;
}
static inline int

Loading…
Cancel
Save