diff options
author | Ratakor <ratakor@disroot.org> | 2023-07-17 00:03:12 +0200 |
---|---|---|
committer | Ratakor <ratakor@disroot.org> | 2023-07-17 00:03:12 +0200 |
commit | 677a197027a04e8703613971fefc90606d3b12e6 (patch) | |
tree | 495fb945e65008751c97ea6259b744adc7c7b618 | |
parent | 3984c2e6fdea72a5f04ec7c57e4c59dbaf6638ca (diff) |
Add asprintf and improve header
Also added vasprintf and warnings for alloc with siz == 0.
-rw-r--r-- | README.md | 16 | ||||
-rw-r--r-- | dalloc.c | 76 | ||||
-rw-r--r-- | dalloc.h | 35 |
3 files changed, 83 insertions, 44 deletions
@@ -1,20 +1,22 @@ dalloc ====== -A simple, thread safe, drop-in memory allocation debugging lib for C89+ +A simple, thread safe, drop-in memory allocation debugging lib for C Usage ----- dalloc.c and dalloc.h should be dropped into an existing project and compiled with the `-DDALLOC` flag to define the macro that enables dalloc. dalloc will replace free(), malloc(), calloc(), realloc(), reallocarray(), -strdup(), and strndup() by a more secure version that will check for buffer -overflow and memory leak. It will also output a recap at the end of the program. +strdup(), strndup(), vasprintf() and asprintf() by a more secure version that +will check for buffer overflow and memory leak. It will also output a recap at +the end of the program. By defining `EXITSEGV` all exit() call will be replaced by a segmentation fault which can be very useful to check where an overflow occur with a real debugger. -strdup, strndup and reallocarray are not standard so you'll probably need to -define `_DEFAULT_SOURCE` or equivalent to use them outside of dalloc. +strdup, strndup, reallocarray, vasprintf and asprintf are not standard so you +will probably need to define `_DEFAULT_SOURCE` or equivalent to use them +outside of dalloc. Functions --------- @@ -43,5 +45,5 @@ When `DALLOC` is not defined this function does nothing. Notes ----- -An error with "Unknown pointer" is either caused by a double free or when -freeing a pointer allocated with a function not supported by dalloc. +An error with "Unknown pointer" can be caused by a double free or when freeing +a pointer allocated with a function not supported by dalloc. @@ -16,16 +16,17 @@ #include <errno.h> #include <pthread.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#define DALLOC_INTERNAL +#include "dalloc.h" + #define EXIT_STATUS 9 #ifdef DALLOC -#undef DALLOC -#include "dalloc.h" - #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) #define OVER_ALLOC 64 #define MAGIC_NUMBER 0x99 @@ -201,8 +202,11 @@ _dalloc_malloc(size_t siz, char *file, int line) void *p = NULL; size_t sizfname; - if (siz == 0) + if (siz == 0) { + fprintf(stderr, "%s:%d: dalloc: malloc with size == 0\n", + file, line); return NULL; + } if (npointers == MAX_POINTERS) { fprintf(stderr, "dalloc: Too much pointers (max:%d)\n", @@ -240,8 +244,11 @@ _dalloc_calloc(size_t nmemb, size_t siz, char *file, int line) { void *p; - if (nmemb == 0 || siz == 0) + if (nmemb == 0 || siz == 0) { + fprintf(stderr, "%s:%d: dalloc: calloc with size == 0\n", + file, line); return NULL; + } if (nmemb > -1 / siz) { fprintf(stderr, "%s:%d: dalloc: calloc: %s\n", @@ -314,7 +321,13 @@ _dalloc_realloc(void *p, size_t siz, char *file, int line) void * _dalloc_reallocarray(void *p, size_t n, size_t s, char *file, int line) { - if (s != 0 && n > -1 / s) { + if (n == 0 || s == 0) { + fprintf(stderr, "%s:%d: dalloc: reallocarray with size == 0\n", + file, line); + return NULL; + } + + if (n > -1 / s) { fprintf(stderr, "%s:%d: dalloc: reallocarray: %s\n", file, line, strerror(ENOMEM)); exit(EXIT_STATUS); @@ -352,31 +365,44 @@ _dalloc_strndup(const char *s, size_t n, char *file, int line) return p; } -#else - -#include "dalloc.h" +int +_dalloc_vasprintf(char **p, const char *fmt, va_list ap, char *file, int line) +{ + va_list ap2; + size_t siz; + int rv; -#define NO_DALLOC "dalloc: Define `DALLOC` to enable dalloc" + va_copy(ap2, ap); + rv = vsnprintf(NULL, 0, fmt, ap2); + va_end(ap2); + if (rv < 0) { + fprintf(stderr, "%s:%d: dalloc: asprintf: %s\n", + file, line, strerror(errno)); + exit(EXIT_STATUS); + } + siz = rv + 1; + *p = _dalloc_malloc(siz, file, line); + rv = vsnprintf(*p, siz, fmt, ap); + if (rv < 0) { + fprintf(stderr, "%s:%d: dalloc: asprintf: %s\n", + file, line, strerror(errno)); + exit(EXIT_STATUS); + } -size_t -dalloc_check_overflow(void) -{ - fprintf(stderr, "%s\n", NO_DALLOC); - return 0; + return rv; } -void -dalloc_check_free(void) +int +_dalloc_asprintf(char **p, char *file, int line, const char *fmt, ...) { - fprintf(stderr, "%s\n", NO_DALLOC); - return; -} + int rv; + va_list ap; -void -dalloc_check_all(void) -{ - fprintf(stderr, "%s\n", NO_DALLOC); - return; + va_start(ap, fmt); + rv = _dalloc_vasprintf(p, fmt, ap, file, line); + va_end(ap); + + return rv; } #endif /* DALLOC */ @@ -8,6 +8,7 @@ #ifndef DALLOC_H #define DALLOC_H +#include <stdarg.h> #include <stdlib.h> #include <string.h> @@ -15,30 +16,25 @@ extern "C" { #endif /* __cplusplus */ -#ifdef DALLOC +#if defined(DALLOC) && !defined(DALLOC_INTERNAL) #define free(p) (_dalloc_free(p, __FILE__, __LINE__)) #define malloc(siz) (_dalloc_malloc(siz, __FILE__, __LINE__)) #define calloc(nmemb, siz) (_dalloc_calloc(nmemb, siz, __FILE__, __LINE__)) #define realloc(p, siz) (_dalloc_realloc(p, siz, __FILE__, __LINE__)) #define reallocarray(p, n, s) (_dalloc_reallocarray(p, n, s, __FILE__, __LINE__)) #define strdup(s) (_dalloc_strdup(s, __FILE__, __LINE__)) -#define strndup(s, n) (_dallloc_strndup(s, n, __FILE__, __LINE__)) +#define strndup(s, n) (_dalloc_strndup(s, n, __FILE__, __LINE__)) +#define vasprintf(p, fmt, ap) (_dalloc_vasprintf(p, fmt, ap, __FILE__, __LINE__)) +#define asprintf(p, fmt, ...) (_dalloc_asprintf(p, __FILE__, __LINE__, fmt, __VA_ARGS__)) #define dalloc_ignore(p) (_dalloc_ignore(p, __FILE__, __LINE__)) -#define dalloc_comment(p, com) (_dalloc_comment(p, com, __FILE__, __LINE__)) -#else -#define dalloc_ignore(p) -#define dalloc_comment(p, comment) -#endif /* DALLOC */ - -#ifdef EXITSEGV -#define exit(dummy) (exitsegv(dummy)) -#endif /* EXITSEGV */ +#define dalloc_comment(p, str) (_dalloc_comment(p, str, __FILE__, __LINE__)) +#endif /* DALLOC && !DALLOC_INTERNAL */ +#ifdef DALLOC size_t dalloc_check_overflow(void); void dalloc_check_free(void); void dalloc_check_all(void); -void dalloc_sighandler(int sig); void _dalloc_ignore(void *p, char *file, int line); void _dalloc_comment(void *p, const char *comment, char *file, int line); @@ -49,7 +45,22 @@ void *_dalloc_realloc(void *p, size_t siz, char *file, int line); void *_dalloc_reallocarray(void *p, size_t n, size_t s, char *file, int line); char *_dalloc_strdup(const char *s, char *file, int line); char *_dalloc_strndup(const char *s, size_t n, char *file, int line); +int _dalloc_vasprintf(char **p, const char *fmt, va_list ap, char *file, int line); +int _dalloc_asprintf(char **p, char *file, int line, const char *fmt, ...); +#else +#define _NO_DALLOC "dalloc: Define `DALLOC` to enable dalloc" +#define dalloc_ignore(p) +#define dalloc_comment(p, str) +#define dalloc_check_overflow() (fprintf(stderr, "%s\n", _NO_DALLOC), 0) +#define dalloc_check_free() (fprintf(stderr, "%s\n", _NO_DALLOC)) +#define dalloc_check_all() (fprintf(stderr, "%s\n", _NO_DALLOC)) +#endif /* DALLOC */ +#ifdef EXITSEGV +#define exit(dummy) (exitsegv(dummy)) +#endif /* EXITSEGV */ + +void dalloc_sighandler(int sig); void exitsegv(int dummy); #ifdef __cplusplus |