[Bug libstdc++/102592] New: heap-use-after-free when constructing std::filesystem::path from iterator pair

dean.gcc.bugzilla at gmail dot com gcc-bugzilla@gcc.gnu.org
Mon Oct 4 12:54:55 GMT 2021


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102592

            Bug ID: 102592
           Summary: heap-use-after-free when constructing
                    std::filesystem::path from iterator pair
           Product: gcc
           Version: 11.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dean.gcc.bugzilla at gmail dot com
  Target Milestone: ---

The std::filesystem::path constructor that takes an iterator pair produces a
heap-use-after-free error (address sanitizer) in case the iterators are
non-contiguous and value_type != char.

Full self-contained reproducible example on Compiler Explorer:
https://godbolt.org/z/3nxqq5Ef8 I've also included the reproduction code and
error below for completeness.

Affected versions: 11.x, trunk
Not affected: 10.x

As far as I've been able to track this in the std::filesystem::path
constructor, for the case of non-contiguous, non-char iterators, a temporary
container is created and then assigned to a std::string_view. However that temp
container has a shorter lifetime than the std::string_view.

The code:

#include <filesystem>

namespace fs = std::filesystem;

fs::path to_path(std::string_view sv) {
    struct AsU8 {
        std::string_view::const_iterator it;

        using iterator_category = std::forward_iterator_tag;
        using difference_type = std::ptrdiff_t;
        using value_type = char8_t;
        using reference = const value_type&;
        using pointer = const value_type*;

        char8_t operator*() const { return static_cast<char8_t>(*it); }
        AsU8& operator++() { return ++it, *this; }
        bool operator==(const AsU8&) const = default;
    };
    return {AsU8{sv.begin()}, AsU8{sv.end()}};
}

int main() {
    return
to_path("/long/path/to/a/file/to/avoid/small/string/opt").string().size();
}

=1==ERROR: AddressSanitizer: heap-use-after-free on address 0x604000000010 at
pc 0x7fed85f999c0 bp 0x7ffdddc9ccc0 sp 0x7ffdddc9c470
READ of size 46 at 0x604000000010 thread T0
    #0 0x7fed85f999bf in __interceptor_memcpy
(/opt/compiler-explorer/gcc-11.2.0/lib64/libasan.so.6+0x3c9bf)
    #1 0x4039e5 in std::char_traits<char>::copy(char*, char const*, unsigned
long)
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/char_traits.h:409
    #2 0x405214 in std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> >::_S_copy(char*, char const*, unsigned long)
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:359
    #3 0x4058f1 in std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> >::_S_copy_chars(char*, char const*, char const*)
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:406
    #4 0x405109 in void std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char
const*, char const*, std::forward_iterator_tag)
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.tcc:225
    #5 0x40578b in void std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >::_M_construct_aux<char
const*>(char const*, char const*, std::__false_type)
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:255
    #6 0x404a8e in void std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char
const*, char const*)
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:274
    #7 0x404119 in std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> >::basic_string(char const*, unsigned long,
std::allocator<char> const&)
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:521
    #8 0x404e66 in std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> >::basic_string(std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >::__sv_wrapper,
std::allocator<char> const&)
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:154
    #9 0x404373 in std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> >::basic_string<std::basic_string_view<char,
std::char_traits<char> >, void>(std::basic_string_view<char,
std::char_traits<char> > const&, std::allocator<char> const&)
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/basic_string.h:664
    #10 0x402c63 in path<to_path(std::string_view)::AsU8>
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/fs_path.h:292
    #11 0x4024ae in to_path[abi:cxx11](std::basic_string_view<char,
std::char_traits<char> >) /app/example.cpp:19
    #12 0x40265c in main /app/example.cpp:23
    #13 0x7fed85a140b2 in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #14 0x40226d in _start (/app/output.s+0x40226d)


More information about the Gcc-bugs mailing list