[libcxx-dev] Question about the no-exceptions mode of libc++

Olivier Giroux via libcxx-dev libcxx-dev at lists.llvm.org
Tue Jan 29 10:45:10 PST 2019


+1. I’m configured in this mode exclusively, and also prefer abort().

Olivier

From: libcxx-dev <libcxx-dev-bounces at lists.llvm.org> on behalf of Duncan Exon Smith via libcxx-dev <libcxx-dev at lists.llvm.org>
Reply-To: Duncan Exon Smith <dexonsmith at apple.com>
Date: Monday, January 28, 2019 at 11:01 AM
To: Louis Dionne <ldionne at apple.com>
Cc: Libc++ Dev <libcxx-dev at lists.llvm.org>
Subject: Re: [libcxx-dev] Question about the no-exceptions mode of libc++

FWIW, I agree ::abort is more appropriate.


On 2019 Jan  28, at 10:44, Louis Dionne via libcxx-dev <libcxx-dev at lists.llvm.org<mailto:libcxx-dev at lists.llvm.org>> wrote:

Hi,

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 _LIBCPP_NO_EXCEPTIONS, or by passing LIBCXX_ENABLE_EXCEPTIONS=OFF when configuring CMake.

However, I'd like to understand the design of this mode a bit better. It seems like we sometimes call abort() instead of throwing, but sometimes we just swallow the would-be exception and carry on. For example, instead of throwing std::bad_optional_access, we call std::abort():

    void __throw_bad_optional_access() {
    #ifndef _LIBCPP_NO_EXCEPTIONS
            throw bad_optional_access();
    #else
            _VSTD::abort();
    #endif
    }

This makes sense to me. However, in other cases, we just swallow the exception. For example, in std::map::at when we can't find the key, we just don't throw an exception, and we dereference a null pointer unless I'm mistaken:

    template <class _Key, class _Tp, class _Compare, class _Allocator>
    const _Tp& map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) const {
        __parent_pointer __parent;
        __node_base_pointer __child = __tree_.__find_equal(__parent, __k);
    #ifndef _LIBCPP_NO_EXCEPTIONS
        if (__child == nullptr)
            throw out_of_range("map::at:  key not found");
    #endif  // _LIBCPP_NO_EXCEPTIONS
        return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
    }

Here, when __child == nullptr, 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 std::abort()) so that we can fix places that don't behave correctly.

Cheers,
Louis

_______________________________________________
libcxx-dev mailing list
libcxx-dev at lists.llvm.org<mailto:libcxx-dev at lists.llvm.org>
https://lists.llvm.org/cgi-bin/mailman/listinfo/libcxx-dev



-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information.  Any unauthorized review, use, disclosure or distribution
is prohibited.  If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/libcxx-dev/attachments/20190129/a7e1038d/attachment.html>


More information about the libcxx-dev mailing list