Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Arpan3323 opened this issue Feb 5, 2025 · 4 comments

Comments

@Arpan3323
Copy link

Describe the bug

Hi, testing umpire::util::FixedMallocPool with fuzzy arguments results in a memory corruption bug and a crash.

FixedMallocPool::FixedMallocPool(const std::size_t object_bytes, const std::size_t objects_per_pool)

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 :)

@Arpan3323
Copy link
Author

I think this is happening because FixedMallocPool::allocInPool(Pool &p) allocates bytes that are a little bit outside the Pool, making p.next point to an invalid address. The problem seems to be happening at this line:

p.next = (p.num_free != 0) ? addr_from_index(p, *reinterpret_cast<unsigned int*>(p.next)) : nullptr;

That said, this is still my guess and I could be wrong. I am looking at Fast Efficient Fixed-Size Memory Pool -- Ben Kenwright to understand the algorithm more clearly and potentially fix the bug.

@davidbeckingsale I wanted to confirm if you think this is indeed a bug in FixedMallocPool?

@davidbeckingsale
Copy link
Member

I think that's a reasonable hypothesis. Are you able to reproduce this deterministically?

@Arpan3323
Copy link
Author

So far, my attempts at reproducing this issue deterministically have not been successful. Though, changing the following lines in the fuzz test:

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;

to:

std::size_t object_size = static_cast<std::size_t>(provider.ConsumeIntegralInRange<int>(1,4096));
std::size_t object_count = static_cast<std::size_t>(provider.ConsumeIntegralInRange<int>(1,4096));

results in a different AddressSanitizer internal error, namely, AddressSanitizer: CHECK failed: asan_allocator.cpp:190 "((old)) == ((kAllocBegMagic))" (0xcc6e96b9cc000000, 0xcc6e96b9cc6e96b9), as shown below:

INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 1598474609
INFO: Loaded 1 modules   (76 inline 8-bit counters): 76 [0x55a24b4d9248, 0x55a24b4d9294), 
INFO: Loaded 1 PC tables (76 PCs): 76 [0x55a24b4d9298,0x55a24b4d9758), 
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: 31Mb
        NEW_FUNC[1/1]: 0x55a24b454410 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
#1377   NEW    cov: 38 ft: 39 corp: 2/18b lim: 17 exec/s: 0 rss: 40Mb L: 17/17 MS: 5 InsertRepeatedBytes-ShuffleBytes-InsertByte-InsertRepeatedBytes-InsertRepeatedBytes-
#1379   REDUCE cov: 38 ft: 39 corp: 2/17b lim: 17 exec/s: 0 rss: 47Mb L: 16/16 MS: 2 EraseBytes-InsertRepeatedBytes-
#1404   REDUCE cov: 38 ft: 54 corp: 3/33b lim: 17 exec/s: 0 rss: 94Mb L: 16/16 MS: 5 EraseBytes-ShuffleBytes-CMP-InsertByte-InsertRepeatedBytes- DE: "\000\000\000\000\000\000\000\000"-
#1418   REDUCE cov: 38 ft: 58 corp: 4/49b lim: 17 exec/s: 0 rss: 112Mb L: 16/16 MS: 4 CopyPart-EraseBytes-InsertByte-CrossOver-
#1424   NEW    cov: 38 ft: 81 corp: 5/65b lim: 17 exec/s: 1424 rss: 163Mb L: 16/16 MS: 1 ChangeBinInt-
#1439   NEW    cov: 38 ft: 104 corp: 6/82b lim: 17 exec/s: 1439 rss: 198Mb L: 17/17 MS: 5 InsertByte-ChangeBinInt-ChangeBinInt-ChangeBit-CopyPart-
#1514   NEW    cov: 38 ft: 107 corp: 7/99b lim: 17 exec/s: 1514 rss: 322Mb L: 17/17 MS: 5 ChangeBit-InsertByte-ChangeBit-ChangeBinInt-CopyPart-
AddressSanitizer: CHECK failed: asan_allocator.cpp:190 "((old)) == ((kAllocBegMagic))" (0xcc6e96b9cc000000, 0xcc6e96b9cc6e96b9) (tid=20252)
    #0 0x55a24b41d835 in __asan::CheckUnwind() asan_rtl.cpp.o
    #1 0x55a24b437ab6 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) (fixedMallocPoolFuzzer+0x128ab6) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #2 0x55a24b37dc29 in __asan::QuarantineCallback::Recycle(__asan::AsanChunk*) const (fixedMallocPoolFuzzer+0x6ec29) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #3 0x55a24b37d96c in __sanitizer::Quarantine<__asan::QuarantineCallback, __asan::AsanChunk>::DoRecycle(__sanitizer::QuarantineCache<__asan::QuarantineCallback>*, __asan::QuarantineCallback) (fixedMallocPoolFuzzer+0x6e96c) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #4 0x55a24b37d58c in __sanitizer::Quarantine<__asan::QuarantineCallback, __asan::AsanChunk>::Recycle(unsigned long, __asan::QuarantineCallback) (fixedMallocPoolFuzzer+0x6e58c) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #5 0x55a24b37f85f in __sanitizer::Quarantine<__asan::QuarantineCallback, __asan::AsanChunk>::Put(__sanitizer::QuarantineCache<__asan::QuarantineCallback>*, __asan::QuarantineCallback, __asan::AsanChunk*, unsigned long) (fixedMallocPoolFuzzer+0x7085f) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #6 0x55a24b4130cf in free (fixedMallocPoolFuzzer+0x1040cf) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #7 0x55a24b455235 in umpire::util::FixedMallocPool::~FixedMallocPool() (fixedMallocPoolFuzzer+0x146235) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #8 0x55a24b4542c4 in LLVMFuzzerTestOneInput /fixed_malloc_pool/fuzzer.cpp:35:1
    #9 0x55a24b35f1d4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (fixedMallocPoolFuzzer+0x501d4) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #10 0x55a24b35e8c9 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) (fixedMallocPoolFuzzer+0x4f8c9) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #11 0x55a24b3600b5 in fuzzer::Fuzzer::MutateAndTestOne() (fixedMallocPoolFuzzer+0x510b5) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #12 0x55a24b360c15 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) (fixedMallocPoolFuzzer+0x51c15) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #13 0x55a24b34deef in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (fixedMallocPoolFuzzer+0x3eeef) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #14 0x55a24b378576 in main (fixedMallocPoolFuzzer+0x69576) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)
    #15 0x7f448c5da1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #16 0x7f448c5da28a in __libc_start_main csu/../csu/libc-start.c:360:3
    #17 0x55a24b342ed4 in _start (fixedMallocPoolFuzzer+0x33ed4) (BuildId: 8adae099c86386cbd09e9e463a1e7fdf0e87c4c9)

