【问题标题】:Is there a malloc variant that zeros out blocks on calling `free()`?是否有一个 malloc 变体可以在调用“free()”时将块清零?
【发布时间】:2013-09-16 19:24:53
【问题描述】:

我想将标准的 malloc 系统范围(通过 LD_PRELOAD 或仅替换已安装的 libc)替换为将已释放块中可能出现的所有内容归零的内容。有谁知道现有的解决方案?

在堆的未使用部分使用零将使通过 zram-config 压缩它更加有效。由于我需要 RAM 多于 CPU,因此增加 CPU 使用率不是问题。

【问题讨论】:

  • 您之后需要能够恢复到标准 malloc 吗?否则,您可以只修改系统上的 C 库。
  • @Étienne 我只需要一个已经修改和测试过的 libc。

标签: linux malloc customization libc


【解决方案1】:

您可以修改系统上的 C 库。我认为您不会找到一个修改后的 C 库以这种方式精确分配内存,因为它是非标准的。但修改听起来相对容易。看看你的 C 库的实现,你可以将 free 的实现替换为执行 free+memset 而不是 free 的包装器。

【讨论】:

  • 其实……不幸的是,并不容易。您不能以简单的方式 wrap free(),因为它需要 仅一个地址(并且没有大小)作为参数。在不了解实现细节的情况下,您无法在给定地址找到内存块的大小......所以是的,如果您有源代码,您可以相应地对其进行修改。不过,它不会是“包装器”。
  • @FrankH:是的,我可能不清楚,我的意思是重新实现免费,将免费的原始实现命名为“standard_free”,然后在您自己的免费实现中使用“standard_free”。
  • @FrankH。虽然更改需要一些知识才能实施,但至少在当前 eglibc 的情况下,它相对简单。有关实际补丁,请参阅下面的答案。
  • @jons34yp 我没有说这很难,只是说......只是说你不能包装它,需要实际的实现细节:-)
【解决方案2】:

以防万一有人遇到类似问题,下面是 eglibc 2.17 的补丁。

--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1424,10 +1424,16 @@
 #define first(b)     ((b)->fd)
 #define last(b)      ((b)->bk)

+#define zero_sizes(P) {                                                \
+    P->size = 0;                                                        \
+    P->prev_size = 0;                                                   \
+}
+
 /* Take a chunk off a bin list */
 #define unlink(P, BK, FD) {                                            \
   FD = P->fd;                                                          \
   BK = P->bk;                                                          \
+  P->bk = 0; P->fd = 0; \
   if (__builtin_expect (FD->bk != P || BK->fd != P, 0))                \
     malloc_printerr (check_action, "corrupted double-linked list", P); \
   else {                                                               \
@@ -1449,9 +1455,11 @@
       } else {                                                         \
         P->fd_nextsize->bk_nextsize = P->bk_nextsize;                       \
         P->bk_nextsize->fd_nextsize = P->fd_nextsize;                       \
       }                                                                \
+      P->fd_nextsize = 0;                                               \
+      P->bk_nextsize = 0;                                               \
     }                                                                  \
   }                                                                    \
 }

 /*
@@ -1878,8 +1886,10 @@

 static int perturb_byte;

-#define alloc_perturb(p, n) memset (p, (perturb_byte ^ 0xff) & 0xff, n)
-#define free_perturb(p, n) memset (p, perturb_byte & 0xff, n)
+#define alloc_perturb(p, n) do {} while(0)
+#define free_perturb(p, n) memset (p, 0, n)


 /* ------------------- Support for multiple arenas -------------------- */
@@ -3809,8 +3819,7 @@
       }
     }

-    if (__builtin_expect (perturb_byte, 0))
-      free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+    free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);

     set_fastchunks(av);
     unsigned int idx = fastbin_index(size);
@@ -3892,13 +3901,13 @@
       goto errout;
     }

-    if (__builtin_expect (perturb_byte, 0))
-      free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+    free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);

     /* consolidate backward */
     if (!prev_inuse(p)) {
       prevsize = p->prev_size;
       size += prevsize;
+      unlink_free(p);
       p = chunk_at_offset(p, -((long) prevsize));
       unlink(p, bck, fwd);
     }
@@ -3910,6 +3921,7 @@
       /* consolidate forward */
       if (!nextinuse) {
         unlink(nextchunk, bck, fwd);
+        zero_sizes(nextchunk);
         size += nextsize;
       } else
    clear_inuse_bit_at_offset(nextchunk, 0);
@@ -4069,6 +4081,7 @@
      if (!prev_inuse(p)) {
        prevsize = p->prev_size;
        size += prevsize;
+       zero_sizes(p);
        p = chunk_at_offset(p, -((long) prevsize));
        unlink(p, bck, fwd);
      }
@@ -4079,6 +4092,7 @@
        if (!nextinuse) {
          size += nextsize;
          unlink(nextchunk, bck, fwd);
+         zero_sizes(nextchunk);
        } else
          clear_inuse_bit_at_offset(nextchunk, 0);

【讨论】:

    【解决方案3】:

    为什么不编写自己的free_zero 函数?

    void free_zero(void *p, size_t n)
    {
       volatile unsigned char *zp = p;
    
       if (!p) return;
    
       while (n--)
       {
           *zp++ = 0;
       }
    
       free(p);
    }
    

    【讨论】:

    • 或者使用memset (p, 0, n)而不是循环?
    • @ChrisJ memset 的问题是“智能”编译器有权对其进行优化
    • @ouah "优化memset() out" 并不意味着不会完成块填充。如果编译器/标准库选择将memset() 实现为inline,那么您将不会在生成的代码中看到对它的调用,但效果必须保持。
    猜你喜欢
    • 2015-08-21
    • 2019-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-16
    • 2010-12-09
    • 2023-04-07
    • 1970-01-01
    相关资源
    最近更新 更多