Free() 没有清除 glibc 中的 prev_in_use 位

问题描述 投票:0回答:1

我使用的是带有 glibc 的 Linux 64 位

ldd (Ubuntu EGLIBC 2.19-0ubuntu6.15) 2.19

这是我的代码

int main (int argc , char** argv){    

    char *first , *second;
    first = malloc(16);
    second = malloc(16);

    free(first);
    free(second);    
}

问题是我在互联网上研究过,当调用 free 时,它会清除下一个块的

prev_in_use
位,下面是第一次调用
free
后这两个块的内存区域。

gdb-peda$ x/20gx 0x602010-16
0x602000:   0x0000000000000000  0x0000000000000021
0x602010:   0x0000000000000000  0x0000000000000000
0x602020:   0x0000000000000000  0x0000000000000021
0x602030:   0x0000000000000000  0x0000000000000000
0x602040:   0x0000000000000000  0x0000000000020fc1
0x602050:   0x0000000000000000  0x0000000000000000

现在的问题是我研究了下一个相邻块的 prev_in_use 位被清除,并且下一个块的

prev_size
将包含此释放块的大小,但从上面的输出来看,
prev_in_use
位都没有被清除,大小也没有被清除。该块写入下一个块
prev_size
字段。

问题是什么?任何帮助将不胜感激。

c malloc free glibc
1个回答
0
投票

问题是 glibc 比这稍微复杂一点。它使用多种方法来存储空闲块。在您显示的示例中,由于您正在使用的块的大小,它们将进入 tcache。

glibc 的问题是其 malloc 实现(ptmalloc2 算法)在不同版本之间差异很大。您应该包含您正在使用的 glibc 版本。不管怎样,假设你的 ubuntu 是最新的,你可能使用的是 glibc 2.35。您可以在下面看到

_int_free()
的代码,它是实现 free() 主要功能的代码。

static void
_int_free (mstate av, mchunkptr p, int have_lock)
{
  // [... declaration of variables and a couple of security checks]

#if USE_TCACHE
  {
    size_t tc_idx = csize2tidx (size);
    if (tcache != NULL && tc_idx < mp_.tcache_bins)
      {
    /* Check to see if it's already in the tcache.  */
    tcache_entry *e = (tcache_entry *) chunk2mem (p);

    /* This test succeeds on double free.  However, we don't 100%
       trust it (it also matches random payload data at a 1 in
       2^<size_t> chance), so verify it's not an unlikely
       coincidence before aborting.  */
    if (__glibc_unlikely (e->key == tcache_key))
      {
        tcache_entry *tmp;
        size_t cnt = 0;
        LIBC_PROBE (memory_tcache_double_free, 2, e, tc_idx);
        for (tmp = tcache->entries[tc_idx];
         tmp;
         tmp = REVEAL_PTR (tmp->next), ++cnt)
          {
        if (cnt >= mp_.tcache_count)
          malloc_printerr ("free(): too many chunks detected in tcache");
        if (__glibc_unlikely (!aligned_OK (tmp)))
          malloc_printerr ("free(): unaligned chunk detected in tcache 2");
        if (tmp == e)
          malloc_printerr ("free(): double free detected in tcache 2");
        /* If we get here, it was a coincidence.  We've wasted a
           few cycles, but don't abort.  */
          }
      }

    if (tcache->counts[tc_idx] < mp_.tcache_count)
      {
        tcache_put (p, tc_idx);
        return;
      }
      }
  }
#endif

在进行一些表面检查之后,该函数立即查看该块的大小是否使其有资格放置在 tcache 中。这是通过 csize2tidx (意思是“tcache 索引的块大小”)完成的,这是因为 tcache 有多个 bin,一个用于不同的块大小,所以这个宏的作用是获取一个大小并告诉 tcache bin 的索引该大小对应,然后我们检查该索引是否确实存在,这有效地设置了块在放入 tcache 之前可能具有的大小限制,该限制在 x64 中和典型配置中为 1024。

© www.soinside.com 2019 - 2024. All rights reserved.