vppinfra: fix pool free bitmap allocation 70/37270/3
authorVladislav Grishenko <themiron@yandex-team.ru>
Wed, 28 Sep 2022 08:37:02 +0000 (13:37 +0500)
committerDave Barach <vpp@barachs.net>
Sun, 19 Mar 2023 12:17:23 +0000 (12:17 +0000)
Using clib_bitmap_vec_validate makes free bitmap vector
to be x64 times bigger (assuming x86_64) than necessary
when non-zero and possible oom due (u32)(0 - 1) math with
zero alloc.
Fix it with clib_bitmap_validate which takes bit size, not
index and ensure at least one bit is allocated.

Type: fix
Change-Id: I7e191f4e2fb3722a06bb800e1d075f7c7e2dcec9
Signed-off-by: Vladislav Grishenko <themiron@yandex-team.ru>
src/vppinfra/CMakeLists.txt
src/vppinfra/pool.h
src/vppinfra/test_pool_alloc.c [new file with mode: 0644]

index e24e049..204858d 100644 (file)
@@ -247,6 +247,7 @@ if(VPP_BUILD_VPPINFRA_TESTS)
     macros
     maplog
     pmalloc
+    pool_alloc
     pool_iterate
     ptclosure
     random
index ea22af4..968614e 100644 (file)
@@ -333,7 +333,7 @@ _pool_alloc (void **pp, uword n_elts, uword align, void *heap, uword elt_sz)
   ph = pool_header (pp[0]);
   vec_resize (ph->free_indices, n_elts);
   vec_dec_len (ph->free_indices, n_elts);
-  clib_bitmap_vec_validate (ph->free_bitmap, len + n_elts - 1);
+  clib_bitmap_validate (ph->free_bitmap, (len + n_elts) ?: 1);
 }
 
 #define pool_alloc_aligned_heap(P, N, A, H)                                   \
diff --git a/src/vppinfra/test_pool_alloc.c b/src/vppinfra/test_pool_alloc.c
new file mode 100644 (file)
index 0000000..57b78b8
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright(c) 2023 Yandex LLC.
+ */
+
+#include <vppinfra/pool.h>
+
+/* can be a very large size */
+#define NELTS 1024
+
+int
+main (int argc, char *argv[])
+{
+  u32 *junk = 0;
+  int i;
+  u32 *tp = 0;
+  u32 *indices = 0;
+
+  clib_mem_init (0, 3ULL << 30);
+
+  vec_validate (indices, NELTS - 1);
+  vec_set_len (indices, 0);
+
+  /* zero size allocation is ok */
+  pool_alloc (tp, 0);
+
+  fformat (stdout, "%d pool elts of empty pool\n", pool_elts (tp));
+
+  pool_validate (tp);
+
+  pool_alloc (tp, NELTS);
+
+  for (i = 0; i < NELTS; i++)
+    {
+      pool_get (tp, junk);
+      vec_add1 (indices, junk - tp);
+      *junk = i;
+    }
+
+  for (i = 0; i < NELTS; i++)
+    {
+      junk = pool_elt_at_index (tp, indices[i]);
+      ASSERT (*junk == i);
+    }
+
+  fformat (stdout, "%d pool elts before deletes\n", pool_elts (tp));
+
+  pool_put_index (tp, indices[12]);
+  pool_put_index (tp, indices[43]);
+
+  fformat (stdout, "%d pool elts after deletes\n", pool_elts (tp));
+
+  pool_validate (tp);
+
+  pool_free (tp);
+  return 0;
+}