Skip to content

heap-use-after-free w/ range erase for unordered_multiset #167820

@rupprecht

Description

@rupprecht

The following fails w/ asan after #162850

Repro flags: -fsanitize=address -stdlib=libc++

#include <cassert>
#include <unordered_set>

int main() {
    std::unordered_multiset<int> m;
    m.emplace(1);
    m.emplace(2);

    {
        auto [it, end] = m.equal_range(1);
        assert(it != end);
        m.erase(it, end);
    }

    {
        auto [it, end] = m.equal_range(2);
        assert(it != end);
        m.erase(it, end);
    }

    m.emplace(3);  // heap-use-after-free
}

Logs:

=================================================================
==1==ERROR: AddressSanitizer: heap-use-after-free on address 0x6c91059e0070 at pc 0x64ccbcb103d9 bp 0x7ffd2db8e6b0 sp 0x7ffd2db8e6a8
READ of size 8 at 0x6c91059e0070 thread T0
    #0 0x64ccbcb103d8 in std::__1::__hash_table<int, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<int>>::__node_insert_multi_prepare(unsigned long, int&) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__hash_table:1508:16
    #1 0x64ccbcb0f7de in std::__1::__hash_table<int, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<int>>::__node_insert_multi(std::__1::__hash_node<int, void*>*) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__hash_table:1561:25
    #2 0x64ccbcb0f111 in std::__1::__hash_iterator<std::__1::__hash_node<int, void*>*> std::__1::__hash_table<int, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<int>>::__emplace_multi<int>(int&&) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__hash_table:1596:23
    #3 0x64ccbcb0e418 in std::__1::__hash_const_iterator<std::__1::__hash_node<int, void*>*> std::__1::unordered_multiset<int, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<int>>::emplace[abi:se220000]<int>(int&&) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/unordered_set:1343:21
    #4 0x64ccbcb0e135 in main /app/example.cpp:21:7
    #5 0x706106629d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: d5197096f709801829b118af1b7cf6631efa2dcd)
    #6 0x706106629e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f) (BuildId: d5197096f709801829b118af1b7cf6631efa2dcd)
    #7 0x64ccbca243e4 in _start (/app/output.s+0x2d3e4)

0x6c91059e0070 is located 0 bytes inside of 24-byte region [0x6c91059e0070,0x6c91059e0088)
freed by thread T0 here:
    #0 0x64ccbcb0d462 in operator delete(void*, unsigned long) /root/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:190:3
    #1 0x64ccbcb0edf2 in void std::__1::__libcpp_deallocate[abi:se220000]<std::__1::__hash_node<int, void*>>(std::__1::__type_identity<std::__1::__hash_node<int, void*>>::type*, std::__1::__element_count, unsigned long) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__new/allocate.h:63:10
    #2 0x64ccbcb0ed95 in std::__1::allocator<std::__1::__hash_node<int, void*>>::deallocate[abi:se220000](std::__1::__hash_node<int, void*>*, unsigned long) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__memory/allocator.h:120:7
    #3 0x64ccbcb0ed24 in std::__1::allocator_traits<std::__1::allocator<std::__1::__hash_node<int, void*>>>::deallocate[abi:se220000](std::__1::allocator<std::__1::__hash_node<int, void*>>&, std::__1::__hash_node<int, void*>*, unsigned long) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__memory/allocator_traits.h:289:9
    #4 0x64ccbcb0ec17 in std::__1::__hash_table<int, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<int>>::__deallocate_node[abi:se220000](std::__1::__hash_node<int, void*>*) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__hash_table:1032:5
    #5 0x64ccbcb12cc5 in std::__1::__hash_table<int, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<int>>::erase(std::__1::__hash_const_iterator<std::__1::__hash_node<int, void*>*>, std::__1::__hash_const_iterator<std::__1::__hash_node<int, void*>*>) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__hash_table:1901:5
    #6 0x64ccbcb0e7ff in std::__1::unordered_multiset<int, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<int>>::erase[abi:se220000](std::__1::__hash_const_iterator<std::__1::__hash_node<int, void*>*>, std::__1::__hash_const_iterator<std::__1::__hash_node<int, void*>*>) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/unordered_set:1422:21
    #7 0x64ccbcb0e0fa in main /app/example.cpp:18:11
    #8 0x706106629d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: d5197096f709801829b118af1b7cf6631efa2dcd)

previously allocated by thread T0 here:
    #0 0x64ccbcb0c85d in operator new(unsigned long) /root/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:109:35
    #1 0x64ccbcb0fcda in std::__1::__hash_node<int, void*>* std::__1::__libcpp_allocate[abi:se220000]<std::__1::__hash_node<int, void*>>(std::__1::__element_count, unsigned long) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__new/allocate.h:43:28
    #2 0x64ccbcb0fc24 in std::__1::allocator<std::__1::__hash_node<int, void*>>::allocate[abi:se220000](unsigned long) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__memory/allocator.h:105:14
    #3 0x64ccbcb0f94c in std::__1::allocator_traits<std::__1::allocator<std::__1::__hash_node<int, void*>>>::allocate[abi:se220000](std::__1::allocator<std::__1::__hash_node<int, void*>>&, unsigned long) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__memory/allocator_traits.h:259:16
    #4 0x64ccbcb0f3e0 in std::__1::unique_ptr<std::__1::__hash_node<int, void*>, std::__1::__hash_node_destructor<std::__1::allocator<std::__1::__hash_node<int, void*>>>> std::__1::__hash_table<int, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<int>>::__construct_node<int>(int&&) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__hash_table:1823:21
    #5 0x64ccbcb0f0fc in std::__1::__hash_iterator<std::__1::__hash_node<int, void*>*> std::__1::__hash_table<int, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<int>>::__emplace_multi<int>(int&&) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/__hash_table:1595:23
    #6 0x64ccbcb0e418 in std::__1::__hash_const_iterator<std::__1::__hash_node<int, void*>*> std::__1::unordered_multiset<int, std::__1::hash<int>, std::__1::equal_to<int>, std::__1::allocator<int>>::emplace[abi:se220000]<int>(int&&) /cefs/8d/8d2fd574113d33adba235562_clang-assertions-trunk-20251112/bin/../include/c++/v1/unordered_set:1343:21
    #7 0x64ccbcb0dde9 in main /app/example.cpp:7:7
    #8 0x706106629d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f) (BuildId: d5197096f709801829b118af1b7cf6631efa2dcd)

Live link: https://compiler-explorer.com/z/PoPx6Wa5G

Metadata

Metadata

Assignees

Labels

libc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions