<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/78025>78025</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[libc++][print] `std::print` to `ostream` swallows exception when writing to terminal
</td>
</tr>
<tr>
<th>Labels</th>
<td>
libc++
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
jiixyj
</td>
</tr>
</table>
<pre>
When calling `std::print`/`std::println` on an `ostream`, formatting exceptions should not be swallowed and `badbit` should not be set on the `ostream` according to <https://eel.is/c++draft/ostream.formatted.print#3.2>.
Minimal reproducer:
```c++
#include <cassert>
#include <format>
#include <iostream>
struct foo {};
struct foo_error : std::runtime_error {
using std::runtime_error::runtime_error;
};
template <> struct std::formatter<foo> {
constexpr auto parse(std::format_parse_context &ctx) { return ctx.begin(); }
auto format(const foo &, auto &ctx) const -> decltype(ctx.out()) {
throw foo_error{"foo cannot be formatted"};
}
};
static_assert(std::formattable<foo, char>);
int main() {
try {
std::println(std::cout, "{}", foo{});
} catch (foo_error &) {
assert(std::cout.good());
return 0;
}
assert(false);
}
```
```sh
$ clang++ -std=c++23 -stdlib=libc++ print.cpp -o print
$ ./print
print: print.cpp:25: int main(): Assertion `false' failed.
zsh: IOT instruction ./print
$ ./print > /dev/null # works as expected
$
```
This happens because the `try` block is a bit too big, and catches all exceptions from `__vprint_unicode_posix`: <https://github.com/llvm/llvm-project/blob/8e8c954a173e0e814de1207513f357e99dff2e85/libcxx/include/ostream#L1109-L1125>
As a side note, there seems to be a typo in the standard -- any failure to generate output in formatted output functions usually sets `failbit` on the stream, not `badbit`. `badbit` is only set when the following output operation fails, i.e. when [`.failed()`](<https://en.cppreference.com/w/cpp/iterator/ostreambuf_iterator/failed>) is true and/or exceptions from the underlying `streambuf` are thrown. So the standard should probably say in <https://eel.is/c++draft/ostream.formatted.print#3.2>:
> any exception thrown by the call to vformat is propagated without regard to the value of os.exceptions() and without turning on ios_base::failbit in the error state of os[.](https://eel.is/c++draft/ostream.formatted.print#3.sentence-1)
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJysVk-P8rwR_zTmMtoocQiEAwdYFqnSW_XQV-oROc6E-HmMHdnOAv301TgJhN1tpaqVVizYnpnfzPzmj_BenQ3ilhV7VhwWog-tddtfSt3uvxaVre_bf7RoQAqtlTkDW6U-1CzfsXzXOWUCW6WMH78da8NWKVgDwpCM9cGhuMTH79BYdxEhkD68SeyCssaDb22vazA2QIXgr0Jre8UahKlJRSXqSpG5rw8xkJ3Q4qshEFJaV5ORYIHl720InSeI_Mj4EVEnyjN-lIzvGd_XTjSB8eOoIBkxYp0MbvI8TzjLPxKWHli6Gz7_qoy6CA0OO2frXqIj_bMH5HD8G62MpzxXRuq-RsIlhffoAss_frodcPybSzW5-7iOnz64XgZorAW23rP1geX7rzcndM46YPkOHplzvQnqgtPVehQC6D2F8ed3Px5Njs5MD58BL50WIaJn-QeMgB6qp7C76LqlJzMc0hof8NY5EH2w0AnnkfHyi_Qpnp-kNQFvARhfyXBjfEOawGHonQEZbkmFZ2UYLxnfsHwPBHa0E7WPkedltDpEk6-Iv_H6qXa4fyOsNUod7h2BIgu2D6P-wfqkHyC0zl6feaA7zsmEFGYk9oOBjPN5IOGJ9DW1Iih5Gsn0LShBVBrHoPJ3kK1wxJro-jxBygS4iCkuc9DB3V99-FbxM6Myuv4OEXukIOdD6dvp9-bVI5AiyBYYL2fspHh_idx3B8lWcra2fsR6phmmjKc_BXCmrhGayLR5Ie9rEf9Y2b6dKnMJUgtzHiod3iK-w1j4PI8HWlUsP2hVjccQQ5fIroM3O_x4aksYP86Ohq_57inD8h0v6OQ1aXSyi24pG7vv6NoaGqE01mML-6dv6eVf_vYnKDPUIb3_avYFCcSC5McaPxk_ml5rAMZzuFr324PwgLcOJXF2kv0PIfyzVR5a0XVoPFQoRe9x6uPB3amHV9rK36A8CKhUgGAtVOoca9DUA2PQg9B6PkgaZy-k43T6jKBPvVHS1njqrFc3ApHvvg-EswptXyXSXhg_av05_XvrnP2FkmZDpW3F-LHEUm6KpcjWOaZYZssaM56uiyxv8mKNm03dNBzLghSoSt5ujB_Hpv0cMIznf2RZunn7I8soiS8NfEcOe1UjDTkkd0OLjmYdXjyNswpBQLh3FtQw-nwQphauhrc3EOYeM907pLdnNOio5do-dH0giUdrmc6a3sgheL3vhdZ3Gqt-4I7S49y1k6kB_3ucwPPJnLzOaeXBmkEVXGmJIOnG0lincTKath2hI-aRKU96VYLJIEFbySpNBt6O7F6lrDjQ928j3VBROGzQoZE4pvJKM77rKAeBLFn3TELVN6fZ6WgmtkVCH1yPRDQScN8YRt70pkan74_NaFQa1w-KPnV5k8Df7WuSxg2mc7YSFUVI3Ckt_7cl5esWkn9EUjw8GIFBdY-4aLkjpnwO-sj1ztlOnAVR5KpCa_sADs-EPQy-fArdI9gGrE-ekRmnBhXnJEbNN6bbgLL-VAmP7IOzMmXlfujfj58j1yZODzOA5tpoiBX7ZMj9_x4mjyYQS94yxjeLepvXm3wjFrjN1mmR5eWSp4t2W69Xy9Wq5BUWm_WqwnKVrdcpZqLhy6bYLBdqy1O-TLMsTzd5vkyTVVquswyXvCpx06ScLVO8CKUT6iWJdeeF8r7H7bpMebHQokLt4_LN-XMs0LAsDgu3jQ2o6s-eLVOtfPBPNUEFHdf2mVhxYMV-8LE4_Lirx134ZU0eF20_Y0csvatTYVyeA7qLMkIveqe3_3XXjP5SdqLL_woAAP__bNrYFQ">