Skip to content

AddressSanitizer detects memory corruption bug in umpire::util::FixedMallocPool #932

@Arpan3323

Description

@Arpan3323

Describe the bug

Hi, testing umpire::util::FixedMallocPool with fuzzy arguments results in a memory corruption bug and a crash.
https://github.com/LLNL/Umpire/blob/02df2c1133af8e08b327b2c79483d78540bfd516/src/umpire/util/FixedMallocPool.cpp#L42

Fuzz test to reproduce the bug

#include <iostream>
#include <vector>
#include "umpire/Allocator.hpp"
#include "umpire/ResourceManager.hpp"
#include "umpire/util/FixedMallocPool.hpp"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    if (size < sizeof(std::size_t) * 2) { return 0; }

    std::size_t object_size = *reinterpret_cast<const std::size_t*>(data) % 1024 + 1;
    std::size_t object_count = (size / sizeof(std::size_t)) % 1024 + 1;
    umpire::Allocator allocator = umpire::ResourceManager::getInstance().getAllocator("HOST");
    umpire::util::FixedMallocPool pool(object_size,object_count);
    std::vector<void*> allocated_ptrs;

    for (std::size_t i = 0; i < object_count; ++i) 
    {
        void* ptr = pool.allocate(object_size);
        if (ptr) 
        {
            allocated_ptrs.push_back(ptr);
        }
    }

    for (void* ptr : allocated_ptrs) 
    {
        if (ptr) 
        {
            pool.deallocate(ptr);
        }
    }

    return 0;
}

Crash report

INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 406018877
INFO: Loaded 1 modules   (64 inline 8-bit counters): 64 [0x559148a908f0, 0x559148a90930), 
INFO: Loaded 1 PC tables (64 PCs): 64 [0x559148a90930,0x559148a90d30), 
INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
INFO: A corpus is not provided, starting from an empty corpus
#2      INITED cov: 2 ft: 2 corp: 1/1b exec/s: 0 rss: 32Mb
        NEW_FUNC[1/1]: 0x5591488d3620 in void std::vector<void*, std::allocator<void*>>::_M_realloc_insert<void* const&>(__gnu_cxx::__normal_iterator<void**, std::vector<void*, std::allocator<void*>>>, void* const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/bits/vector.tcc:453
#1341   NEW    cov: 29 ft: 30 corp: 2/17b lim: 17 exec/s: 0 rss: 34Mb L: 16/16 MS: 3 ChangeBinInt-ChangeBit-InsertRepeatedBytes-
#2168   NEW    cov: 31 ft: 37 corp: 3/42b lim: 25 exec/s: 0 rss: 36Mb L: 25/25 MS: 2 InsertRepeatedBytes-CopyPart-
#2254   REDUCE cov: 31 ft: 37 corp: 3/41b lim: 25 exec/s: 0 rss: 37Mb L: 24/24 MS: 1 EraseBytes-
#3117   REDUCE cov: 31 ft: 55 corp: 4/74b lim: 33 exec/s: 0 rss: 39Mb L: 33/33 MS: 3 ChangeBinInt-ShuffleBytes-InsertRepeatedBytes-
#3374   REDUCE cov: 31 ft: 55 corp: 4/73b lim: 33 exec/s: 0 rss: 40Mb L: 32/32 MS: 2 EraseBytes-CopyPart-
#4398   REDUCE cov: 31 ft: 57 corp: 5/113b lim: 43 exec/s: 0 rss: 43Mb L: 40/40 MS: 4 CMP-InsertRepeatedBytes-ChangeByte-InsertRepeatedBytes- DE: "\000\000\000\000\000\000\000\002"-
#4916   NEW    cov: 31 ft: 59 corp: 6/161b lim: 48 exec/s: 0 rss: 45Mb L: 48/48 MS: 3 InsertRepeatedBytes-ShuffleBytes-CMP- DE: "\000\000"-
#6031   REDUCE cov: 31 ft: 64 corp: 7/218b lim: 58 exec/s: 0 rss: 50Mb L: 57/57 MS: 5 CrossOver-ShuffleBytes-ChangeBit-CopyPart-InsertRepeatedBytes-
#6237   REDUCE cov: 31 ft: 64 corp: 7/217b lim: 58 exec/s: 0 rss: 50Mb L: 56/56 MS: 1 CrossOver-
#7263   REDUCE cov: 31 ft: 70 corp: 8/281b lim: 68 exec/s: 0 rss: 56Mb L: 64/64 MS: 1 PersAutoDict- DE: "\000\000\000\000\000\000\000\002"-
#10320  REDUCE cov: 31 ft: 72 corp: 9/377b lim: 98 exec/s: 0 rss: 73Mb L: 96/96 MS: 2 CMP-InsertRepeatedBytes- DE: "\020\000\000\000\000\000\000\000"-
#12902  NEW    cov: 31 ft: 75 corp: 10/497b lim: 122 exec/s: 0 rss: 90Mb L: 120/120 MS: 2 ChangeBinInt-InsertRepeatedBytes-
#13600  NEW    cov: 31 ft: 77 corp: 11/625b lim: 128 exec/s: 0 rss: 95Mb L: 128/128 MS: 3 ChangeBit-ChangeBinInt-PersAutoDict- DE: "\000\000\000\000\000\000\000\002"-
#17961  NEW    cov: 31 ft: 79 corp: 12/795b lim: 170 exec/s: 0 rss: 132Mb L: 170/170 MS: 1 InsertRepeatedBytes-
#18904  REDUCE cov: 31 ft: 79 corp: 12/794b lim: 177 exec/s: 0 rss: 141Mb L: 169/169 MS: 3 EraseBytes-ShuffleBytes-InsertRepeatedBytes-
#19715  REDUCE cov: 31 ft: 79 corp: 12/793b lim: 184 exec/s: 0 rss: 148Mb L: 168/168 MS: 1 EraseBytes-
#26945  REDUCE cov: 31 ft: 82 corp: 13/1042b lim: 254 exec/s: 0 rss: 211Mb L: 249/249 MS: 5 InsertRepeatedBytes-ChangeByte-InsertRepeatedBytes-CMP-CopyPart- DE: "\017\000\000\000\000\000\000\000"-
#27771  NEW    cov: 31 ft: 84 corp: 14/1302b lim: 261 exec/s: 0 rss: 219Mb L: 260/260 MS: 1 CopyPart-
#31683  REDUCE cov: 31 ft: 84 corp: 14/1299b lim: 293 exec/s: 0 rss: 257Mb L: 257/257 MS: 2 ShuffleBytes-CrossOver-
#33313  NEW    cov: 31 ft: 86 corp: 15/1606b lim: 309 exec/s: 0 rss: 273Mb L: 307/307 MS: 5 PersAutoDict-ChangeByte-CrossOver-ChangeBinInt-CrossOver- DE: "\000\000\000\000\000\000\000\002"-
#33321  REDUCE cov: 31 ft: 86 corp: 15/1603b lim: 309 exec/s: 0 rss: 273Mb L: 304/304 MS: 3 EraseBytes-InsertRepeatedBytes-CrossOver-
AddressSanitizer: CHECK failed: asan_allocator.cpp:239 "((old_chunk_state)) == ((CHUNK_QUARANTINE))" (0x0, 0x3) (tid=13562)
    #0 0x55914889cc25 in __asan::CheckUnwind() asan_rtl.cpp.o
    #1 0x5591488b6ea6 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) (fixedMallocPoolFuzzer+0x12fea6) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #2 0x5591487fcff4 in __asan::QuarantineCallback::Recycle(__asan::AsanChunk*) const (fixedMallocPoolFuzzer+0x75ff4) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #3 0x5591487fcd5c in __sanitizer::Quarantine<__asan::QuarantineCallback, __asan::AsanChunk>::DoRecycle(__sanitizer::QuarantineCache<__asan::QuarantineCallback>*, __asan::QuarantineCallback) (fixedMallocPoolFuzzer+0x75d5c) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #4 0x5591487fc97c in __sanitizer::Quarantine<__asan::QuarantineCallback, __asan::AsanChunk>::Recycle(unsigned long, __asan::QuarantineCallback) (fixedMallocPoolFuzzer+0x7597c) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #5 0x5591487fec4f in __sanitizer::Quarantine<__asan::QuarantineCallback, __asan::AsanChunk>::Put(__sanitizer::QuarantineCache<__asan::QuarantineCallback>*, __asan::QuarantineCallback, __asan::AsanChunk*, unsigned long) (fixedMallocPoolFuzzer+0x77c4f) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #6 0x5591488924bf in free (fixedMallocPoolFuzzer+0x10b4bf) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #7 0x55914898d247 in umpire::util::FixedMallocPool::~FixedMallocPool() (fixedMallocPoolFuzzer+0x206247) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #8 0x5591488d3496 in LLVMFuzzerTestOneInput /fixed_malloc_pool/fuzzer.cpp:35:1
    #9 0x5591487de5c4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (fixedMallocPoolFuzzer+0x575c4) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #10 0x5591487ddcb9 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) (fixedMallocPoolFuzzer+0x56cb9) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #11 0x5591487df4a5 in fuzzer::Fuzzer::MutateAndTestOne() (fixedMallocPoolFuzzer+0x584a5) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #12 0x5591487e0005 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) (fixedMallocPoolFuzzer+0x59005) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #13 0x5591487cd2df in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (fixedMallocPoolFuzzer+0x462df) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #14 0x5591487f7966 in main (fixedMallocPoolFuzzer+0x70966) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)
    #15 0x7f3836aeb1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
    #16 0x7f3836aeb28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
    #17 0x5591487c22c4 in _start (fixedMallocPoolFuzzer+0x3b2c4) (BuildId: 52fe3df0f10b8d32e0cefb0a88dae472f8c5f6c7)

Expected behavior

I expected FixedMallocPool::~FixedMallocPool() to perform the necessary cleanup or the API to catch the bug and exit.

Potential fix

If we look at the crash report, it seems like the bug is related to FixedMallocPool::~FixedMallocPool() as suggested by the line: #7 0x55914898d247 in umpire::util::FixedMallocPool::~FixedMallocPool(). Though, I doubt this is the case because I tried to manage the lifetime of umpire::util::FixedMallocPool object myself by using umpire::util::FixedMallocPool* pool = new umpire::util::FixedMallocPool(object_size, object_count); but the bug persisted. I am not exactly sure what is causing the memory corruption here. Please let me know if you have any questions :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions