Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<system_error>: heap-use-after-free for _HAS_EXCEPTIONS=0 #5276

Open
StephanTLavavej opened this issue Feb 12, 2025 · 0 comments
Open

<system_error>: heap-use-after-free for _HAS_EXCEPTIONS=0 #5276

StephanTLavavej opened this issue Feb 12, 2025 · 0 comments
Labels
bug Something isn't working

Comments

@StephanTLavavej
Copy link
Member

Extracted from #5275 to simplify discussion. Thanks to @fredemmott for the report. Repros with VS 2022 17.14 Preview 1 x64.

C:\Temp>type woof.cpp
#include <cstdio>
#include <string>
#include <system_error>
using namespace std;

int main() {
    string str{"abc"};
    error_code ec{2, system_category()};
    system_error syserr{ec, str};

    printf("%s\n", syserr.what());
}
C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /MTd /Od woof.cpp && woof
woof.cpp
abc: The system cannot find the file specified.

C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /MTd /Od /Zi /fsanitize=address woof.cpp && woof
woof.cpp
abc: The system cannot find the file specified.

C:\Temp>cl /EHsc /nologo /W4 /std:c++latest /MTd /Od /Zi /fsanitize=address /D_HAS_EXCEPTIONS=0 woof.cpp && woof
woof.cpp
=================================================================
==9800==ERROR: AddressSanitizer: heap-use-after-free on address 0x11e3947a0690 at pc 0x7ffca0fb1eb6 bp 0x00c75e1bedf0 sp 0x00c75e1be590
READ of size 2 at 0x11e3947a0690 thread T0
Click to expand more ASan error info:
    #0 0x7ffca0fb1eb5 in strnlen D:\a\_work\1\s\src\vctools\asan\llvm\compiler-rt\lib\sanitizer_common\sanitizer_common_interceptors.inc:439
    #1 0x7ff608296767 in __crt_stdio_output::output_processor<char, class __crt_stdio_output::stream_output_adapter<char>, class __crt_stdio_output::standard_base<char, class __crt_stdio_output::stream_output_adapter<char>>>::type_case_s_compute_narrow_string_length(int, char) minkernel\crts\ucrt\inc\corecrt_internal_stdio_output.h:2353
    #2 0x7ff608295ca1 in __crt_stdio_output::output_processor<char, class __crt_stdio_output::stream_output_adapter<char>, class __crt_stdio_output::standard_base<char, class __crt_stdio_output::stream_output_adapter<char>>>::type_case_s(void) minkernel\crts\ucrt\inc\corecrt_internal_stdio_output.h:2340
    #3 0x7ff608289f51 in __crt_stdio_output::output_processor<char, class __crt_stdio_output::stream_output_adapter<char>, class __crt_stdio_output::standard_base<char, class __crt_stdio_output::stream_output_adapter<char>>>::state_case_type(void) minkernel\crts\ucrt\inc\corecrt_internal_stdio_output.h:2066
    #4 0x7ff60828069e in __crt_stdio_output::output_processor<char, class __crt_stdio_output::stream_output_adapter<char>, class __crt_stdio_output::standard_base<char, class __crt_stdio_output::stream_output_adapter<char>>>::process(void) minkernel\crts\ucrt\inc\corecrt_internal_stdio_output.h:1704
    #5 0x7ff60827c628 in <lambda_303760bc4008a2b3ec4768a30b06a80c>::operator() minkernel\crts\ucrt\src\appcrt\stdio\output.cpp:48
    #6 0x7ff60825dfe4 in __crt_seh_guarded_call<int>::operator()<<lambda_d854c62834386a3b23916ad6dae2782d>,<lambda_303760bc4008a2b3ec4768a30b06a80c> &,<lambda_4780a7ea4f8cbd2590aec34bd14e2bbf> > VCCRT\vcruntime\inc\internal_shared.h:204
    #7 0x7ff60825e0b7 in __acrt_lock_stream_and_call<<lambda_303760bc4008a2b3ec4768a30b06a80c> > minkernel\crts\ucrt\inc\corecrt_internal_stdio.h:297
    #8 0x7ff60825edd9 in common_vfprintf<__crt_stdio_output::standard_base,char> minkernel\crts\ucrt\src\appcrt\stdio\output.cpp:37
    #9 0x7ff60829e64b in __stdio_common_vfprintf minkernel\crts\ucrt\src\appcrt\stdio\output.cpp:61
    #10 0x7ff60823a594 in _vfprintf_l C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\ucrt\stdio.h:645
    #11 0x7ff60823a5f1 in printf C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\ucrt\stdio.h:960
    #12 0x7ff6082312a1 in main C:\Temp\woof.cpp:11
    #13 0x7ff60823d9d8 in invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #14 0x7ff60823d8f1 in __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #15 0x7ff60823d7ad in __scrt_common_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:330
    #16 0x7ff60823da4d in mainCRTStartup D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:16
    #17 0x7ffd2c2ce8d6  (C:\WINDOWS\System32\KERNEL32.DLL+0x18002e8d6)
    #18 0x7ffd2e13bf2b  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x1800bbf2b)

