musl libc malloc中的adjust_size有什么作用?

时间:2018-02-06 10:21:41

标签: c malloc libc

我正在研究musl libc malloc实现,我很难理解adjust_size函数。

static int adjust_size(size_t *n)  
{
    /* Result of pointer difference must fit in ptrdiff_t. */
    if (*n-1 > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) {
        if (*n) {
            errno = ENOMEM;
            return -1;
        } else {
            *n = SIZE_ALIGN;
            return 0;
        }
    }
    *n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK;
    return 0;
}

例如,在第一次比较中,为什么他们不只是与PTRDIFF_MAX进行比较。无论如何,这似乎是上面评论的意图,为什么他们从*n减去1,我认为(*n-1)被比较为无符号而不是签名,所以他们正在处理案例其中*n为0.但我不知道为什么在这种情况下将其作为无符号进行比较,因为看起来这两个职位在最后都会评估为签名数字。

另外,为什么如果它为0,他们会将*n设置为SIZE_ALIGN?我的理解是malloc应该返回NULL或指针,如果size为0,它可以被传递给free而不会引起问题。

1 个答案:

答案 0 :(得分:2)

  

为什么他们不只是与PTRDIFF_MAX

进行比较

大多数malloc实现使用mmap分别分配大块。因为mmap在页面中分配内存,所以n需要与页面边界(PAGE_SIZE)对齐,另外还应包括块头(由SIZE_ALIGN对齐)。< / p>

这就是为什么要对PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE而不是PTRDIFF_MAX进行比较的原因 - 以确保所有可能的未来对齐调整都不会导致块大小超过PTRDIFF_MAX。< / p>

  

为什么他们会从*n

中减去1

因为n可能会在以后像这样对齐:

n = (n + SIZE_ALIGN + PAGE_SIZE - 1) & -PAGE_SIZE;

结果值应小于或等于PTRDIFF_MAX。值PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE + 1仍然可以,因此减去1。

  

如果它为0

,为什么他们会将*n设置为SIZE_ALIGN

因为调整后的块大小应该大于或等于SIZE_ALIGN字节以适应OVERHEAD字节的堆开销加上请求的数据区域应该能够适应稍后从free使用的2个指针。稍后在代码中假定此对齐。

  

我认为(*n-1)被比较为无符号而不是   签名,所以他们正在处理*n为0的情况。但我没有   知道为什么在这种情况下将其作为无符号进行比较   这两个职位最终都会评估签名数字。

我认为它可以写得更简单(虽然这可能不正确,我可能需要睡觉):

static int adjust_size(size_t *n)
{
    if (*n > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE + 1) {
        errno = ENOMEM;
        return -1;
    }
    *n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK;
    return 0;
}