lsquic icon indicating copy to clipboard operation
lsquic copied to clipboard

Is this a memory leak?

Open lishaobingdong opened this issue 3 years ago • 1 comments

Hello, I noticed that ASan reported a memory leak, but I'm not quite sure if it was caused by my client server, or caused by lsquic. In get_or_generate_state in lsquic_tokgen.c:198, data and key_copy are not freed before the function returns, so I think it may cause a memory leak. Screenshot from 2022-05-20 09-57-05

lishaobingdong avatar May 20 '22 01:05 lishaobingdong

Yes, it is a memory leak, you can try the following patch

diff --git a/src/liblsquic/lsquic_stock_shi.c b/src/liblsquic/lsquic_stock_shi.c
index b6807cf8..61f36140 100644
--- a/src/liblsquic/lsquic_stock_shi.c
+++ b/src/liblsquic/lsquic_stock_shi.c
@@ -42,8 +42,6 @@ struct hash_elem
 static void
 free_key_data (struct hash_elem *he)
 {
-    if (he->data_sz)
-        free(he->data);
     free(he->key.buf);
 }
 
@@ -86,9 +84,17 @@ stock_shi_insert (void *hash_ctx, void *key, unsigned key_sz,
     he = lsquic_malo_get(hash->malo);
     if (!he)
         return -1;
-    he->key.buf = key;
+    he->key.buf = malloc(key_sz + data_sz + 1);
+    if (!he->key.buf)
+    {
+        lsquic_malo_put(he);
+        return -1;
+    }
+    memmove(he->key.buf, key, key_sz);
+    ((char *)(he->key.buf))[key_sz] = 0;
     he->key.sz  = key_sz;
-    he->data    = data;
+    he->data    = he->key.buf + he->key.sz + 1;
+    memmove(he->data, data, data_sz);
     he->data_sz = data_sz;
     he->expiry = expiry;
     memset(&he->lhash_elem, 0, sizeof(he->lhash_elem));
diff --git a/src/liblsquic/lsquic_tokgen.c b/src/liblsquic/lsquic_tokgen.c
index 93a12df8..81ca5a4d 100644
--- a/src/liblsquic/lsquic_tokgen.c
+++ b/src/liblsquic/lsquic_tokgen.c
@@ -151,7 +151,8 @@ get_or_generate_state (struct lsquic_engine_public *enpub, time_t now,
 {
     const struct lsquic_shared_hash_if *const shi = enpub->enp_shi;
     void *const ctx = enpub->enp_shi_ctx;
-    void *data, *copy, *key_copy;
+    void *data, *copy;
+    char key_copy[TOKGEN_SHM_KEY_SIZE];
     int s;
     unsigned sz;
     size_t bufsz;
@@ -236,28 +237,13 @@ get_or_generate_state (struct lsquic_engine_public *enpub, time_t now,
     memcpy(shm_state->tgss_magic_bottom, TOKGEN_SHM_MAGIC_BOTTOM,
                                         sizeof(TOKGEN_SHM_MAGIC_BOTTOM) - 1);
 
-    data = malloc(sizeof(*shm_state));
-    if (!data)
-    {
-        LSQ_ERROR("%s: malloc", __func__);
-        return -1;
-    }
-    memcpy(data, shm_state, sizeof(*shm_state));
-    key_copy = malloc(TOKGEN_SHM_KEY_SIZE);
-    if (!key_copy)
-    {
-        LSQ_ERROR("%s: malloc", __func__);
-        free(data);
-        return -1;
-    }
+    data = shm_state;
     memcpy(key_copy, TOKGEN_SHM_KEY, TOKGEN_SHM_KEY_SIZE);
     s = shi->shi_insert(ctx, key_copy, TOKGEN_SHM_KEY_SIZE, data,
                                                     sizeof(*shm_state), 0);
     if (s != 0)
     {
         LSQ_ERROR("cannot insert into SHM");
-        free(data);
-        free(key_copy);
         return -1;
     }
     sz = sizeof(*shm_state);
diff --git a/tests/test_shi.c b/tests/test_shi.c
index 8e6b9109..4c6f73f5 100644
--- a/tests/test_shi.c
+++ b/tests/test_shi.c
@@ -23,30 +23,6 @@ static const struct pair {
 };
 
 
-struct data {
-    size_t   size;      /* Overall size including the payload */
-    char    *key;
-    char    *value;
-    char     data[0];   /* key followed by value */
-};
-
-
-static struct data *
-new_data (const char *key, const char *value)
-{
-    size_t klen = strlen(key);
-    size_t vlen = strlen(value);
-    size_t size = klen + vlen + 2 + sizeof(struct data);
-    struct data *data = malloc(size);
-    data->size = size;
-    data->key = data->data;
-    data->value = data->data + klen + 1;
-    memcpy(data->data, key, klen);
-    data->key[klen] = '\0';
-    memcpy(data->value, value, vlen);
-    data->value[vlen] = '\0';
-    return data;
-}
 
 
 #define N_PAIRS (sizeof(pairs) / sizeof(pairs[0]))
@@ -72,7 +48,6 @@ test_shi (const struct order *order)
     const time_t now = time(NULL);
     time_t expiry;
     void *datap;
-    struct data *data;
 
     hash = lsquic_stock_shared_hash_new();
 
@@ -83,9 +58,8 @@ test_shi (const struct order *order)
             expiry = now + 1;
         else
             expiry = 0;
-        data = new_data(pair->key, pair->value);
-        s = stock_shi.shi_insert(hash, strdup(data->key), strlen(data->key),
-                            data, data->size, expiry);
+        s = stock_shi.shi_insert(hash, (char *)pair->key, strlen(pair->key),
+                            (char *)pair->value, strlen(pair->value), expiry);
         assert(0 == s);
     }
 
@@ -106,11 +80,9 @@ test_shi (const struct order *order)
         }
         else
         {
-            data = datap;
             assert(1 == s);
-            assert(data_sz == data->size);
-            assert(0 == strcmp(pair->key, data->key));
-            assert(0 == strcmp(pair->value, data->value));
+            assert(data_sz == strlen(pair->value));
+            assert(0 == strncmp(pair->value, datap, data_sz));
         }
     }
 

litespeedtech avatar Jun 29 '22 02:06 litespeedtech

It is in release v3.1.2 already, assume it has been fixed.

litespeedtech avatar Aug 19 '22 19:08 litespeedtech