From 1ea611c90e7778d2f41b5d2ece9c37b8e262c4b1 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Thu, 20 Dec 2018 14:13:14 +0000 Subject: [PATCH] Improved allocation failure reporting Now it reports file and line number of the function too. Signed-off-by: Yuxuan Shui --- src/meson.build | 2 +- src/string_utils.h | 19 +++++++++++++++++++ src/utils.c | 34 ++++++++++++++++++++++++++++++++++ src/utils.h | 13 +++++-------- 4 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 src/utils.c diff --git a/src/meson.build b/src/meson.build index 7e24251c..4d16488a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,7 +4,7 @@ deps = [ dependency('xcb', version: '>=1.9.2'), ] -srcs = [ files('compton.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'vsync.c', +srcs = [ files('compton.c', 'win.c', 'c2.c', 'x.c', 'config.c', 'vsync.c', 'utils.c', 'diagnostic.c', 'string_utils.c', 'render.c', 'kernel.c', 'log.c')] cflags = [] diff --git a/src/string_utils.h b/src/string_utils.h index c66c7a0e..bff0bd6e 100644 --- a/src/string_utils.h +++ b/src/string_utils.h @@ -11,6 +11,25 @@ char * mstrjoin3(const char *src1, const char *src2, const char *src3); void mstrextend(char **psrc1, const char *src2); +static inline int uitostr(unsigned int n, char *buf) { + int ret = 0; + unsigned int tmp = n; + while (tmp > 0) { + tmp /= 10; + ret++; + } + + if (ret == 0) + ret = 1; + + int pos = ret; + while (pos--) { + buf[pos] = n%10 + '0'; + n /= 10; + } + return ret; +} + static inline const char * skip_space_const(const char *src) { if (!src) diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 00000000..1707ee7d --- /dev/null +++ b/src/utils.c @@ -0,0 +1,34 @@ +#include +#include + +#include "compiler.h" +#include "string_utils.h" +#include "utils.h" + +/// Report allocation failure without allocating memory +void report_allocation_failure(const char *func, const char *file, unsigned int line) { + // Since memory allocation failed, we try to print this error message without any + // memory allocation. Since logging framework allocates memory (and might even + // have not been initialized yet), so we can't use it. + char buf[11]; + int llen = uitostr(line, buf); + const char msg1[] = " has failed to allocate memory, "; + const char msg2[] = ". Aborting...\n"; + const struct iovec v[] = { + {.iov_base = (void *)func, .iov_len = strlen(func)}, + {.iov_base = "()", .iov_len = 2}, + {.iov_base = (void *)msg1, .iov_len = sizeof(msg1) - 1}, + {.iov_base = "at ", .iov_len = 3}, + {.iov_base = (void *)file, .iov_len = strlen(file)}, + {.iov_base = ":", .iov_len = 1}, + {.iov_base = buf, .iov_len = llen}, + {.iov_base = (void *)msg2, .iov_len = sizeof(msg2) - 1}, + }; + + writev(STDERR_FILENO, v, ARR_SIZE(v)); + abort(); + + unreachable; +} + +// vim: set noet sw=8 ts=8 : diff --git a/src/utils.h b/src/utils.h index acd97178..478e4592 100644 --- a/src/utils.h +++ b/src/utils.h @@ -101,24 +101,21 @@ normalize_d(double d) { return normalize_d_range(d, 0.0, 1.0); } +void report_allocation_failure(const char *func, const char *file, unsigned int line); + /** * @brief Quit if the passed-in pointer is empty. */ static inline void * -allocchk_(const char *func_name, void *ptr) { +allocchk_(const char *func_name, const char *file, unsigned int line, void *ptr) { if (unlikely(!ptr)) { - // Since memory allocation failed, we try to print - // this error message without any memory allocation. - const char msg[] = "(): Failed to allocate memory\n"; - write(STDERR_FILENO, func_name, strlen(func_name)); - write(STDERR_FILENO, msg, ARR_SIZE(msg)); - abort(); + report_allocation_failure(func_name, file, line); } return ptr; } /// @brief Wrapper of allocchk_(). -#define allocchk(ptr) allocchk_(__func__, ptr) +#define allocchk(ptr) allocchk_(__func__, __FILE__, __LINE__, ptr) /// @brief Wrapper of malloc(). #define cmalloc(type) ((type *) allocchk(malloc(sizeof(type))))