aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRatakor <ratakor@disroot.org>2023-06-25 23:41:12 +0200
committerRatakor <ratakor@disroot.org>2023-06-25 23:41:12 +0200
commit2c9f28013122ee242a56a188dbf339fb6f8cf3ff (patch)
treea39e4e44d1c243d2d5a90bb1aa7c9c2c320cc2df
parent62ac361d518a8a07238d1531858693c9157006b9 (diff)
Add ignore and comment, refactor realloc
Add dalloc_ignore() to ignore a pointer in memory leak check, it can be useful for a daemon because the program never stop. Add dalloc_comment() to add small comment to pointers so it's easier to figure out what they are from dalloc error message. Remove function attributes but keep destructor for dalloc_check_all(). Internal: Add find_pointer_index() to search for a pointer in pointers, it search from the last to the first pointer added. Change __realloc() to use realloc() instead of __free() and __malloc(), this is needed to keep comment and ignored field easily, also it should be more efficient.
-rw-r--r--README.md15
-rw-r--r--dalloc.c125
-rw-r--r--dalloc.h23
3 files changed, 127 insertions, 36 deletions
diff --git a/README.md b/README.md
index 568f477..7c45cd3 100644
--- a/README.md
+++ b/README.md
@@ -30,3 +30,18 @@ Run both dalloc_check_free() and dalloc_check_overflow() on program exit.
#### dalloc_sighandler(int sig)
Output signal meaning and exit. To be used with signal() from signal.h.
e.g.: `signal(SIG, dalloc_sighandler);` Require `_DEFAULT_SOURCE` or equivalent.
+
+#### dalloc_ignore(void *p)
+Ignore the pointer in argument for memory leak check. This can be useful when
+developing an application that never stop.
+When `DALLOC` is not defined this function does nothing.
+
+#### dalloc_comment(void *p, char *comment)
+Add a comment to a pointer so it is more easy to know what the pointer stands
+for just by looking at the error message from dalloc.
+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.
diff --git a/dalloc.c b/dalloc.c
index daa41eb..77c37ca 100644
--- a/dalloc.c
+++ b/dalloc.c
@@ -29,11 +29,11 @@ void dalloc_check_all(void) __attribute__((destructor));
#endif /* DALLOC */
#include "dalloc.h"
-#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#define OVER_ALLOC 64
#define MAGIC_NUMBER 0x99
#define EXIT_STATUS 9
#define MAX_POINTERS 1024
+#define COMMENT_MAX 128
#ifndef PATH_MAX
#define PATH_MAX 256
#endif /* PATH_MAX */
@@ -41,11 +41,14 @@ void dalloc_check_all(void) __attribute__((destructor));
struct Pointer {
void *p;
size_t siz;
+ char comment[COMMENT_MAX];
+ int ignored;
char file[PATH_MAX];
int line;
};
static int overflow(unsigned char *p, size_t siz);
+static size_t find_pointer_index(void *p, char *file, int line);
static pthread_mutex_t dalloc_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct Pointer pointers[MAX_POINTERS];
@@ -61,6 +64,23 @@ overflow(unsigned char *p, size_t siz)
return i < OVER_ALLOC;
}
+static size_t
+find_pointer_index(void *p, char *file, int line)
+{
+ ssize_t i = npointers;
+
+ while (i-- > 0 && p != pointers[i].p);
+
+ if (i == -1) {
+ fprintf(stderr, "%s:%d: dalloc: Unknown pointer %p\n",
+ file, line, p);
+ pthread_mutex_unlock(&dalloc_mutex);
+ exit(EXIT_STATUS);
+ }
+
+ return i;
+}
+
size_t
dalloc_check_overflow(void)
{
@@ -81,6 +101,8 @@ dalloc_check_overflow(void)
fprintf(stderr, "\n%s:%d: %p, total: %zu bytes",
pointers[i].file, pointers[i].line,
pointers[i].p, pointers[i].siz);
+ if (pointers[i].comment[0] != 0)
+ fprintf(stderr, " /* %s */", pointers[i].comment);
}
pthread_mutex_unlock(&dalloc_mutex);
@@ -105,10 +127,15 @@ dalloc_check_free(void)
pthread_mutex_lock(&dalloc_mutex);
fprintf(stderr, "Memory allocated and not freed:");
for (i = 0; i < npointers; i++) {
+ if (pointers[i].ignored)
+ continue;
+
sum += pointers[i].siz;
fprintf(stderr, "\n%s:%d: %p, %zu bytes",
pointers[i].file, pointers[i].line,
pointers[i].p, pointers[i].siz);
+ if (pointers[i].comment[0] != 0)
+ fprintf(stderr, " /* %s */", pointers[i].comment);
}
pthread_mutex_unlock(&dalloc_mutex);
@@ -138,27 +165,55 @@ dalloc_sighandler(int sig)
}
void
+__dalloc_ignore(void *p, char *file, int line)
+{
+ size_t i;
+
+#ifdef NO_DALLOC
+ return;
+#endif /* NO_DALLOC */
+
+ pthread_mutex_lock(&dalloc_mutex);
+ i = find_pointer_index(p, file, line);
+ pointers[i].ignored = 1;
+ pthread_mutex_unlock(&dalloc_mutex);
+}
+
+void
+__dalloc_comment(void *p, char *comment, char *file, int line)
+{
+ size_t i, j;
+
+#ifdef NO_DALLOC
+ return;
+#endif /* NO_DALLOC */
+
+ pthread_mutex_lock(&dalloc_mutex);
+ i = find_pointer_index(p, file, line);
+ for (j = 0; j < COMMENT_MAX && comment[j] != '\0'; j++)
+ pointers[i].comment[j] = comment[j];
+ pointers[i].comment[j] = '\0';
+ pthread_mutex_unlock(&dalloc_mutex);
+}
+
+void
__free(void *p, char *file, int line)
{
- size_t i = 0;
+ size_t i;
if (p == NULL)
return;
pthread_mutex_lock(&dalloc_mutex);
- while (p != pointers[i].p && ++i < npointers);
- if (i == npointers) {
- fprintf(stderr, "%s:%d: dalloc: Double free\n", file, line);
- pthread_mutex_unlock(&dalloc_mutex);
- exit(EXIT_STATUS);
- }
-
+ i = find_pointer_index(p, file, line);
if (overflow(pointers[i].p, pointers[i].siz)) {
fprintf(stderr, "%s:%d: dalloc: "
"Memory overflow on %p, total: %zu bytes\n",
file, line, pointers[i].p, pointers[i].siz);
- fprintf(stderr,
- "The pointer was allocated in '%s' on line %d\n",
+ fprintf(stderr, "The pointer ");
+ if (pointers[i].comment[0] != 0)
+ fprintf(stderr, "'%s' ", pointers[i].comment);
+ fprintf(stderr, "was allocated in '%s' on line %d.\n",
pointers[i].file, pointers[i].line);
pthread_mutex_unlock(&dalloc_mutex);
exit(EXIT_STATUS);
@@ -236,9 +291,7 @@ __calloc(size_t nmemb, size_t siz, char *file, int line)
void *
__realloc(void *p, size_t siz, char *file, int line)
{
-
- void *np;
- size_t i = 0, osiz;
+ size_t i, j;
if (p == NULL)
return __malloc(siz, file, line);
@@ -249,21 +302,45 @@ __realloc(void *p, size_t siz, char *file, int line)
}
pthread_mutex_lock(&dalloc_mutex);
- while (p != pointers[i].p && ++i < npointers);
- if (i == npointers) {
- fprintf(stderr, "%s:%d: dalloc: realloc: Unknown pointer %p\n",
- file, line, p);
+ i = find_pointer_index(p, file, line);
+
+ if (overflow(pointers[i].p, pointers[i].siz)) {
+ fprintf(stderr, "%s:%d: dalloc: "
+ "Memory overflow on %p, total: %zu bytes\n",
+ file, line, pointers[i].p, pointers[i].siz);
+ fprintf(stderr, "The pointer ");
+ if (pointers[i].comment[0] != 0)
+ fprintf(stderr, "'%s' ", pointers[i].comment);
+ fprintf(stderr, "was allocated in '%s' on line %d.\n",
+ pointers[i].file, pointers[i].line);
pthread_mutex_unlock(&dalloc_mutex);
exit(EXIT_STATUS);
}
- osiz = pointers[i].siz;
- pthread_mutex_unlock(&dalloc_mutex);
- np = __malloc(siz, file, line);
- memcpy(np, p, MIN(osiz, siz));
- __free(p, file, line);
+ if (siz + OVER_ALLOC < OVER_ALLOC) {
+ p = NULL;
+ errno = ENOMEM;
+ } else {
+ p = realloc(p, siz + OVER_ALLOC);
+ }
- return np;
+ if (p == NULL) {
+ fprintf(stderr, "%s:%d: dalloc: %s\n",
+ file, line, strerror(errno));
+ pthread_mutex_unlock(&dalloc_mutex);
+ exit(EXIT_STATUS);
+ }
+
+ memset((unsigned char *)p + siz, MAGIC_NUMBER, OVER_ALLOC);
+ pointers[i].p = p;
+ pointers[i].siz = siz;
+ for (j = 0; j < PATH_MAX - 1 && file[j] != '\0'; j++)
+ pointers[i].file[j] = file[j];
+ pointers[i].file[j] = '\0';
+ pointers[i].line = line;
+ pthread_mutex_unlock(&dalloc_mutex);
+
+ return p;
}
void *
diff --git a/dalloc.h b/dalloc.h
index 6725e10..3d38172 100644
--- a/dalloc.h
+++ b/dalloc.h
@@ -29,24 +29,23 @@ extern "C" {
#define exit(dummy) (exitsegv(dummy))
#endif /* EXITSEGV */
+#define dalloc_ignore(p) (__dalloc_ignore(p, __FILE__, __LINE__))
+#define dalloc_comment(p, com) (__dalloc_comment(p, com, __FILE__, __LINE__))
+
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, char *comment, char *file, int line);
void __free(void *p, char *file, int line);
-void *__malloc(size_t siz, char *file, int line)
- __attribute_warn_unused_result__;
-void *__calloc(size_t nmemb, size_t siz, char *file, int line)
- __attribute_warn_unused_result__;
-void *__realloc(void *p, size_t siz, char *file, int line)
- __attribute_warn_unused_result__;
-void *__reallocarray(void *p, size_t nmemb, size_t siz, char *file, int line)
- __attribute_warn_unused_result__;
-char *__strdup(const char *s, char *file, int line)
- __attribute_warn_unused_result__ __nonnull ((1));
-char *__strndup(const char *s, size_t n, char *file, int line)
- __attribute_warn_unused_result__ __nonnull ((1));
+void *__malloc(size_t siz, char *file, int line);
+void *__calloc(size_t nmemb, size_t siz, char *file, int line);
+void *__realloc(void *p, size_t siz, char *file, int line);
+void *__reallocarray(void *p, size_t nmemb, size_t siz, char *file, int line);
+char *__strdup(const char *s, char *file, int line);
+char *__strndup(const char *s, size_t n, char *file, int line);
void exitsegv(int dummy);