<html><head><meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Jan 29, 2019, at 13:03, Marshall Clow <<a href="mailto:mclow.lists@gmail.com" class="">mclow.lists@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><br class="Apple-interchange-newline"><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;" class=""><div class="gmail_quote" style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;"><div dir="ltr" class="gmail_attr">On Mon, Jan 28, 2019 at 10:44 AM Louis Dionne via libcxx-dev <<a href="mailto:libcxx-dev@lists.llvm.org" class="">libcxx-dev@lists.llvm.org</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-style: solid; border-left-color: rgb(204, 204, 204); padding-left: 1ex;"><div style="overflow-wrap: break-word;" class=""><div class=""><div class="">Hi,</div><div class=""><br class=""></div><div class="">My understanding is that libc++ has a no-exceptions mode under which we never throw and never use try-catch blocks. This mode is enabled by defining<span class="Apple-converted-space"> </span><font face="Menlo" class="">_LIBCPP_NO_EXCEPTIONS</font>, or by passing<span class="Apple-converted-space"> </span><font face="Menlo" class="">LIBCXX_ENABLE_EXCEPTIONS=OFF</font><span class="Apple-converted-space"> </span>when configuring CMake.</div><div class=""><br class=""></div><div class="">However, I'd like to understand the design of this mode a bit better. It seems like we sometimes call<span class="Apple-converted-space"> </span><font face="Menlo" class="">abort()</font> instead of throwing, but sometimes we just swallow the would-be exception and carry on. For example, instead of throwing<span class="Apple-converted-space"> </span><font face="Menlo" class="">std::bad_optional_access</font>, we call<span class="Apple-converted-space"> </span><font face="Menlo" class="">std::abort()</font>:</div><div class=""><br class=""></div><div class=""><font face="Menlo" class="">   <span class="Apple-converted-space"> </span>void __throw_bad_optional_access() {</font></div><div class=""><font face="Menlo" class="">   <span class="Apple-converted-space"> </span>#ifndef _LIBCPP_NO_EXCEPTIONS</font></div><div class=""><font face="Menlo" class="">           <span class="Apple-converted-space"> </span>throw bad_optional_access();</font></div><div class=""><font face="Menlo" class="">   <span class="Apple-converted-space"> </span>#else</font></div><div class=""><font face="Menlo" class="">           <span class="Apple-converted-space"> </span>_VSTD::abort();</font></div><div class=""><font face="Menlo" class="">   <span class="Apple-converted-space"> </span>#endif</font></div><div class=""><font face="Menlo" class="">   <span class="Apple-converted-space"> </span>}</font></div><div class=""><br class=""></div><div class="">This makes sense to me. However, in other cases, we just swallow the exception. For example, in<span class="Apple-converted-space"> </span><font face="Menlo" class="">std::map::at</font><span class="Apple-converted-space"> </span>when we can't find the key, we just don't throw an exception, and we dereference a null pointer unless I'm mistaken:</div><div class=""><br class=""></div><div class=""><font face="Menlo" class="">   <span class="Apple-converted-space"> </span>template <class _Key, class _Tp, class _Compare, class _Allocator></font></div><div class=""><font face="Menlo" class="">   <span class="Apple-converted-space"> </span>const _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) const {</font></div><div class=""><font face="Menlo" class="">       <span class="Apple-converted-space"> </span>__parent_pointer __parent;</font></div><div class=""><font face="Menlo" class="">       <span class="Apple-converted-space"> </span>__node_base_pointer __child = __tree_.__find_equal(__parent, __k);</font></div><div class=""><font face="Menlo" class="">   <span class="Apple-converted-space"> </span>#ifndef _LIBCPP_NO_EXCEPTIONS</font></div><div class=""><font face="Menlo" class="">       <span class="Apple-converted-space"> </span>if (__child == nullptr)</font></div><div class=""><font face="Menlo" class="">           <span class="Apple-converted-space"> </span>throw out_of_range("map::at:  key not found");</font></div><div class=""><font face="Menlo" class="">   <span class="Apple-converted-space"> </span>#endif  // _LIBCPP_NO_EXCEPTIONS</font></div><div class=""><font face="Menlo" class="">       <span class="Apple-converted-space"> </span>return static_cast<__node_pointer>(__child)->__value_.__get_value().second;</font></div><div class=""><font face="Menlo" class="">   <span class="Apple-converted-space"> </span>}</font></div><div class=""><br class=""></div><div class="">Here, when<span class="Apple-converted-space"> </span><font face="Menlo" class="">__child == nullptr</font>, we do NOT throw an exception and we end up dereferencing it, which is UB. I haven't made a full survey of libc++, but I'd like to know whether this is by design, and if so, what is the rationale for it. Otherwise, I'd like for us to agree on what the behaviour should be (I suggest<span class="Apple-converted-space"> </span><font face="Menlo" class="">std::abort()</font>) so that we can fix places that don't behave correctly.</div></div></div><br class=""></blockquote><div class=""><br class=""></div><div class="">std::abort is the "correct" behavior.</div><div class="">We have a "__throw_out_of_range" call that does what we want.</div><div class="">Change the code to:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Menlo" class="">- #ifndef _LIBCPP_NO_EXCEPTIONS</font></div><div class=""><font face="Menlo" class="">        if (__child == nullptr)</font></div><div class=""><font face="Menlo" class="">-            throw out_of_range("map::at:  key not found");</font></div><div class=""><font face="Menlo" class="">+           __throw_out_of_range("map::at:  key not found");</font></div><div class=""><span style="font-family: Menlo;" class="">- #endif  // _LIBCPP_NO_EXCEPTIONS</span><br class=""></div></div><div class=""><br class=""></div><div class="">AND it gets rid of ifdefs!</div><div class=""><br class=""></div><div class="">-- Marshall</div></div></div></blockquote></div><br class=""><div class="">I surveyed libc++ and I fixed the occurrences that seemed wrong to me: <a href="https://reviews.llvm.org/D57761" class="">https://reviews.llvm.org/D57761</a>.</div><div class=""><br class=""></div><div class="">Louis</div><div class=""><br class=""></div></body></html>