diff --git a/src/hmemory.c b/src/hmemory.c index 391d748..2ccc551 100644 --- a/src/hmemory.c +++ b/src/hmemory.c @@ -97,6 +97,7 @@ static pthread_mutex_t hmemory_mutex = PTHREAD_MUTEX_INITIALIZER; static inline int hmemory_getenv_int (const char *name); static inline int debug_dump_callstack (const char *prefix); static inline int debug_memory_add (const char *name, void *address, size_t size, const char *command, const char *func, const char *file, const int line); +static inline int debug_memory_check (void *address, const char *command, const char *func, const char *file, const int line); static inline int debug_memory_del (void *address, const char *command, const char *func, const char *file, const int line); #else @@ -105,34 +106,42 @@ static inline int debug_memory_del (void *address, const char *command, const ch (void) func; \ (void) file; \ (void) line; -#define debug_memory_add(a...) (void) name; debug_memory_unused() +#define debug_memory_add(a...) (void) name; (void) command; debug_memory_unused() #define debug_memory_del(a...) debug_memory_unused() +#define debug_memory_check(a...) debug_memory_unused() #endif -void * HMEMORY_FUNCTION_NAME(memset_actual) (const char *func, const char *file, const int line, void *destination, int c, size_t len) +static unsigned int hmemory_signature = 0xdeadbeef; + +static inline void * malloc_actual (const char *command, const char *func, const char *file, const int line, const char *name, size_t size) { void *rc; - (void) func; - (void) file; - (void) line; - rc = memset(destination, c, len); - return rc; + size += sizeof(hmemory_signature) * 2; + rc = malloc(size); + if (rc == NULL) { + herrorf("malloc failed"); + return NULL; + } + debug_memory_add(name, rc, size, command, func, file, line); + debug_memory_check(rc, command, func, file, line); + return rc + sizeof(hmemory_signature); } -void * HMEMORY_FUNCTION_NAME(memcpy_actual) (const char *func, const char *file, const int line, void *destination, void *source, size_t len) +static inline void free_actual (const char *command, const char *func, const char *file, const int line, void *address) { - void *rc; - (void) func; - (void) file; - (void) line; - rc = memcpy(destination, source, len); - return rc; + void *addr; + (void) command; + addr = address - sizeof(hmemory_signature); + debug_memory_check(addr, command, func, file, line); + debug_memory_del(addr, command, func, file, line); + free(addr); } int HMEMORY_FUNCTION_NAME(asprintf_actual) (const char *func, const char *file, const int line, const char *name, char **strp, const char *fmt, ...) { int rc; + void *tmp; va_list ap; va_start(ap, fmt); rc = vasprintf(strp, fmt, ap); @@ -146,7 +155,10 @@ int HMEMORY_FUNCTION_NAME(asprintf_actual) (const char *func, const char *file, hassert((rc >= 0) && "asprintf failed"); #endif } else { - debug_memory_add(name, *strp, strlen(*strp) + 1, "asprintf", func, file, line); + tmp = malloc_actual("asprintf", func, file, line, name, strlen(*strp) + 1); + memcpy(tmp, *strp, strlen(*strp) + 1); + free(*strp); + *strp = tmp; } va_end(ap); return rc; @@ -155,6 +167,7 @@ int HMEMORY_FUNCTION_NAME(asprintf_actual) (const char *func, const char *file, int HMEMORY_FUNCTION_NAME(vasprintf_actual) (const char *func, const char *file, const int line, const char *name, char **strp, const char *fmt, va_list ap) { int rc; + void *tmp; rc = vasprintf(strp, fmt, ap); if (rc < 0) { #if defined(HMEMORY_DEBUG) && (HMEMORY_DEBUG == 1) @@ -166,7 +179,10 @@ int HMEMORY_FUNCTION_NAME(vasprintf_actual) (const char *func, const char *file, hassert((rc >= 0) && "vasprintf failed"); #endif } else { - debug_memory_add(name, *strp, strlen(*strp) + 1, "vasprintf", func, file, line); + tmp = malloc_actual("vasprintf", func, file, line, name, strlen(*strp) + 1); + memcpy(tmp, *strp, strlen(*strp) + 1); + free(*strp); + *strp = tmp; } return rc; } @@ -174,6 +190,7 @@ int HMEMORY_FUNCTION_NAME(vasprintf_actual) (const char *func, const char *file, char * HMEMORY_FUNCTION_NAME(strdup_actual) (const char *func, const char *file, const int line, const char *name, const char *string) { void *rc; + void *tmp; if (string == NULL) { #if defined(HMEMORY_DEBUG) && (HMEMORY_DEBUG == 1) hdebug_lock(); @@ -189,13 +206,16 @@ char * HMEMORY_FUNCTION_NAME(strdup_actual) (const char *func, const char *file, if (rc == NULL) { herrorf("strdup failed"); } - debug_memory_add(name, rc, strlen(rc) + 1, "strdup", func, file, line); - return rc; + tmp = malloc_actual("strdup", func, file, line, name, strlen(rc) + 1); + memcpy(tmp, rc, strlen(rc) + 1); + free(rc); + return tmp; } char * HMEMORY_FUNCTION_NAME(strndup_actual) (const char *func, const char *file, const int line, const char *name, const char *string, size_t size) { void *rc; + void *tmp; if (string == NULL) { #if defined(HMEMORY_DEBUG) && (HMEMORY_DEBUG == 1) hdebug_lock(); @@ -211,48 +231,69 @@ char * HMEMORY_FUNCTION_NAME(strndup_actual) (const char *func, const char *file if (rc == NULL) { herrorf("strndup failed"); } - debug_memory_add(name, rc, strlen(rc) + 1, "strndup", func, file, line); - return rc; + tmp = malloc_actual("strndup", func, file, line, name, strlen(rc) + 1); + memcpy(tmp, rc, strlen(rc) + 1); + free(rc); + return tmp; } void * HMEMORY_FUNCTION_NAME(malloc_actual) (const char *func, const char *file, const int line, const char *name, size_t size) { void *rc; - rc = malloc(size); + rc = malloc_actual("malloc", func, file, line, name, size); if (rc == NULL) { - herrorf("malloc failed"); + herrorf("malloc_actual failed"); + return NULL; } - debug_memory_add(name, rc, size, "malloc", func, file, line); return rc; } void * HMEMORY_FUNCTION_NAME(calloc_actual) (const char *func, const char *file, const int line, const char *name, size_t nmemb, size_t size) { void *rc; - rc = calloc(nmemb, size); + rc = malloc_actual("calloc", func, file, line, name, nmemb * size); if (rc == NULL) { - herrorf("calloc failed"); + herrorf("malloc actual failed"); + return NULL; + } + rc = memset(rc, 0, nmemb * size); + if (rc == NULL) { + herrorf("memset actual failed"); + return NULL; } - debug_memory_add(name, rc, nmemb * size, "calloc", func, file, line); return rc; } void * HMEMORY_FUNCTION_NAME(realloc_actual) (const char *func, const char *file, const int line, const char *name, void *address, size_t size) { void *rc; - rc = realloc(address, size); + void *tmp; + void *addr; + if (address == NULL) { + rc = malloc_actual("realloc", func, file, line, name, size); + if (rc == NULL) { + herrorf("malloc_actual failed"); + return NULL; + } + return rc; + } + addr = address - sizeof(hmemory_signature); + debug_memory_check(addr, "realloc", func, file, line); + rc = realloc(addr, size); if (rc == NULL) { herrorf("realloc failed"); + return NULL; } - debug_memory_del(address, "realloc", func, file, line); - debug_memory_add(name, rc, size, "realloc", func, file, line); - return rc; + debug_memory_del(addr, "realloc", func, file, line); + tmp = malloc_actual("realloc", func, file, line, name, size); + memcpy(tmp, rc, size); + free(rc); + return tmp; } void HMEMORY_FUNCTION_NAME(free_actual) (const char *func, const char *file, const int line, void *address) { - debug_memory_del(address, "free", func, file, line); - free(address); + free_actual("free", func, file, line, address); } #if defined(HMEMORY_DEBUG) && (HMEMORY_DEBUG == 1) @@ -468,6 +509,8 @@ static int debug_memory_add (const char *name, void *address, size_t size, const m->func = func; m->file = file; m->line = line; + memcpy(m->address, &hmemory_signature, sizeof(hmemory_signature)); + memcpy(m->address + m->size - sizeof(hmemory_signature), &hmemory_signature, sizeof(hmemory_signature)); HASH_ADD_PTR(debug_memory, address, m); hdebugf("%s added memory: %s, address: %p, size: %zd, func: %s, file: %s, line: %d", command, m->name, m->address, m->size, m->func, m->file, m->line); memory_total += size; @@ -477,6 +520,52 @@ static int debug_memory_add (const char *name, void *address, size_t size, const return 0; } +static int debug_memory_check (void *address, const char *command, const char *func, const char *file, const int line) +{ + int rcu; + int rco; + struct hmemory_memory *m; + if (address == NULL) { + return 0; + } + hmemory_lock(); + HASH_FIND_PTR(debug_memory, &address, m); + if (m != NULL) { + goto found_m; + } + hdebug_lock(); + hinfof("%s with invalid memory (%p)", command, address); + hinfof(" at: %s (%s:%d)", func, file, line); + debug_dump_callstack(" "); + hinfof(" "); + hinfof(" if it is certain that program is memory bug free, then hmemory"); + hinfof(" may have a serious bug that needs to be fixed urgent. please "); + hinfof(" inform author"); + hinfof(" at: alper.akcan@gmail.com"); + hdebug_unlock(); + hassert((m != NULL) && "invalid memory"); + hmemory_unlock(); + return -1; +found_m: + hdebug_lock(); + rcu = memcmp(m->address, &hmemory_signature, sizeof(hmemory_signature)); + if (rcu != 0) { + hinfof("%s with corrupted memory (%p), underflow", command, address); + hinfof(" at: %s (%s:%d)", func, file, line); + debug_dump_callstack(" "); + } + rco = memcmp(m->address + m->size - sizeof(hmemory_signature), &hmemory_signature, sizeof(hmemory_signature)); + if (rco != 0) { + hinfof("%s with corrupted memory (%p), overflow", command, address); + hinfof(" at: %s (%s:%d)", func, file, line); + debug_dump_callstack(" "); + } + hdebug_unlock(); + hassert(((rcu == 0) && (rco == 0)) && "memory corruption"); + hmemory_unlock(); + return 0; +} + static int debug_memory_del (void *address, const char *command, const char *func, const char *file, const int line) { struct hmemory_memory *m; diff --git a/src/hmemory.h b/src/hmemory.h index e2264d1..f3884bf 100644 --- a/src/hmemory.h +++ b/src/hmemory.h @@ -50,20 +50,6 @@ #define HMEMORY_DEBUG_NAME_MAX 256 -#undef memset -#define memset(b, c, len) ({ \ - void *__r; \ - __r = hmemory_memset(b, c, len); \ - __r; \ -}) - -#undef memcpy -#define memcpy(s1, s2, n) ({ \ - void *__r; \ - __r = hmemory_memcpy(s1, s2, n); \ - __r; \ -}) - #undef asprintf #define asprintf(strp, fmt...) ({ \ int __r; \ @@ -142,9 +128,6 @@ #endif -#define hmemory_memset(a, b, c) HMEMORY_FUNCTION_NAME(memset_actual)(__FUNCTION__, __FILE__, __LINE__, a, b, c) -#define hmemory_memcpy(a, b, c) HMEMORY_FUNCTION_NAME(memcpy_actual)(__FUNCTION__, __FILE__, __LINE__, a, b, c) - #define hmemory_asprintf(a, b...) HMEMORY_FUNCTION_NAME(asprintf_actual)(__FUNCTION__, __FILE__, __LINE__, a, b) #define hmemory_vasprintf(a, b, c) HMEMORY_FUNCTION_NAME(vasprintf_actual)(__FUNCTION__, __FILE__, __LINE__, a, b, c) diff --git a/test/Makefile b/test/Makefile index 56f6e80..6e1f011 100644 --- a/test/Makefile +++ b/test/Makefile @@ -33,6 +33,7 @@ define test-debug-defaults ../src/libhmemory.o $1_cflags-y = \ + -O1 \ -DHMEMORY_DEBUG=1 \ -include ../src/hmemory.h diff --git a/test/fail-00.c b/test/fail-00.c index 424f91e..b80faf4 100644 --- a/test/fail-00.c +++ b/test/fail-00.c @@ -14,9 +14,7 @@ int main (int argc, char *argv[]) { - int r; void *rc; - char *strp; (void) argc; (void) argv; rc = malloc(1024); @@ -24,47 +22,5 @@ int main (int argc, char *argv[]) fprintf(stderr, "malloc failed\n"); exit(-1); } - free(rc + 10); - rc = calloc(1, 1024); - if (rc == NULL) { - fprintf(stderr, "calloc failed\n"); - exit(-1); - } - free(rc + 10); - rc = realloc(NULL, 1024); - if (rc == NULL) { - fprintf(stderr, "realloc failed\n"); - exit(-1); - } - free(rc + 10); - rc = realloc(NULL, 1024); - if (rc == NULL) { - fprintf(stderr, "realloc failed\n"); - exit(-1); - } - rc = realloc(rc, 2048); - if (rc == NULL) { - fprintf(stderr, "realloc failed\n"); - exit(-1); - } - free(rc + 10); - rc = strdup(argv[0]); - if (rc == NULL) { - fprintf(stderr, "strdup failed\n"); - exit(-1); - } - free(rc + 10); - rc = strndup(argv[0], 1024); - if (rc == NULL) { - fprintf(stderr, "strndup failed\n"); - exit(-1); - } - free(rc + 10); - r = asprintf(&strp, "%s", argv[0]); - if (r < 0) { - fprintf(stderr, "asprintf failed\n"); - exit(-1); - } - free(strp + 10); return 0; } diff --git a/test/fail-01.c b/test/fail-01.c index 678cad7..3ed9497 100644 --- a/test/fail-01.c +++ b/test/fail-01.c @@ -17,17 +17,10 @@ int main (int argc, char *argv[]) void *rc; (void) argc; (void) argv; - rc = strdup(NULL); + rc = calloc(1, 1024); if (rc == NULL) { - fprintf(stderr, "strdup failed\n"); + fprintf(stderr, "calloc failed\n"); exit(-1); } - free(rc); - rc = strndup(NULL, 1024); - if (rc == NULL) { - fprintf(stderr, "strndup failed\n"); - exit(-1); - } - free(rc); return 0; } diff --git a/test/fail-02.c b/test/fail-02.c index cecc683..163c380 100644 --- a/test/fail-02.c +++ b/test/fail-02.c @@ -17,12 +17,10 @@ int main (int argc, char *argv[]) void *rc; (void) argc; (void) argv; - rc = malloc(1024); + rc = realloc(NULL, 1024); if (rc == NULL) { - fprintf(stderr, "malloc failed\n"); + fprintf(stderr, "realloc failed\n"); exit(-1); } - memset(rc + 10, 0, 1024); - free(rc + 10); return 0; } diff --git a/test/fail-03.c b/test/fail-03.c new file mode 100644 index 0000000..fa5d28e --- /dev/null +++ b/test/fail-03.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2008-2013 Alper Akcan + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://www.wtfpl.net/ for more details. + */ + +#include +#include +#include + +int main (int argc, char *argv[]) +{ + void *rc; + (void) argc; + (void) argv; + rc = realloc(NULL, 1024); + if (rc == NULL) { + fprintf(stderr, "realloc failed\n"); + exit(-1); + } + rc = realloc(rc, 2048); + if (rc == NULL) { + fprintf(stderr, "realloc failed\n"); + exit(-1); + } + return 0; +} diff --git a/test/fail-04.c b/test/fail-04.c new file mode 100644 index 0000000..3189aa3 --- /dev/null +++ b/test/fail-04.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2013 Alper Akcan + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://www.wtfpl.net/ for more details. + */ + +#include +#include +#include + +int main (int argc, char *argv[]) +{ + void *rc; + (void) argc; + (void) argv; + rc = strdup(argv[0]); + if (rc == NULL) { + fprintf(stderr, "strdup failed\n"); + exit(-1); + } + return 0; +} diff --git a/test/fail-05.c b/test/fail-05.c new file mode 100644 index 0000000..0a2207e --- /dev/null +++ b/test/fail-05.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008-2013 Alper Akcan + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://www.wtfpl.net/ for more details. + */ + +#include +#include +#include + +int main (int argc, char *argv[]) +{ + void *rc; + (void) argc; + (void) argv; + rc = strndup(argv[0], 1024); + if (rc == NULL) { + fprintf(stderr, "strndup failed\n"); + exit(-1); + } + return 0; +} diff --git a/test/fail-06.c b/test/fail-06.c new file mode 100644 index 0000000..0050660 --- /dev/null +++ b/test/fail-06.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2013 Alper Akcan + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://www.wtfpl.net/ for more details. + */ + +#include +#include +#include + +int main (int argc, char *argv[]) +{ + int r; + char *rc; + (void) argc; + (void) argv; + r = asprintf(&rc, "%s", argv[0]); + if (r < 0) { + fprintf(stderr, "asprintf failed\n"); + exit(-1); + } + return 0; +} diff --git a/test/success-00.c b/test/success-00.c index 59dbc07..c91cfb2 100644 --- a/test/success-00.c +++ b/test/success-00.c @@ -14,9 +14,7 @@ int main (int argc, char *argv[]) { - int r; void *rc; - char *strp; (void) argc; (void) argv; rc = malloc(1024); @@ -25,46 +23,5 @@ int main (int argc, char *argv[]) exit(-1); } free(rc); - rc = calloc(1, 1024); - if (rc == NULL) { - fprintf(stderr, "calloc failed\n"); - exit(-1); - } - free(rc); - rc = realloc(NULL, 1024); - if (rc == NULL) { - fprintf(stderr, "realloc failed\n"); - exit(-1); - } - free(rc); - rc = realloc(NULL, 1024); - if (rc == NULL) { - fprintf(stderr, "realloc failed\n"); - exit(-1); - } - rc = realloc(rc, 2048); - if (rc == NULL) { - fprintf(stderr, "realloc failed\n"); - exit(-1); - } - free(rc); - rc = strdup(argv[0]); - if (rc == NULL) { - fprintf(stderr, "strdup failed\n"); - exit(-1); - } - free(rc); - rc = strndup(argv[0], 1024); - if (rc == NULL) { - fprintf(stderr, "strndup failed\n"); - exit(-1); - } - free(rc); - r = asprintf(&strp, "%s", argv[0]); - if (r < 0) { - fprintf(stderr, "asprintf failed\n"); - exit(-1); - } - free(strp); return 0; } diff --git a/test/success-01.c b/test/success-01.c index 68decdb..090cc2b 100644 --- a/test/success-01.c +++ b/test/success-01.c @@ -17,15 +17,9 @@ int main (int argc, char *argv[]) void *rc; (void) argc; (void) argv; - rc = strdup(argv[0]); + rc = calloc(1, 1024); if (rc == NULL) { - fprintf(stderr, "strdup failed\n"); - exit(-1); - } - free(rc); - rc = strndup(argv[0], 1024); - if (rc == NULL) { - fprintf(stderr, "strndup failed\n"); + fprintf(stderr, "calloc failed\n"); exit(-1); } free(rc); diff --git a/test/success-02.c b/test/success-02.c index 09d38b6..3da14a5 100644 --- a/test/success-02.c +++ b/test/success-02.c @@ -17,12 +17,11 @@ int main (int argc, char *argv[]) void *rc; (void) argc; (void) argv; - rc = malloc(1024); + rc = realloc(NULL, 1024); if (rc == NULL) { - fprintf(stderr, "malloc failed\n"); + fprintf(stderr, "realloc failed\n"); exit(-1); } - memset(rc, 0, 1024); free(rc); return 0; } diff --git a/test/success-03.c b/test/success-03.c new file mode 100644 index 0000000..a382bf1 --- /dev/null +++ b/test/success-03.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2008-2013 Alper Akcan + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://www.wtfpl.net/ for more details. + */ + +#include +#include +#include + +int main (int argc, char *argv[]) +{ + void *rc; + (void) argc; + (void) argv; + rc = realloc(NULL, 1024); + if (rc == NULL) { + fprintf(stderr, "realloc failed\n"); + exit(-1); + } + rc = realloc(rc, 2048); + if (rc == NULL) { + fprintf(stderr, "realloc failed\n"); + exit(-1); + } + free(rc); + return 0; +} diff --git a/test/success-04.c b/test/success-04.c new file mode 100644 index 0000000..e8773b7 --- /dev/null +++ b/test/success-04.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2013 Alper Akcan + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://www.wtfpl.net/ for more details. + */ + +#include +#include +#include + +int main (int argc, char *argv[]) +{ + void *rc; + (void) argc; + (void) argv; + rc = strdup(argv[0]); + if (rc == NULL) { + fprintf(stderr, "strdup failed\n"); + exit(-1); + } + free(rc); + return 0; +} diff --git a/test/success-05.c b/test/success-05.c new file mode 100644 index 0000000..cefc11e --- /dev/null +++ b/test/success-05.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2008-2013 Alper Akcan + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://www.wtfpl.net/ for more details. + */ + +#include +#include +#include + +int main (int argc, char *argv[]) +{ + void *rc; + (void) argc; + (void) argv; + rc = strndup(argv[0], 1024); + if (rc == NULL) { + fprintf(stderr, "strndup failed\n"); + exit(-1); + } + free(rc); + return 0; +} diff --git a/test/success-06.c b/test/success-06.c new file mode 100644 index 0000000..8100c02 --- /dev/null +++ b/test/success-06.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008-2013 Alper Akcan + * + * This program is free software. It comes without any warranty, to + * the extent permitted by applicable law. You can redistribute it + * and/or modify it under the terms of the Do What The Fuck You Want + * To Public License, Version 2, as published by Sam Hocevar. See + * http://www.wtfpl.net/ for more details. + */ + +#include +#include +#include + +int main (int argc, char *argv[]) +{ + int r; + char *rc; + (void) argc; + (void) argv; + r = asprintf(&rc, "%s", argv[0]); + if (r < 0) { + fprintf(stderr, "asprintf failed\n"); + exit(-1); + } + free(rc); + return 0; +}