The project uses CMake to build a library, FooBug
, and a tests
executable,
which is what is making use of googletest.
There appears to be an issue with googletest and an interaction with:
-
defining at least 5 tests
-
compiling the
tests
executable, which linksgtest_main
with the following ASAN-related flag:-fsanitize=address
-
making use of nlohmann/json, specifically creating a
nlohmann::json
object and then trying to extract the value using theget<std::vector<int>>()
syntax, for example:json ints = json{1, 2, 3}; std::vector<int> ints_vec = ints.get<std::vector<int>>();
You can do it all with a single command:
git clone https://github.com/hamchapman/googletest-json-asan-issue.git \
&& cd googletest-json-asan-issue && mkdir -p build && cd build && cmake .. \
&& make -j8 && ./tests
Or you can clone the repo, cd
into googletest-json-asan-issue
, and run the
following:
mkdir -p build && cd build && cmake .. && make -j8 && ./tests
You'll then see some output like the following.
Error output
-- Configuring done -- Generating done -- Build files have been written to: /Users/ham/Desktop/cpp/build/googletest-download [ 11%] Performing update step for 'googletest' [ 22%] No configure step for 'googletest' [ 33%] No build step for 'googletest' [ 44%] No install step for 'googletest' [ 55%] No test step for 'googletest' [ 66%] Completed 'googletest' [100%] Built target googletest -- Configuring done -- Generating done -- Build files have been written to: /Users/ham/Desktop/cpp/build [ 50%] Built target FooBug [ 50%] Built target gtest [ 75%] Built target gtest_main Scanning dependencies of target tests [ 87%] Building CXX object CMakeFiles/tests.dir/test/FooTest.cpp.o [100%] Linking CXX executable tests ================================================================= ==28828==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000002bc at pc 0x0001085d2ba3 bp 0x7ffee7893e40 sp 0x7ffee7893608 READ of size 16 at 0x6020000002bc thread T0 #0 0x1085d2ba2 in __asan_memcpy (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x43ba2) #1 0x10838efdf in std::__1::enable_if<((std::__1::integral_constant::value) || (!(__has_construct, bool*, bool>::value))) && (is_trivially_move_constructible::value), void>::type std::__1::allocator_traits >::__construct_backward(std::__1::allocator&, bool*, bool*, bool*&) memory:1699 #2 0x10838e570 in std::__1::vector >::__swap_out_circular_buffer(std::__1::__split_buffer&>&) vector:937 #3 0x1083e3acb in void std::__1::vector >::__push_back_slow_path(int&&) vector:1621 #4 0x1083aacd9 in std::__1::vector >::push_back(int&&) vector:1658 #5 0x1083aab5e in testing::TestSuite::AddTestInfo(testing::TestInfo*) gtest.cc:2994 #6 0x1083a95d3 in testing::internal::UnitTestImpl::AddTestInfo(void (*)(), void (*)(), testing::TestInfo*) gtest-internal-inl.h:700 #7 0x1083a93c3 in testing::internal::MakeAndRegisterTestInfo(char const*, char const*, char const*, char const*, testing::internal::CodeLocation, void const*, void (*)(), void (*)(), testing::internal::TestFactoryBase*) gtest.cc:2769 #8 0x10839985f in __cxx_global_var_init.9 FooTest.cpp:18 #9 0x108399a58 in _GLOBAL__sub_I_FooTest.cpp FooTest.cpp #10 0x1139491e2 in ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) (dyld:x86_64+0x1b1e2) #11 0x1139495ed in ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (dyld:x86_64+0x1b5ed) #12 0x11394400a in ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (dyld:x86_64+0x1600a) #13 0x113942013 in ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (dyld:x86_64+0x14013) #14 0x1139420b3 in ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) (dyld:x86_64+0x140b3) #15 0x1139305e5 in dyld::initializeMainExecutable() (dyld:x86_64+0x25e5) #16 0x113935af7 in dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) (dyld:x86_64+0x7af7) #17 0x11392f226 in dyldbootstrap::start(dyld3::MachOLoaded const*, int, char const**, dyld3::MachOLoaded const*, unsigned long*) (dyld:x86_64+0x1226) #18 0x11392f024 in _dyld_start (dyld:x86_64+0x1024)
0x6020000002c0 is located 0 bytes to the right of 16-byte region [0x6020000002b0,0x6020000002c0) allocated by thread T0 here: #0 0x1085e0fdd in wrap__Znwm (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x51fdd) #1 0x108376648 in std::__1::__libcpp_allocate(unsigned long, unsigned long) new:253 #2 0x10838ed67 in std::__1::allocator::allocate(unsigned long, void const*) memory:1813 #3 0x10838ebc0 in std::__1::allocator_traits<std::__1::allocator >::allocate(std::__1::allocator&, unsigned long) memory:1546 #4 0x10838e96f in std::__1::__split_buffer<int, std::__1::allocator&>::__split_buffer(unsigned long, unsigned long, std::__1::allocator&) __split_buffer:311 #5 0x10838e49c in std::__1::__split_buffer<int, std::__1::allocator&>::__split_buffer(unsigned long, unsigned long, std::__1::allocator&) __split_buffer:310 #6 0x1083e3a7c in void std::__1::vector<int, std::__1::allocator >::__push_back_slow_path(int&&) vector:1617 #7 0x1083aacd9 in std::__1::vector<int, std::__1::allocator >::push_back(int&&) vector:1658 #8 0x1083aab5e in testing::TestSuite::AddTestInfo(testing::TestInfo*) gtest.cc:2994 #9 0x1083a95d3 in testing::internal::UnitTestImpl::AddTestInfo(void ()(), void ()(), testing::TestInfo*) gtest-internal-inl.h:700 #10 0x1083a93c3 in testing::internal::MakeAndRegisterTestInfo(char const*, char const*, char const*, char const*, testing::internal::CodeLocation, void const*, void ()(), void ()(), testing::internal::TestFactoryBase*) gtest.cc:2769 #11 0x1083990ff in __cxx_global_var_init.5 FooTest.cpp:13 #12 0x108399a4e in _GLOBAL__sub_I_FooTest.cpp FooTest.cpp #13 0x1139491e2 in ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) (dyld:x86_64+0x1b1e2) #14 0x1139495ed in ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (dyld:x86_64+0x1b5ed) #15 0x11394400a in ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (dyld:x86_64+0x1600a) #16 0x113942013 in ImageLoader::processInitializers(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (dyld:x86_64+0x14013) #17 0x1139420b3 in ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) (dyld:x86_64+0x140b3) #18 0x1139305e5 in dyld::initializeMainExecutable() (dyld:x86_64+0x25e5) #19 0x113935af7 in dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) (dyld:x86_64+0x7af7) #20 0x11392f226 in dyldbootstrap::start(dyld3::MachOLoaded const*, int, char const**, dyld3::MachOLoaded const*, unsigned long*) (dyld:x86_64+0x1226) #21 0x11392f024 in _dyld_start (dyld:x86_64+0x1024)
SUMMARY: AddressSanitizer: heap-buffer-overflow (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x43ba2) in __asan_memcpy Shadow bytes around the buggy address: 0x1c0400000000: fa fa fd fd fa fa 00 00 fa fa 00 03 fa fa 00 02 0x1c0400000010: fa fa 00 04 fa fa 00 00 fa fa 00 06 fa fa 00 fa 0x1c0400000020: fa fa 00 00 fa fa 00 fa fa fa 00 fa fa fa 00 fa 0x1c0400000030: fa fa 00 fa fa fa 00 fa fa fa 04 fa fa fa fd fa 0x1c0400000040: fa fa fd fa fa fa 00 fa fa fa fd fd fa fa fd fa =>0x1c0400000050: fa fa 00 fa fa fa 00[04]fa fa 00 fa fa fa 00 fa 0x1c0400000060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x1c0400000070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x1c0400000080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x1c0400000090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x1c04000000a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==28828==ABORTING CMake Error at /usr/local/Cellar/cmake/3.17.2/share/cmake/Modules/GoogleTestAddTests.cmake:40 (message): Error running test executable.
Path: '/Users/ham/Desktop/cpp/build/tests' Result: Child aborted Output:
make[2]: *** [tests] Error 1 make[2]: *** Deleting file `tests' make[1]: *** [CMakeFiles/tests.dir/all] Error 2 make: *** [all] Error 2
As written out in comments in the Footest.cpp
file, you can stop the issue from occurring if you do at least one of the following:
- Comment out the line that adds the
-fsanitize=address
compiler flag for thetests
executable. - Comment out at least one of the test cases so that only 4 (or fewer) remain in total.
- Comment out the line in the tests that tries to get the json value as a
vector of
int
s.
You can see in Footest.cpp
that using nlohmann/json with a vector of double
s is fine. It's only when a vector of int
s are used that the heap buffer overflow occurs.
The only thing I could find that seems at all similar is this issue: google/googletest#487