-
Notifications
You must be signed in to change notification settings - Fork 61
Description
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 :)