Actually finish memcache_add_talloc
authorVolker Lendecke <vl@samba.org>
Thu, 13 Nov 2008 22:50:19 +0000 (23:50 +0100)
committerVolker Lendecke <vl@samba.org>
Fri, 14 Nov 2008 19:07:29 +0000 (20:07 +0100)
This fixes a memleak found by Martin Zielinski <mz@seh.de>. Thanks for
looking closely!

Volker
(cherry picked from commit a31a84a078100819809e6d40dbc3df207a50a0b2)

source3/lib/memcache.c
source3/torture/torture.c

index d586f707fadd6bd7be2f3055200474c6fc01fb42..1951b4abf907288b1329437253b83fc377d3985a 100644 (file)
@@ -40,6 +40,24 @@ struct memcache {
 static void memcache_element_parse(struct memcache_element *e,
                                   DATA_BLOB *key, DATA_BLOB *value);
 
+static bool memcache_is_talloc(enum memcache_number n)
+{
+       bool result;
+
+       switch (n) {
+       case GETPWNAM_CACHE:
+       case PDB_GETPWSID_CACHE:
+       case SINGLETON_CACHE_TALLOC:
+               result = true;
+               break;
+       default:
+               result = false;
+               break;
+       }
+
+       return result;
+}
+
 static int memcache_destructor(struct memcache *cache) {
        struct memcache_element *e, *next;
 
@@ -188,6 +206,16 @@ static void memcache_delete_element(struct memcache *cache,
        }
        DLIST_REMOVE(cache->mru, e);
 
+       if (memcache_is_talloc(e->n)) {
+               DATA_BLOB cache_key, cache_value;
+               void *ptr;
+
+               memcache_element_parse(e, &cache_key, &cache_value);
+               SMB_ASSERT(cache_value.length == sizeof(ptr));
+               memcpy(&ptr, cache_value.data, sizeof(ptr));
+               TALLOC_FREE(ptr);
+       }
+
        cache->size -= memcache_element_size(e->keylength, e->valuelength);
 
        SAFE_FREE(e);
@@ -250,6 +278,12 @@ void memcache_add(struct memcache *cache, enum memcache_number n,
                memcache_element_parse(e, &cache_key, &cache_value);
 
                if (value.length <= cache_value.length) {
+                       if (memcache_is_talloc(e->n)) {
+                               void *ptr;
+                               SMB_ASSERT(cache_value.length == sizeof(ptr));
+                               memcpy(&ptr, cache_value.data, sizeof(ptr));
+                               TALLOC_FREE(ptr);
+                       }
                        /*
                         * We can reuse the existing record
                         */
@@ -308,7 +342,8 @@ void memcache_add(struct memcache *cache, enum memcache_number n,
 void memcache_add_talloc(struct memcache *cache, enum memcache_number n,
                         DATA_BLOB key, void *ptr)
 {
-       memcache_add(cache, n, key, data_blob_const(&ptr, sizeof(ptr)));
+       void *p = talloc_move(cache, &ptr);
+       memcache_add(cache, n, key, data_blob_const(&p, sizeof(p)));
 }
 
 void memcache_flush(struct memcache *cache, enum memcache_number n)
index 904fb5c26252c0af35de3cc99e0be72d58c799b1..762ea214d10ba777754053d3498c083c5122075e 100644 (file)
@@ -5291,6 +5291,11 @@ static bool run_local_memcache(int dummy)
        DATA_BLOB d1, d2, d3;
        DATA_BLOB v1, v2, v3;
 
+       TALLOC_CTX *mem_ctx;
+       char *str1, *str2;
+       size_t size1, size2;
+       bool ret = false;
+
        cache = memcache_init(NULL, 100);
 
        if (cache == NULL) {
@@ -5342,7 +5347,33 @@ static bool run_local_memcache(int dummy)
        }
 
        TALLOC_FREE(cache);
-       return true;
+
+       cache = memcache_init(NULL, 0);
+
+       mem_ctx = talloc_init("foo");
+
+       str1 = talloc_strdup(mem_ctx, "string1");
+       str2 = talloc_strdup(mem_ctx, "string2");
+
+       memcache_add_talloc(cache, SINGLETON_CACHE_TALLOC,
+                           data_blob_string_const("torture"), str1);
+       size1 = talloc_total_size(cache);
+
+       memcache_add_talloc(cache, SINGLETON_CACHE_TALLOC,
+                           data_blob_string_const("torture"), str2);
+       size2 = talloc_total_size(cache);
+
+       printf("size1=%d, size2=%d\n", (int)size1, (int)size2);
+
+       if (size2 > size1) {
+               printf("memcache leaks memory!\n");
+               goto fail;
+       }
+
+       ret = true;
+ fail:
+       TALLOC_FREE(cache);
+       return ret;
 }
 
 static double create_procs(bool (*fn)(int), bool *result)