0x11e3947a0690 is located 0 bytes inside of 48-byte region [0x11e3947a0690,0x11e3947a06c0)
freed by thread T0 here:
    #0 0x7ff60823d303 in operator delete(void *, unsigned __int64) D:\a\_work\1\s\src\vctools\asan\llvm\compiler-rt\lib\asan\asan_win_delete_scalar_size_thunk.cpp:41
    #1 0x7ff608232dc0 in std::_Deallocate<16>(void *, unsigned __int64) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xmemory:289
    #2 0x7ff6082392c7 in std::allocator<char>::deallocate(char *const, unsigned __int64) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xmemory:981
    #3 0x7ff608236aec in std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>::_Deallocate_for_capacity(class std::allocator<char> &, char *const, unsigned __int64) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xstring:830
    #4 0x7ff60823865b in std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>::_Tidy_deallocate(void) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xstring:3052
    #5 0x7ff608235432 in std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>::~basic_string<char, struct std::char_traits<char>, class std::allocator<char>>(void) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xstring:1361
    #6 0x7ff6082349d9 in std::_System_error::_System_error(class std::error_code, class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>> const &) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\system_error:476
    #7 0x7ff6082351c7 in std::system_error::system_error(class std::error_code, class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>> const &) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\system_error:488
    #8 0x7ff608231285 in main C:\Temp\woof.cpp:9
    #9 0x7ff60823d9d8 in invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #10 0x7ff60823d8f1 in __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #11 0x7ff60823d7ad in __scrt_common_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:330
    #12 0x7ff60823da4d in mainCRTStartup D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:16
    #13 0x7ffd2c2ce8d6  (C:\WINDOWS\System32\KERNEL32.DLL+0x18002e8d6)
    #14 0x7ffd2e13bf2b  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x1800bbf2b)

previously allocated by thread T0 here:
    #0 0x7ff60823d1e5 in operator new(unsigned __int64) D:\a\_work\1\s\src\vctools\asan\llvm\compiler-rt\lib\asan\asan_win_new_scalar_thunk.cpp:40
    #1 0x7ff608236182 in std::_Default_allocate_traits::_Allocate(unsigned __int64) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xmemory:136
    #2 0x7ff60823162d in std::_Allocate<16, struct std::_Default_allocate_traits>(unsigned __int64) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xmemory:256
    #3 0x7ff60823885f in std::allocator<char>::allocate(unsigned __int64) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xmemory:986
    #4 0x7ff6082316b6 in std::_Allocate_at_least_helper<class std::allocator<char>>(class std::allocator<char> &, unsigned __int64 &) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xmemory:2287
    #5 0x7ff6082317af in std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>::_Allocate_for_capacity<0>(class std::allocator<char> &, unsigned __int64 &) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xstring:807
    #6 0x7ff6082331f1 in std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>::_Reallocate_grow_by<class `public: class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>> & __cdecl std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>::append(char const *const, unsigned __int64)'::`2'::<lambda_1>, char const *, unsigned __int64>(unsigned __int64, class `public: class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>> & __cdecl std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>::append(char const *const, unsigned __int64)'::`2'::<lambda_1>, char const *, unsigned __int64) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xstring:3003
    #7 0x7ff608238d67 in std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>::append(char const *const, unsigned __int64) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xstring:1500
    #8 0x7ff60823893b in std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>::append(class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>> const &) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\xstring:1461
    #9 0x7ff608236e38 in std::_System_error::_Makestr(class std::error_code, class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\system_error:468
    #10 0x7ff60823499e in std::_System_error::_System_error(class std::error_code, class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>> const &) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\system_error:476
    #11 0x7ff6082351c7 in std::system_error::system_error(class std::error_code, class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>> const &) C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.44.34823\include\system_error:488
    #12 0x7ff608231285 in main C:\Temp\woof.cpp:9
    #13 0x7ff60823d9d8 in invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #14 0x7ff60823d8f1 in __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #15 0x7ff60823d7ad in __scrt_common_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:330
    #16 0x7ff60823da4d in mainCRTStartup D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:16
    #17 0x7ffd2c2ce8d6  (C:\WINDOWS\System32\KERNEL32.DLL+0x18002e8d6)
    #18 0x7ffd2e13bf2b  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x1800bbf2b)