This still leads me to suspect that invalid/unallowed regions of memory that are actually reserved for allocation metadata by AddressSanitizer when malloc is called is overwritten.

Perhaps, this is because of some misalignment issues. In other words, when FixedMallocPool::addr_from_index(...) is called here:

p.next = (p.num_free != 0) ? addr_from_index(p, *reinterpret_cast<unsigned int*>(p.next)) : nullptr;

p.next points to an invalid address (as I guessed earlier) and on the next FixedMallocPool::allocInPool(Pool& p) call, ret = static_cast<void*>(p.next); has allocated memory in an invalid region and now p.num_free == 0. Thus, when the destructor is called it frees a chunk of bytes that it was not supposed to resulting in errors that indicate memory is overwritten when in fact restricted region of memory is partially freed.

@Arpan3323
Copy link
Author

After building the project as a debug build and running my fuzz test in GDB, I have found the exact arguments for FixedMallocPool::FixedMallocPool(const std::size_t object_bytes, const std::size_t objects_per_pool) on which the error occurs. This should allow us to reproduce the error deterministically. Moreover, updating the fuzz test source to only supply these values to FixedMallocPool constructor results in a clear signal from AddressSanitizer as opposed to AddressSanitizer failing internal checks, which was the case earlier.

Updated fuzz test to reproduce the bug

#include <vector>
#include "umpire/Allocator.hpp"
#include "umpire/ResourceManager.hpp"
#include "umpire/util/FixedMallocPool.hpp"
#include <fuzzer/FuzzedDataProvider.h>

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

    std::size_t object_size = 1; /* static object_size */
    std::size_t object_count = 3966; /* static object_count */
    
    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;
}

Output from running the fuzzer under GDB:

(gdb) r
Starting program: fixedMallocPoolFuzzer 

This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.ubuntu.com>
Enable debuginfod for this session? (y or [n]) n
Debuginfod has been disabled.
To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 804209758
INFO: Loaded 1 modules   (62 inline 8-bit counters): 62 [0x55555571e228, 0x55555571e266), 
INFO: Loaded 1 PC tables (62 PCs): 62 [0x55555571e268,0x55555571e648), 
[New Thread 0x7ffff33b96c0 (LWP 73735)]
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: 38Mb
        NEW_FUNC[1/1]: [Detaching after fork from child process 73736]
0x555555699140 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
#1426   NEW    cov: 30 ft: 31 corp: 2/18b lim: 17 exec/s: 1426 rss: 38Mb L: 17/17 MS: 4 InsertRepeatedBytes-InsertRepeatedBytes-InsertByte-InsertRepeatedBytes-
#1544   REDUCE cov: 30 ft: 31 corp: 2/17b lim: 17 exec/s: 1544 rss: 38Mb L: 16/16 MS: 3 EraseBytes-CopyPart-InsertByte-

Thread 1 "fixedMallocPool" received signal SIGSEGV, Segmentation fault.
0x000055555569a038 in umpire::util::FixedMallocPool::allocInPool (this=0x7ffff5d30920, p=...) at /home/repos/Umpire/src/umpire/util/FixedMallocPool.cpp:63
63          *ptr = p.num_initialized + 1;
(gdb) p m_obj_bytes
$1 = 1
(gdb) p m_obj_per_pool
$2 = 3966
(gdb) print p
$3 = (umpire::util::FixedMallocPool::Pool &) @0x503000003eb0: {
  data = 0x52000003f080 "\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310"..., next = 0x52000003fffd "\017", num_initialized = 3965, num_free = 1}
(gdb) c
Continuing.
AddressSanitizer:DEADLYSIGNAL
=================================================================
==73697==ERROR: AddressSanitizer: SEGV on unknown address 0x520000040000 (pc 0x55555569a038 bp 0x7fffffffd7f0 sp 0x7fffffffd7d0 T0)
==73697==The signal is caused by a WRITE memory access.
    #0 0x55555569a038 in umpire::util::FixedMallocPool::allocInPool(umpire::util::FixedMallocPool::Pool&) /home/repos/Umpire/src/umpire/util/FixedMallocPool.cpp:63:10
    #1 0x55555569a121 in umpire::util::FixedMallocPool::allocate_impl(unsigned long) /home/repos/Umpire/src/umpire/util/FixedMallocPool.cpp:82:22
    #2 0x55555569a23f in umpire::util::FixedMallocPool::allocate(unsigned long) /home/repos/Umpire/src/umpire/util/FixedMallocPool.cpp:102:23
    #3 0x555555698dcd in LLVMFuzzerTestOneInput fuzzer.cpp:21:26
    #4 0x5555555a41d4 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (fixedMallocPoolFuzzer+0x501d4) (BuildId: 2dc05342bc7c2fe1e2b089e1109d84c71bd3e4c7)
    #5 0x5555555a38c9 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool, bool*) (fixedMallocPoolFuzzer+0x4f8c9) (BuildId: 2dc05342bc7c2fe1e2b089e1109d84c71bd3e4c7)
    #6 0x5555555a50b5 in fuzzer::Fuzzer::MutateAndTestOne() (fixedMallocPoolFuzzer+0x510b5) (BuildId: 2dc05342bc7c2fe1e2b089e1109d84c71bd3e4c7)
    #7 0x5555555a5c15 in fuzzer::Fuzzer::Loop(std::vector<fuzzer::SizedFile, std::allocator<fuzzer::SizedFile>>&) (fixedMallocPoolFuzzer+0x51c15) (BuildId: 2dc05342bc7c2fe1e2b089e1109d84c71bd3e4c7)
    #8 0x555555592eef in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (fixedMallocPoolFuzzer+0x3eeef) (BuildId: 2dc05342bc7c2fe1e2b089e1109d84c71bd3e4c7)
    #9 0x5555555bd576 in main (fixedMallocPoolFuzzer+0x69576) (BuildId: 2dc05342bc7c2fe1e2b089e1109d84c71bd3e4c7)
    #10 0x7ffff7a201c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #11 0x7ffff7a2028a in __libc_start_main csu/../csu/libc-start.c:360:3
    #12 0x555555587ed4 in _start (fixedMallocPoolFuzzer+0x33ed4) (BuildId: 2dc05342bc7c2fe1e2b089e1109d84c71bd3e4c7)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/repos/Umpire/src/umpire/util/FixedMallocPool.cpp:63:10 in umpire::util::FixedMallocPool::allocInPool(umpire::util::FixedMallocPool::Pool&)
==73697==ABORTING
MS: 1 CopyPart-; base unit: 9caf36394b24a279e8b43337af9e0bd44accb31d
0x69,0x69,0xe5,0xe5,0x6a,0xe5,0xe5,0x69,0x69,0xe5,0xe5,0xe5,0xe5,0x69,0x6a,0xe5,
ii\345\345j\345\345ii\345\345\345\345ij\345
artifact_prefix='./'; Test unit written to ./crash-94866233c070392671c4d541270c843c3a39290d
Base64: aWnl5Wrl5Wlp5eXl5Wlq5Q==
[Thread 0x7ffff79f17c0 (LWP 73697) exited]
[Thread 0x7ffff33b96c0 (LWP 73735) exited]
[New process 73697]
[Inferior 1 (process 73697) exited with code 01]
(gdb) q

The Segmentation Fault occurs at FixedMallocPool.cpp:63 when umpire::util::FixedMallocPool::allocInPool(Pool& p) is called for the last time (when p.num_free == 1) and ptr is dereferenced:

*ptr = p.num_initialized + 1;

I tried adding:

UMPIRE_ASSET(ptr);
*ptr = p.num_initialized + 1;

but the error persisted. So either, addr_from_index(...) is returning an invalid addresses or there could be an alignment issue when casting to unsigned int*.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants