llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
27.95k stars 11.53k forks source link

scudo/CHECK_GE failed #75761

Open chericc opened 9 months ago

chericc commented 9 months ago

scudo/CHECK_GE failed

Crash outputs

...((Sci->Stats.PoppedBlocks)) >= ((Sci->Stats.PushedBlocks)) (252, 4294966864)...

Location

file: primary32.h

lines:

  NOINLINE uptr releaseToOSMaybe(SizeClassInfo *Sci, uptr ClassId,
                                 bool Force = false) {
    const uptr BlockSize = getSizeByClassId(ClassId);
    const uptr PageSize = getPageSizeCached();

    CHECK_GE(Sci->Stats.PoppedBlocks, Sci->Stats.PushedBlocks);
    const uptr BytesInFreeList =
        Sci->AllocatedUser -
        (Sci->Stats.PoppedBlocks - Sci->Stats.PushedBlocks) * BlockSize;

Line CHECK_GE(Sci->Stats.PoppedBlocks, Sci->Stats.PushedBlocks);may FAIL when PoppedBlocks crosses UINT32_MAX while PushedBlocks not.

Problem reproduction

std::list<void*> g_list;
while (true)
{
    g_list.clear();
    for (int i = 0; i < 10000; ++i)
    {
        void *p = malloc(1600);
        g_list.push_back(p);
    }
    for (auto i : g_list)
    {
        free(i);
    }
}

If malloc executes for about UINT32_MAX times, then CHECK_GE will fail.

Version

This problem occurs with scudo version in 2019(the specific version number not known). The newest version(2023.12.18) has change CHECK_GE to DCHECK_GE, but this problem still exists.

cferris1000 commented 1 month ago

This should be fixed as we move to a single primary.h instead of two. The primary64.h, which will be the new base, does not appear to have this same issue.