SUMMARY: AddressSanitizer: heap-use-after-free minkernel\crts\ucrt\inc\corecrt_internal_stdio_output.h:2353 in __crt_stdio_output::output_processor<char, class __crt_stdio_output::stream_output_adapter<char>, class __crt_stdio_output::standard_base<char, class __crt_stdio_output::stream_output_adapter<char>>>::type_case_s_compute_narrow_string_length(int, char)
Shadow bytes around the buggy address:
  0x11e3947a0400: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 05
  0x11e3947a0480: fa fa 00 00 00 00 00 06 fa fa 00 00 00 00 00 00
  0x11e3947a0500: fa fa 00 00 00 00 00 02 fa fa 00 00 00 00 02 fa
  0x11e3947a0580: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 01
  0x11e3947a0600: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
=>0x11e3947a0680: fa fa[fd]fd fd fd fd fd fa fa fd fd fd fd fd fa
  0x11e3947a0700: fa fa fd fd fd fd fd fd fa fa fa fa fa fa fa fa
  0x11e3947a0780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x11e3947a0800: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x11e3947a0880: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x11e3947a0900: 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
==9800==ABORTING
  • runtime_error(const string&) constructs its exception base from .c_str():
    • STL/stl/inc/stdexcept

      Lines 100 to 106 in d43d49a

      _EXPORT_STD class _NODISCARD runtime_error : public exception { // base of all runtime-error exceptions
      public:
      using _Mybase = exception;
      explicit runtime_error(const string& _Message) : _Mybase(_Message.c_str()) {}
      explicit runtime_error(const char* _Message) : _Mybase(_Message) {}
  • error_code::message() returns string:
  • _System_error::_Makestr() returns string:
    • STL/stl/inc/system_error

      Lines 461 to 463 in d43d49a

      class _NODISCARD _System_error : public runtime_error { // base of all system-error exceptions
      private:
      static string _Makestr(error_code _Errcode, string _Message) { // compose error message
  • So _System_error has multiple constructors sending string to its runtime_error base:
    • STL/stl/inc/system_error

      Lines 473 to 476 in d43d49a

      _System_error(error_code _Errcode) : runtime_error(_Errcode.message()), _Mycode(_Errcode) {}
      _System_error(error_code _Errcode, const string& _Message)
      : runtime_error(_Makestr(_Errcode, _Message)), _Mycode(_Errcode) {}

This is normally fine, as std::exception will copy the string contents.

However, in our quasi-supported, mostly-undocumented, mostly-untested _HAS_EXCEPTIONS=0 mode, std::exception is actually stdext::exception, which just STORES THE RAW POINTER 🙀 :

explicit __CLR_OR_THIS_CALL exception(const char* _Message = "unknown", int = 1) noexcept : _Ptr(_Message) {}

Therefore, the STL has a use-after-free bug whenever we construct exception, runtime_error, etc. from anything other than a string literal.

Notably, <regex> is fine:

STL/stl/inc/regex

Lines 466 to 479 in d43d49a

_EXPORT_STD class _NODISCARD regex_error : public runtime_error { // type of all regular expression exceptions
public:
explicit regex_error(regex_constants::error_type _Ex) : runtime_error(_Stringify(_Ex)), _Err(_Ex) {}
_NODISCARD regex_constants::error_type code() const noexcept /* strengthened */ {
return _Err;
}
private:
static const char* _Stringify(regex_constants::error_type _Ex) noexcept { // map error code to string
switch (_Ex) { // select known error_type message
case regex_constants::error_collate:
return "regex_error(error_collate): The expression "
"contained an invalid collating element name.";

I think what we need to do here is audit all STL exceptions, and anywhere we're using string like this, we need to special-case _HAS_EXCEPTIONS=0 to store a string literal (it's okay if it has far less info).

@StephanTLavavej StephanTLavavej added the bug Something isn't working label Feb 12, 2025
@StephanTLavavej StephanTLavavej marked this as a duplicate of #5275 Feb 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant