Add strdup probe. 69/96069/4
authorMaxim Ostapenko <m.ostapenko@samsung.com>
Mon, 7 Nov 2016 14:29:16 +0000 (17:29 +0300)
committerMaxim Ostapenko <m.ostapenko@samsung.com>
Wed, 9 Nov 2016 12:03:23 +0000 (15:03 +0300)
Currently SWAP doesn't intercept allocation functions coming from Glibc, thus
it misses strdup. However, strdup is one of the most favourite instruments for
introducing memory leaks (developers often forgot to free memory allocated by
strdup). Although the correct fix would be handling all allocations coming from
Glibc, this change is too intrusive now. Thus, just add strdup probe to be able
catch memory leaks, introduced by strdup.

Change-Id: Ibea87ee8b05533fc7230d0d9923c214e9bd0fe97
Signed-off-by: Maxim Ostapenko <m.ostapenko@samsung.com>
lsan/src/lsan_interceptors.cc
probe_memory/api_names.txt
probe_memory/libdamemalloc.c
probe_memory/memory_probes_list.h

index 1f2248b..899c6dc 100644 (file)
@@ -117,6 +117,23 @@ INTERCEPTOR(void *, pvalloc, uptr size) {
   return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
 }
 
+INTERCEPTOR(SIZE_T, strlen, const char *s) {
+  return REAL(strlen)(s);
+}
+
+INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) {
+  return REAL(memcpy)(dst, src, size);
+}
+
+INTERCEPTOR(char*, strdup, const char *s) {
+  ENSURE_LSAN_INITED;
+  GET_STACK_TRACE_MALLOC;
+  uptr length = REAL(strlen)(s);
+  void *new_mem = Allocate(stack, length + 1, 1, kAlwaysClearMemory);
+  REAL(memcpy)(new_mem, s, length + 1);
+  return reinterpret_cast<char*>(new_mem);
+}
+
 #define OPERATOR_NEW_BODY                                \
   ENSURE_LSAN_INITED;                                    \
   GET_STACK_TRACE_MALLOC;                                \
@@ -226,9 +243,15 @@ void InitializeInterceptors() {
   INTERCEPT_FUNCTION(free);
   INTERCEPT_FUNCTION(calloc);
   INTERCEPT_FUNCTION(realloc);
+  INTERCEPT_FUNCTION(strdup);
   INTERCEPT_FUNCTION(pthread_create);
   INTERCEPT_FUNCTION(pthread_join);
 
+  // Just to make REAL(strlen)(...) available.
+  INTERCEPT_FUNCTION(strlen);
+  // Just to make REAL(memcpy)(...) available.
+  INTERCEPT_FUNCTION(memcpy);
+
   if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
     Report("LeakSanitizer: failed to create thread key.\n");
     Die();
index 0b816b2..c44dc66 100644 (file)
@@ -36,6 +36,7 @@ free@*;             free;             4
 realloc@*;          realloc;          4
 calloc@*;           calloc;           4
 posix_memalign@*;   posix_memalign;   4
+strdup@*;           strdup;           4
 
 
 #filename libdamemalloc.c
@@ -46,4 +47,5 @@ free@*;             free;             1
 realloc@*;          realloc;          1
 calloc@*;           calloc;           1
 posix_memalign@*;   posix_memalign;   1
+strdup@*;           strdup;           1
 
index 0468e32..3b3ca52 100755 (executable)
@@ -54,7 +54,8 @@ enum mem_symid {
        MEM_CALLOC,
        MEM_REALLOC,
        MEM_FREE,
-       MEM_POSIX_MEMALIGN
+       MEM_POSIX_MEMALIGN,
+       MEM_STRDUP
 };
 
 /* TODO Split LSan */
@@ -63,7 +64,8 @@ static const char *const real_functions[] = {
        "calloc",
        "realloc",
        "free",
-       "posix_memalign"
+       "posix_memalign",
+       "strdup"
 };
 
 /* TODO Split LSan */
@@ -72,7 +74,8 @@ static const char *const lsan_interceptors[] = {
        "__interceptor_calloc",
        "__interceptor_realloc",
        "__interceptor_free",
-       "__interceptor_posix_memalign"
+       "__interceptor_posix_memalign",
+       "__interceptor_strdup"
 };
 
 
@@ -279,3 +282,39 @@ HANDLER_WRAPPERS(memory_feature, int, posix_memalign, void**, memptr,
 
        return iret;
 }
+
+HANDLER_WRAPPERS(memory_feature, char *, strdup, const char*, s)
+{
+       /* TODO Split LSan */
+       static char* (*lsan_strdupp)(const char *);
+       char* (*strdupp)(const char *);
+       DECLARE_VARIABLE_STANDARD;
+       char *pret;
+       int size = strlen(s);
+
+       if (lsan_init_succeeded && lsan_strdupp == NULL)
+               lsan_strdupp = lsan_get_sym(lsan_interceptors[MEM_STRDUP]);
+
+       /* If LSan is used - call LSan strdup instead of origin */
+       strdupp = lsan_init_succeeded ? lsan_strdupp : (void *)orig;
+
+       PRE_PROBEBLOCK();
+
+       pret = (*strdupp)(s);
+
+       if (pret == 0)
+               add_memory_hash(pret, size, MEMTYPE_ALLOC, CALL_TYPE);
+
+       POST_PACK_PROBEBLOCK_BEGIN();
+
+       PREPARE_LOCAL_BUF();
+       PACK_COMMON_BEGIN(MSG_PROBE_MEMORY, API_ID_strdup, "x",
+                         (int64_t)size);
+       PACK_COMMON_END('p', pret, newerrno, call_type, caller);
+       PACK_MEMORY(size, MEMORY_API_ALLOC, pret);
+       FLUSH_LOCAL_BUF();
+
+       POST_PACK_PROBEBLOCK_END();
+
+       return pret;
+}
index 586d94d..76ad4bb 100644 (file)
@@ -9,7 +9,8 @@
        X(PROBE_NAME(memset), "memset", GT_TARGET_PROBE) \
        X(PROBE_NAME(memcmp), "memcmp", GT_TARGET_PROBE) \
        X(PROBE_NAME(memcpy), "memcpy", GT_TARGET_PROBE) \
-       X(PROBE_NAME(posix_memalign), "posix_memalign", GT_ALWAYS_PROBE)
+       X(PROBE_NAME(posix_memalign), "posix_memalign", GT_ALWAYS_PROBE) \
+       X(PROBE_NAME(strdup), "strdup", GT_ALWAYS_PROBE)
 
 #define PROBES_LIST_MEMORY_ALWAYS \
        X(CONCAT(PROBE_NAME(malloc), _always), "malloc", GT_ALWAYS_PROBE) \
@@ -19,7 +20,8 @@
        X(CONCAT(PROBE_NAME(memset), _always), "memset", GT_ALWAYS_PROBE) \
        X(CONCAT(PROBE_NAME(memcmp), _always), "memcmp", GT_ALWAYS_PROBE) \
        X(CONCAT(PROBE_NAME(memcpy), _always), "memcpy", GT_ALWAYS_PROBE) \
-       X(CONCAT(PROBE_NAME(posix_memalign), _always), "posix_memalign", GT_ALWAYS_PROBE)
+       X(CONCAT(PROBE_NAME(posix_memalign), _always), "posix_memalign", GT_ALWAYS_PROBE) \
+       X(CONCAT(PROBE_NAME(strdup), _always), "strdup", GT_ALWAYS_PROBE)
 
 #define PROBES_LIST \
        PROBES_LIST_MEMORY