musl libc malloc 中的 adjust_size 是做什么的?

What adjust_size in musl libc malloc does?

我正在研究 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。但我不知道为什么在那种情况下将其作为无符号进行比较,因为看起来两个位置最后都会计算为有符号数。

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

why they are not just comparing against PTRDIFF_MAX

大多数 malloc 实现使用 mmap 单独分配大块。因为 mmap 以页为单位分配内存,所以 n 需要与页边界对齐 (PAGE_SIZE),另外还应包括块头(按 SIZE_ALIGN 对齐)。

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

why are they subtracting 1 from *n

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

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

结果值应小于或等于 PTRDIFF_MAX。值PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE + 1还可以,所以减1。

Also why does they set *n to SIZE_ALIGN if it is 0

因为调整后的块大小应该大于或等于 SIZE_ALIGN 字节以适应 OVERHEAD 字节的堆开销加上请求的数据区域应该能够适应以后从 [=30= 使用的 2 个指针].稍后在代码中采用这种对齐方式。

I think that (*n-1) was being compared as unsigned instead of signed, so they are handling the case where *n is 0. But I do not know why this is being compared as unsigned in that case as it seems both positions would evaluate to signed numbers at the end.

我觉得可以写得简单一点(虽然这可能不正确,我可能需要睡觉了):

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;
}