abseil/abseil-cpp

[Bug]: SIGSEGV from absl::flat_hash_map::insert()

Closed this issue · 4 comments

Describe the issue

We are using absl::flat_hash_map in our code base. When our operator new throws an exception at the wrong time in absl::flat_hash_map::insert(), the program exits with SIGSEGV (or SIGABRT, depending on your malloc implementation). Since abseil gives the basic exception guarantee, this should not happen.

Steps to reproduce the problem

Here is a reproduction on godbolt.org: https://godbolt.org/z/WaYG7hqjj

This is the minimal reproduction of the problem:

#include <absl/container/flat_hash_map.h>

void * operator new(std::size_t size) {
    throw std::bad_alloc{};
}

// Exits with SIGSEGV
int main(int, char **) {
    try {
        absl::flat_hash_map<int, int> m;
        m.insert({42, 42});
    } catch (const std::bad_alloc &) {}
    return 0;
}

What version of Abseil are you using?

lts_2023_01_25
The godbolt reproduction uses trunk.

What operating system and version are you using?

Ubuntu 22.04.3 LTS

What compiler and version are you using?

Ubuntu clang version 14.0.6
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/11
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/11
Candidate multilib: .;@m64
Selected multilib: .;@m64

What build system are you using?

CMake or whatever godbolt is using

Additional context

No response

I think this might be the same issue that I have been observing: when trying to run asan even on the most simple flat_hash_map insertion, asan flags a DEADLYSIGNAL and dies. In my case, though, when running the executable normally I don't see any failures.

I'm using the following test program:

#include <absl/container/flat_hash_map.h>

int main(int argc, char const *argv[]) {
  absl::flat_hash_map<int, int> lengths;
  // try_emplace fails in the exact same way
  lengths[99] = 1;
  return 0;
}

I build this with the following cmakelists file:

cmake_minimum_required(VERSION 3.10)

project(memissue)

set(CMAKE_CXX_STANDARD 17)

add_subdirectory(abseil-cpp) # 20230125.3

add_executable(absl_issue absl_issue.cpp)

target_link_libraries(absl_issue absl::flat_hash_map)

target_compile_options(absl_issue PRIVATE -fsanitize=address)
target_link_options(absl_issue PRIVATE -fsanitize=address)

Building and running the executable with both Apple clang 14.0.3.14030022 (XCode 14.3.1) on an Intel MacBook Pro and gcc 11.3.0 on CentOS7 results in the following error (this one is from the Mac):

