<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/62074>62074</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[libc++][format][chrono] Problems with `chrono-specs` with short lifetime
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
JMazurkiewicz
</td>
</tr>
</table>
<pre>
Repro:
```c++
#include <chrono>
#include <format>
#include <iostream>
struct Midnight {};
template <> struct std::formatter<Midnight> {
private:
std::formatter<std::chrono::hours> underlying;
public:
constexpr auto parse(auto &ctx) {
const auto it = ctx.begin();
if (it != ctx.end() && *it != '}') {
throw std::format_error{"Format spec for Midnight should be empty"};
} else {
char spec[] = "%T %p"; // variable with automatic storage duration, not available after leaving this function
format_parse_context new_ctx{spec};
underlying.parse(new_ctx); // underlying keeps `string_view` pointing to `spec` automatic variable!
return it;
}
}
auto format(Midnight, auto &ctx) const {
return underlying.format(std::chrono::hours{0}, ctx); // sheesh!
}
};
int main() { std::cout << std::format("{}\n", Midnight{}); }
```
Build:
```console
PS D:\libcxx-playground> clang -std=c++2b -fexperimental-library -Iinclude\c++\v1 -llib\c++ "-llib\windows\clang_rt.builtins-x86_64" .\test.cpp
PS D:\libcxx-playground> .\a.exe
[garbage]
```
Currently libc++ [stores *`chrono-specs`* as `basic_string_view`](https://github.com/llvm/llvm-project/blob/32aaacc609e7a0523d498b244e081ac6f3df532b/libcxx/include/__chrono/parser_std_format_spec.h#L158), which means that it might become dangling in some pathological cases (like the one presented here).
Other builds:
<details>
<summary>Clang/libc++/ASAN/Windows</summary>
```console
PS D:\libcxx-playground> clang -std=c++2b -fexperimental-library -fsanitize=address -g -O2 -Iinclude\c++\v1 -llib\c++ "-llib\windows\clang_rt.builtins-x86_64" .\test.cpp
Creating library a.lib and object a.exp
PS D:\libcxx-playground> .\a.exe
=================================================================
==13728==ERROR: AddressSanitizer: stack-use-after-scope on address 0x00901cfeeab0 at pc 0x7ff795fd48b4 bp 0x00901cfedfa0 sp 0x00901cfedfe8
READ of size 1 at 0x00901cfeeab0 thread T0
#0 0x7ff795fd48b3 in std::__1::__formatter::__format_chrono_using_chrono_specs<char, class std::__1::chrono::duration<long, class std::__1::ratio<3600, 1>>>(class std::__1::chrono::duration<long, class std::__1::ratio<3600, 1>> const &, class std::__1::basic_stringstream<char, struct std::__1::char_traits<char>, class std::__1::allocator<char>> &, class std::__1::basic_string_view<char, struct std::__1::char_traits<char>>) D:\libcxx-playground\include\c++\v1\__chrono\formatter.h:179
#1 0x7ff795fd1275 in std::__1::__formatter::__format_chrono<char, class std::__1::chrono::duration<long, class std::__1::ratio<3600, 1>>, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char>>(class std::__1::chrono::duration<long, class std::__1::ratio<3600, 1>> const &, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char> &, struct std::__1::__format_spec::__parsed_specifications<char>, class std::__1::basic_string_view<char, struct std::__1::char_traits<char>>) D:\libcxx-playground\include\c++\v1\__chrono\formatter.h:510
#2 0x7ff795fcfd7f in std::__1::__formatter_chrono<char>::format D:\libcxx-playground\include\c++\v1\__chrono\formatter.h:576
#3 0x7ff795fcfd7f in std::__1::formatter<Midnight,char>::format D:\libcxx-playground\test.cpp:25
#4 0x7ff795fcfd7f in `public: __cdecl std::__1::__basic_format_arg_value<class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char>>::__handle::__handle<struct Midnight &>(struct Midnight &)'::`1'::<lambda_1>::operator()(class std::__1::basic_format_parse_context<char> &, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char> &, void const *) const D:\libcxx-playground\include\c++\v1\__format\format_arg.h:172
#5 0x7ff795fcf9cd in `public: __cdecl std::__1::__basic_format_arg_value<class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char>>::__handle::__handle<struct Midnight &>(struct Midnight &)'::`1'::<lambda_1>::__invoke(class std::__1::basic_format_parse_context<char> &, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char> &, void const *) D:\libcxx-playground\include\c++\v1\__format\format_arg.h:161
#6 0x7ff795fa5d3a in std::__1::basic_format_arg<std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char> >,char> >::handle::format D:\libcxx-playground\include\c++\v1\__format\format_arg.h:267
#7 0x7ff795fa5d3a in std::__1::__format::__handle_replacement_field<const char *,std::__1::basic_format_parse_context<char>,std::__1::basic_format_context<std::__1::back_insert_iterator<std::__1::__format::__output_buffer<char> >,char> >::<lambda_1>::operator() D:\libcxx-playground\include\c++\v1\__format\format_functions.h:279
#8 0x7ff795fa5d3a in std::__1::__invoke D:\libcxx-playground\include\c++\v1\__functional\invoke.h:394
#9 0x7ff795fa5d3a in std::__1::invoke D:\libcxx-playground\include\c++\v1\__functional\invoke.h:539
#10 0x7ff795fa5d3a in std::__1::__visit_format_arg<class `char const * __cdecl std::__1::__format::__handle_replacement_field<char const *, class std::__1::basic_format_parse_context<char>, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char>>(char const *, char const *, class std::__1::basic_format_parse_context<char> &, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char> &)'::`1'::<lambda_1>, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char>>(class `char const * __cdecl std::__1::__format::__handle_replacement_field<char const *, class std::__1::basic_format_parse_context<char>, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char>>(char const *, char const *, class std::__1::basic_format_parse_context<char> &, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char> &)'::`1'::<lambda_1> &&, class std::__1::basic_format_arg<class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char>>) D:\libcxx-playground\include\c++\v1\__format\format_arg.h:140
#11 0x7ff795fa4ced in std::__1::__format::__handle_replacement_field<char const *, class std::__1::basic_format_parse_context<char>, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char>>(char const *, char const *, class std::__1::basic_format_parse_context<char> &, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char> &) D:\libcxx-playground\include\c++\v1\__format\format_functions.h:274
#12 0x7ff795fa2080 in std::__1::__format::__vformat_to<class std::__1::basic_format_parse_context<char>, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char>>(class std::__1::basic_format_parse_context<char> &&, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char> &&) D:\libcxx-playground\include\c++\v1\__format\format_functions.h:314
#13 0x7ff795fa197d in std::__1::__vformat_to<class std::__1::back_insert_iterator<class std::__1::basic_string<char, struct std::__1::char_traits<char>, class std::__1::allocator<char>>>, char, class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>>(class std::__1::back_insert_iterator<class std::__1::basic_string<char, struct std::__1::char_traits<char>, class std::__1::allocator<char>>>, class std::__1::basic_string_view<char, struct std::__1::char_traits<char>>, class std::__1::basic_format_args<class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char>>) D:\libcxx-playground\include\c++\v1\__format\format_functions.h:405
#14 0x7ff795fa125e in std::__1::vformat_to D:\libcxx-playground\include\c++\v1\__format\format_functions.h:417
#15 0x7ff795fa125e in std::__1::vformat D:\libcxx-playground\include\c++\v1\__format\format_functions.h:450
#16 0x7ff795fa125e in std::__1::format D:\libcxx-playground\include\c++\v1\__format\format_functions.h:469
#17 0x7ff795fa125e in main D:\libcxx-playground\test.cpp:29
#18 0x7ff796027f1b in invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
#19 0x7ff796027f1b in __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
#20 0x7ffea8fb7603 (C:\WINDOWS\System32\KERNEL32.DLL+0x180017603)
#21 0x7ffea9a226a0 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x1800526a0)
Address 0x00901cfeeab0 is located in stack of thread T0 at offset 176 in frame
#0 0x7ff795fcfa1f in `public: __cdecl std::__1::__basic_format_arg_value<class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char>>::__handle::__handle<struct Midnight &>(struct Midnight &)'::`1'::<lambda_1>::operator()(class std::__1::basic_format_parse_context<char> &, class std::__1::basic_format_context<class std::__1::back_insert_iterator<class std::__1::__format::__output_buffer<char>>, char> &, void const *) const D:\libcxx-playground\include\c++\v1\__format\format_arg.h:161
This frame has 8 object(s):
[32, 48) 'agg.tmp.i.i'
[64, 80) 'agg.tmp2.i.i'
[96, 100) 'ref.tmp.i'
[112, 136) 'tmp.i'
[176, 182) 'spec.i' <== Memory access at offset 176 is inside this variable
[208, 248) 'new_ctx.i'
[288, 320) '__f' (line 170)
[352, 360) 'agg.tmp'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp, SEH and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope D:\libcxx-playground\include\c++\v1\__chrono\formatter.h:179 in std::__1::__formatter::__format_chrono_using_chrono_specs<char, class std::__1::chrono::duration<long, class std::__1::ratio<3600, 1>>>(class std::__1::chrono::duration<long, class std::__1::ratio<3600, 1>> const &, class std::__1::basic_stringstream<char, struct std::__1::char_traits<char>, class std::__1::allocator<char>> &, class std::__1::basic_string_view<char, struct std::__1::char_traits<char>>)
Shadow bytes around the buggy address:
0x00901cfee800: f2 f2 f8 f2 f2 f2 00 f2 f2 f2 00 00 f2 f2 04 f2
0x00901cfee880: f8 f8 f8 f2 f2 f2 f2 f2 00 00 f2 f2 00 00 f3 f3
0x00901cfee900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00901cfee980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00901cfeea00: f1 f1 f1 f1 00 00 f2 f2 00 00 f2 f2 04 f2 f8 f8
=>0x00901cfeea80: f8 f2 f2 f2 f2 f2[f8]f2 f2 f2 f8 f8 f8 f8 f8 f2
0x00901cfeeb00: f2 f2 f2 f2 00 00 00 00 f2 f2 f2 f2 00 f3 f3 f3
0x00901cfeeb80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00901cfeec00: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 01 f3 f3 f3
0x00901cfeec80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00901cfeed00: 00 00 00 00 f1 f1 f1 f1 f8 f8 f2 f2 f8 f8 f2 f2
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
==13728==ABORTING
```
</details>
<details>
<summary>Clang/STL/ASAN (correct behaviour, STL stores *`chrono-specs`* in `vector`)</summary>
```console
PS D:\libcxx-playground> clang -std=c++2b -fsanitize=address -g -O2 .\test.cpp
Creating library a.lib and object a.exp
PS D:\libcxx-playground> .\a.exe
00:00:00 AM
```
</details>
Compiler explorer: https://godbolt.org/z/hGK6456bY (this bug is present in libstdc++ too)
CC: @mordante
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsXFtzo7iz_zTKS1dcIAzGD3lwcLI75z-XrWRObe0TJUAYbQSiJOEk8-lPSVzt2DOeS1KT888W6wHRtH59lRDqEKXYpqL0AvmXyF-fkUYXQl78zwfypZF3jN6z9MtZIrLHixtaS4G8FXLWyOl_A6c9UoQvzdG2Yo9VKW8yCsiL0kKKSiDv6tDNXMiS6CM3mVBaUlKOt-2v0rJJNXxgWcU2hQa0uESLNfIup0SaljUn2vJB3hV0DymdGRG8VduxphJ5Uc_J0BlmlkEt2ZZoOgh8-NGhsZfSnBeikcowa6qMSv7Iqs0eurpJOEtH3pCKSmn6UEsgjRZQE6kowqG9QDhI9QPCyxEcQPdIS840IG8NqX6YJXTDKoRDhJdDn4aa5YBwaAix29PSKmspTRcIB4DwaqRAeGHUihdPegbQhRT3-xqJqZRCGkqMr20LqJqmkAs5GksVouEZJBRoWetHhPHUdoY3WqyBckX3-0wLIi3D1lOhxYgR9j8Dwn5tzr1LQPga4WvYEslIwincM11YLZVEsxSUFpJsKGSNJJqJCuEIKqGBbAnj9gGSayqBU7Jl1QZ0wRTkTZVa4gmcTmZrqTgVlaYPGip6HxtbLS4t0Klkoy_Meuv21NZUPfCRDu4orRWgwFFasmoTbxm9R4EDtWCVtuCEvWu6CpyJkL3wxpITyJLqRlbA9L6--4vhtG-w3tXFKA6HOMER7Hlm64w7Fut6m8g9MPpK1CwuHet1ETzRjCooVcUo04j2SfSzSkNJ-kAwuEZnTUWj26wQ7XuwJcddPvGjyrpXNDhvd6MDNfTe58ApgMuG8exoshSVEpy2rX_dwtoQ-hFnSfrwcF5z8riRoqkyk0JSTqoNnFug6y7L4gTOc_pQU8lKWmnCzzlLJJGPcP6uS5_Ij_qU7EdbF845Z8nYaAKnb7pnVSbulblp-oqlniUN45pV6vwhDOJgjjCGGfIjTZWepXV9EnDzAJnRh05M5F9uiEzIhiL_a4qLGilppfkjGK49Wv_SxC1VJkMZBVq3OTeOr8zzeAXEBkpCFEvj3XAx_eGw0LpWBq71pQ3TRZPMUlEifM35tv_nvJbiX5pqhK8TLhKErz1MCEnTwFnSBXF87GXzZZjg-Zw6oUvSIPey3PewIW3VgPB1bwN8Hcedh-NrG_QyVjqLu9Rh4M8KhL33rm_zNY7gvmBpASUllQJdEG1Se2kTZ0JTUVLISLXhJvZZBco01EQXgosNSwmHlCirpJCzOwq6oCAqCrWkilaaZlBQSRFezqYa_6QLKsGYPFP7HutFGdWEcTUOwV6kmrIk8hF5V5FxmE7yztvw9ep29RHh6787t_IihK_HR146IHJFKqbZF4q8NckySZWC8w2cf8IvGiwAEElKbNbusZEZZwmQKgORGKcDEy4_Flze-tUfE0Fcb4HD9vTq5ubTDfJWsGptd9tZU5o2pUl6d94oem7H7HOVitp4PPSGdh4cZ-m4aU4pSRwgGuoUnIdFni-Wfp7Nw2QOST0hy3LigNptoWGL7eZqtQaRg2JfKLiG2R57XUhKMvjsTMZW7Dm7HXo2cPthJ47d_mQyq5w2dAkkbpRJad1Fm_jM1JpIO1RyotQBrtPhdZjweBEXJmqPP2YJkRd5geMYOtfEbXvg8GX66icUZl56_OFpuu9fFQal7M_4J0iJjLUkTA86NJId74ZwLlKihZyQm1eF08G1Y9EPYzPwlscTgh8dTmTIj4YByI8GB5sVyFu5i-WOm7oTN3Xxwv8xN315n_ymAXp87QzdADxKnt7FrFJU6phpKnuDHyHvJe-vRKPrRsdJk-dU7tkugunVbxhCv5WSeshHgySezqD6Jju_ymwTy1lqlXdifP_ekeq7uwMKHiM1zbNF_s1I3YtNg3J85fnFWBfBDlbvJKwH12Lw96IdJlzeCvs7KOYHUKDAGRZhII7TjKb8oBp3AoTITbwlvKFfDZHfLqIGLcZxQaqM0_2r6MmaGg7aXHXohnlVWbQsUOC444UXcVImGYndoUdRdyK1S1LHk9-O2nZWVUapXnEy2wqWDRl5NS6Z_Fj4dUD68DN-2Y3qeMfz_annL9PszfNfzvPjmFVbcUfffH70-V_s7YG74-3B6O3EzzxyeLTZd-vpKv63tHqyPn9Yk9CqcnrVro5OvPenRu5jysTBYkeZi5OUuS9VCzOWtOYkpSWtdJwzyjMjoHUEu4pvveFbWj8SD99-8Hcw17eHwl9kvv7ThGqNOLzVIeyFJ1qwTVM_iqfrn3BLZzhZJN5yvuNOy5PAPAsU35soxXVO1MqWKaZ300SbJO36M5FjYvvqIHp6eOzwPDnjH4-S1zRidO_FT1XwS5XyaofS02Ydr0uy6VLIW0i9hdTvGFLdvoiTBZwOE69CFz-1XnV0Wj53JuPtZGGZzFOa_fw88i2q36L6WFQ_06x6PnHoyforwU7onObQ246zFqdmiP9XDvvTzvg6_fHZXNJzpy45WWYn7nJxNMee6ITfpZ3px5MX_Po61fZXPeO5TP0Nv35NOnyZz2Knz6HUf_EkajfM544_CfP5NMyxTw-H-RjkzwPJXUwg-d8D6Xnw-NPZZnASnueEE0wXmxYH4JSEVad-x9zbozGs6AUOXuRuYti1C13xlCsxOO-FvEN-ZDAr879MjQipFoLb7WtS22ulidRNPVCM1_TBDMZlKaoZqzjyVotwItnyAJQ4VqnU3UMWUaxo8cyocDiBhbvVPUrCPFkEjmf0FkYtgL_ffVx_-vsW-dHto9K09DDyo_9c3Xy8eu_h2fr9e4QvnQc3dBzXPIrwxJLY7RkvCcYBcQ7z_ef289UHy7fSGeezjPOBqW8eG5i2v6vDG9WYApuv-7clkt6ByMcNZkA0iDxXVIO7CAxNLklJj-07S3Pivn30fvvo_cKT3xf76N1_Buz8_7Mt2TABAQVREHbba41d7d791SRO_EvPbvGfd2UwC7LZzHRZz9iMGRNPKYO5oQydXUp8iHRpxXednlbSvOW6T-i6tnvXCzrKPSpDsmiZhbgjsfvGDU1bxbBG3ho-0FLIRyBpatLJXnpQwCrFMtoWswzFIVMc2AlNJ3jQQ1eb8hSxybc4Ag_3ssVxbrHgkLOKgrtwJpnTv_R8K6EX7Olt4Pvnu4-fTT6y4EryCAkFAjnhikItFNNsS4Hl8CgaCbUUG0lKaBRV7f73tFFalF2SbKp7VmVQ0rQgFVOlnarek7qvzxESzFzkbkjsIRfV5l-DJoLbqz_tbuyo2_ZNH1Ja25HdeC-RFOEVqKauhdQ0G4S8_d8PH1Y3_3zfJuVfvZfzbVfxKX297Sp-slex8-GCZOIekkdNFRDribZ6JGk2m8d-O_0kc07mK6HjGDfPsT3C_gSD4-ycD5fOHHJ8iFHYMgr7A-8cOyzacw9yr2M04bNsAbU0Jx8H-IS_hg_pFOSOxwFZRtW04k_qIa6mzEYl7agH-Zd5iPz12BTuHvgpsGTHchMwU0ijLb1jCk9-kaLSrxtuR4HuV_CkvwhP9hTPFMOOl47nTwIKON3QKjODjagoqMkdSbvSLDNLIXXNu33LbSDuTFa6ocUO3F5Xz2n_G5DDX0RqRjgfArYndlxwMDie8S_HBycAZxjT_6SkBk5zDZJmX0Q14Z6TnuhaUls8RmqQdGNT8ECUdUS3dgA-yCkftmm1RCXLDvSGd4mknXnvkQ3m7ojaWt220nTszt8lalRf1GvH3jZ-epI_uEgIfwrH8FnuEbGKmSlE1g7sHVG_4fkvwZSoaAbJo-lxQgL5oO1IVJqwikoQWypzLu5H1GlPtJKSPEIqxB3bszWQgehdpSXpC8d20SfJwOmWVMAqTWVFuJV7mPW9N4Zqh6B94dPB7jfWBk-p0uRIudbq8tPN53cf_zhc4GlLAZ8UFH5XpeHt5_ddiaGJp1RIaeRPaEG2TDR2FLz9_B6-VS3avgtvaWqGXzszfbk6xeMFiS9dNmjzW_cDqw_fbbRIlDXjVAJ9qLmQrc_vFdqKLBFcz4Q01vuC8HXxx3-CuR8k_xgD2jl_0mzMO0qXCo1tOEuUzvrySy3E3rJJFJme0NwphcxIpSmcZRdetvSW5IxeuEHo4jn23OVZcYHDfOnOA2e-mCeLLPfzZRrk1Mc-9fN5Fvhn7AI72HPmrusu5767nAVuEBDPw0s3DTyHhmju0JIwPuN8WxpBzphSDb0IsLOYn3GSUK7sX8_AuKL3YG8ijJG_PpMXtqg4aTYKzR3OlFYjF800t392Y1I966_NQN6955rzfsa_hr-kSDgtVfsHDZ66dduuCiE1cJZTzUp61kh-8d2Vz1YChfC1lfD_AgAA__8FAo3C">