memcache: Properly track the size of talloc objects
authorChristof Schmitt <cs@samba.org>
Mon, 1 Apr 2019 23:23:35 +0000 (16:23 -0700)
committerJeremy Allison <jra@samba.org>
Sat, 6 Apr 2019 05:12:21 +0000 (05:12 +0000)
With memcache_add_talloc, the talloc object becomes part of the pool and
the memcache_element stores a pointer to the talloc object. The
size of the the talloc object was not used when tracking the used space,
allowing the cache to grow larger than defined in the memcache_init
call.

Fix this by adding the size of the talloc object to the used space.

Also record the initial size of the talloc object for proper adjustment
of the used space in the cache later. This is in case the size of the
talloc object is modified while being owned by the cache (e.g.
allocating talloc child objects). This should never happen, but better
be safe than ending up with a broken cache usage counter.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13865

Signed-off-by: Christof Schmitt <cs@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
lib/util/memcache.c

index d0250c6b3eea1ac7222132231e0de4f7181f2553..1e616bd0e9a9cc7eb5f0618338adcb22be5c6be2 100644 (file)
@@ -29,6 +29,7 @@ static struct memcache *global_cache;
 
 struct memcache_talloc_value {
        void *ptr;
+       size_t len;
 };
 
 struct memcache_element {
@@ -213,6 +214,7 @@ static void memcache_delete_element(struct memcache *cache,
                memcache_element_parse(e, &cache_key, &cache_value);
                SMB_ASSERT(cache_value.length == sizeof(mtv));
                memcpy(&mtv, cache_value.data, sizeof(mtv));
+               cache->size -= mtv.len;
                TALLOC_FREE(mtv.ptr);
        }
 
@@ -283,6 +285,7 @@ void memcache_add(struct memcache *cache, enum memcache_number n,
 
                                SMB_ASSERT(cache_value.length == sizeof(mtv));
                                memcpy(&mtv, cache_value.data, sizeof(mtv));
+                               cache->size -= mtv.len;
                                TALLOC_FREE(mtv.ptr);
                        }
                        /*
@@ -290,6 +293,14 @@ void memcache_add(struct memcache *cache, enum memcache_number n,
                         */
                        memcpy(cache_value.data, value.data, value.length);
                        e->valuelength = value.length;
+
+                       if (memcache_is_talloc(e->n)) {
+                               struct memcache_talloc_value mtv;
+
+                               SMB_ASSERT(cache_value.length == sizeof(mtv));
+                               memcpy(&mtv, cache_value.data, sizeof(mtv));
+                               cache->size += mtv.len;
+                       }
                        return;
                }
 
@@ -333,6 +344,13 @@ void memcache_add(struct memcache *cache, enum memcache_number n,
        DLIST_ADD(cache->mru, e);
 
        cache->size += element_size;
+       if (memcache_is_talloc(e->n)) {
+               struct memcache_talloc_value mtv;
+
+               SMB_ASSERT(cache_value.length == sizeof(mtv));
+               memcpy(&mtv, cache_value.data, sizeof(mtv));
+               cache->size += mtv.len;
+       }
        memcache_trim(cache);
 }
 
@@ -349,6 +367,7 @@ void memcache_add_talloc(struct memcache *cache, enum memcache_number n,
                return;
        }
 
+       mtv.len = talloc_total_size(*ptr);
        mtv.ptr = talloc_move(cache, ptr);
        memcache_add(cache, n, key, data_blob_const(&mtv, sizeof(mtv)));
 }