$ MallocNanoZone=0 ./build/absl_issue
AddressSanitizer:DEADLYSIGNAL
=================================================================
==61051==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x00010668a4f1 bp 0x7ff7b987b4f0 sp 0x7ff7b987b4a0 T0)
==61051==The signal is caused by a READ memory access.
==61051==Hint: address points to the zero page.
    #0 0x10668a4f1 in absl::lts_20230125::container_internal::GroupSse2Impl::GroupSse2Impl(absl::lts_20230125::container_internal::ctrl_t const*)+0xc1 (absl_issue:x86_64+0x1000084f1) (BuildId: 0b2a619aee3f3ee2a6fb871b56e68962320000002000000001000000000f0a00)
    #1 0x106688bdc in absl::lts_20230125::container_internal::GroupSse2Impl::GroupSse2Impl(absl::lts_20230125::container_internal::ctrl_t const*)+0x1c (absl_issue:x86_64+0x100006bdc) (BuildId: 0b2a619aee3f3ee2a6fb871b56e68962320000002000000001000000000f0a00)
    #2 0x1066947ac in absl::lts_20230125::container_internal::FindInfo absl::lts_20230125::container_internal::find_first_non_full<void>(absl::lts_20230125::container_internal::CommonFields const&, unsigned long)+0x4c (absl_issue:x86_64+0x1000127ac) (BuildId: 0b2a619aee3f3ee2a6fb871b56e68962320000002000000001000000000f0a00)
    #3 0x106689b99 in absl::lts_20230125::container_internal::raw_hash_set<absl::lts_20230125::container_internal::FlatHashMapPolicy<int, int>, absl::lts_20230125::hash_internal::Hash<int>, std::__1::equal_to<int>, std::__1::allocator<std::__1::pair<int const, int>>>::prepare_insert(unsigned long)+0x1f9 (absl_issue:x86_64+0x100007b99) (BuildId: 0b2a619aee3f3ee2a6fb871b56e68962320000002000000001000000000f0a00)
    #4 0x1066881a9 in std::__1::pair<unsigned long, bool> absl::lts_20230125::container_internal::raw_hash_set<absl::lts_20230125::container_internal::FlatHashMapPolicy<int, int>, absl::lts_20230125::hash_internal::Hash<int>, std::__1::equal_to<int>, std::__1::allocator<std::__1::pair<int const, int>>>::find_or_prepare_insert<int>(int const&)+0x849 (absl_issue:x86_64+0x1000061a9) (BuildId: 0b2a619aee3f3ee2a6fb871b56e68962320000002000000001000000000f0a00)
    #5 0x1066876a2 in std::__1::pair<absl::lts_20230125::container_internal::raw_hash_set<absl::lts_20230125::container_internal::FlatHashMapPolicy<int, int>, absl::lts_20230125::hash_internal::Hash<int>, std::__1::equal_to<int>, std::__1::allocator<std::__1::pair<int const, int>>>::iterator, bool> absl::lts_20230125::container_internal::raw_hash_map<absl::lts_20230125::container_internal::FlatHashMapPolicy<int, int>, absl::lts_20230125::hash_internal::Hash<int>, std::__1::equal_to<int>, std::__1::allocator<std::__1::pair<int const, int>>>::try_emplace_impl<int>(int&&)+0x152 (absl_issue:x86_64+0x1000056a2) (BuildId: 0b2a619aee3f3ee2a6fb871b56e68962320000002000000001000000000f0a00)
    #6 0x106686fd3 in std::__1::pair<absl::lts_20230125::container_internal::raw_hash_set<absl::lts_20230125::container_internal::FlatHashMapPolicy<int, int>, absl::lts_20230125::hash_internal::Hash<int>, std::__1::equal_to<int>, std::__1::allocator<std::__1::pair<int const, int>>>::iterator, bool> absl::lts_20230125::container_internal::raw_hash_map<absl::lts_20230125::container_internal::FlatHashMapPolicy<int, int>, absl::lts_20230125::hash_internal::Hash<int>, std::__1::equal_to<int>, std::__1::allocator<std::__1::pair<int const, int>>>::try_emplace<int, 0, (int*)0>(int&&)+0x23 (absl_issue:x86_64+0x100004fd3) (BuildId: 0b2a619aee3f3ee2a6fb871b56e68962320000002000000001000000000f0a00)
    #7 0x106685220 in decltype(absl::lts_20230125::container_internal::FlatHashMapPolicy<int, int>::value(std::__1::pair<int const, int>* std::__1::addressof[abi:v15006]<std::__1::pair<int const, int>>(std::__1::pair<int const, int>&)(decltype(__declval<std::__1::pair<int const, int>>(0)) std::__1::declval<std::__1::pair<int const, int>&>()()))) absl::lts_20230125::container_internal::raw_hash_map<absl::lts_20230125::container_internal::FlatHashMapPolicy<int, int>, absl::lts_20230125::hash_internal::Hash<int>, std::__1::equal_to<int>, std::__1::allocator<std::__1::pair<int const, int>>>::operator[]<int, absl::lts_20230125::container_internal::FlatHashMapPolicy<int, int>, (int*)0>(int&&)+0xf0 (absl_issue:x86_64+0x100003220) (BuildId: 0b2a619aee3f3ee2a6fb871b56e68962320000002000000001000000000f0a00)
    #8 0x106684f0d in main+0x16d (absl_issue:x86_64+0x100002f0d) (BuildId: 0b2a619aee3f3ee2a6fb871b56e68962320000002000000001000000000f0a00)
    #9 0x7ff8167ff41e in start+0x76e (dyld:x86_64+0xfffffffffff6e41e) (BuildId: 31e1c182e611388397a34334a21c90bd32000000200000000100000000050d00)

==61051==Register values:
rax = 0x00007ff7b987b540  rbx = 0x00007ff7b987b600  rcx = 0x0000000000000000  rdx = 0x0000000000000000  
rdi = 0x00007ff7b987b540  rsi = 0x0000000000000000  rbp = 0x00007ff7b987b4f0  rsp = 0x00007ff7b987b4a0  
 r8 = 0x0000000000000004   r9 = 0x0000000000000000  r10 = 0xffffffffffffffff  r11 = 0xfffffffffffffea0  
r12 = 0x00007ff7b987c0c8  r13 = 0x00007ff7b987c100  r14 = 0x00007ff7b987c110  r15 = 0x00007ff7b987bf90  
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (absl_issue:x86_64+0x1000084f1) (BuildId: 0b2a619aee3f3ee2a6fb871b56e68962320000002000000001000000000f0a00) in absl::lts_20230125::container_internal::GroupSse2Impl::GroupSse2Impl(absl::lts_20230125::container_internal::ctrl_t const*)+0xc1
==61051==ABORTING

@ricrogz - Your issue is probably stemming from not applying -fsanitize=address to the entire build. It looks like you are only applying it to absl_issue.cpp. This is going to create an ABI mismatch.

See also https://github.com/abseil/abseil-cpp/blob/master/FAQ.md#what-is-abi-and-why-dont-you-recommend-using-a-pre-compiled-version-of-abseil

We also encountered the same issue:

try {
    absl::flat_hash_set<int> set;
    set.reserve(std::numeric_limits<int64_t>::max());
} catch (std::exception &) {
}

When operator new(size_t) throws exeception, the program exits with SIGSEGV.
Are there any plans to fix this issue?

This appears to be a duplicate of #388, so I'll close it as that. Please let me know if I missed any difference.

(And per #388, as of this writing, it doesn't appear likely that these containers would be made exception-safe.)