-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
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 itsexceptionbase from.c_str():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()returnsstring:Line 206 in d43d49a
_NODISCARD string message() const {
_System_error::_Makestr()returnsstring: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_errorhas multiple constructors sendingstringto itsruntime_errorbase: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 🙀 :
Line 96 in d43d49a
| 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:
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).