[libcxx-commits] [libcxx] r353850 - [libc++] Avoid UB in the no-exceptions mode in a few places

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Tue Feb 12 08:06:02 PST 2019


Author: ldionne
Date: Tue Feb 12 08:06:02 2019
New Revision: 353850

URL: http://llvm.org/viewvc/llvm-project?rev=353850&view=rev
Log:
[libc++] Avoid UB in the no-exceptions mode in a few places

Summary:
A few places in the library seem to behave unexpectedly when the library
is compiled or used with exceptions disabled. For example, not throwing
an exception when a pointer is NULL can lead us to dereference the pointer
later on, which is UB. This patch fixes such occurences.

It's hard to tell whether there are other places where the no-exceptions
mode misbehaves like this, because the replacement for throwing an
exception does not always seem to be abort()ing, but at least this
patch will improve the situation somewhat.

See http://lists.llvm.org/pipermail/libcxx-dev/2019-January/000172.html

Reviewers: mclow.lists, EricWF

Subscribers: christof, jkorous, dexonsmith, libcxx-commits

Differential Revision: https://reviews.llvm.org/D57761

Added:
    libcxx/trunk/test/libcxx/containers/associative/map/at.abort.pass.cpp
    libcxx/trunk/test/libcxx/containers/associative/map/at.const.abort.pass.cpp
    libcxx/trunk/test/libcxx/containers/unord/unord.map/at.abort.pass.cpp
    libcxx/trunk/test/libcxx/containers/unord/unord.map/at.const.abort.pass.cpp
    libcxx/trunk/test/libcxx/input.output/iostreams.base/ios/
    libcxx/trunk/test/libcxx/input.output/iostreams.base/ios/iostate.flags/
    libcxx/trunk/test/libcxx/input.output/iostreams.base/ios/iostate.flags/clear.abort.pass.cpp
    libcxx/trunk/test/libcxx/localization/locales/locale.abort.pass.cpp
    libcxx/trunk/test/libcxx/localization/locales/locale.category.abort.pass.cpp
    libcxx/trunk/test/libcxx/localization/locales/use_facet.abort.pass.cpp
Modified:
    libcxx/trunk/include/ios
    libcxx/trunk/include/map
    libcxx/trunk/include/unordered_map
    libcxx/trunk/src/hash.cpp
    libcxx/trunk/src/ios.cpp
    libcxx/trunk/src/locale.cpp

Modified: libcxx/trunk/include/ios
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/ios?rev=353850&r1=353849&r2=353850&view=diff
==============================================================================
--- libcxx/trunk/include/ios (original)
+++ libcxx/trunk/include/ios Tue Feb 12 08:06:02 2019
@@ -425,6 +425,16 @@ public:
     virtual ~failure() throw();
 };
 
+_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY
+void __throw_failure(char const* __msg) {
+#ifndef _LIBCPP_NO_EXCEPTIONS
+    throw ios_base::failure(__msg);
+#else
+    ((void)__msg);
+    _VSTD::abort();
+#endif
+}
+
 class _LIBCPP_TYPE_VIS ios_base::Init
 {
 public:

Modified: libcxx/trunk/include/map
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/map?rev=353850&r1=353849&r2=353850&view=diff
==============================================================================
--- libcxx/trunk/include/map (original)
+++ libcxx/trunk/include/map Tue Feb 12 08:06:02 2019
@@ -1535,10 +1535,8 @@ map<_Key, _Tp, _Compare, _Allocator>::at
 {
     __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
+        __throw_out_of_range("map::at:  key not found");
     return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
 }
 
@@ -1548,10 +1546,8 @@ map<_Key, _Tp, _Compare, _Allocator>::at
 {
     __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
+        __throw_out_of_range("map::at:  key not found");
     return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
 }
 

Modified: libcxx/trunk/include/unordered_map
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/unordered_map?rev=353850&r1=353849&r2=353850&view=diff
==============================================================================
--- libcxx/trunk/include/unordered_map (original)
+++ libcxx/trunk/include/unordered_map Tue Feb 12 08:06:02 2019
@@ -1602,10 +1602,8 @@ _Tp&
 unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::at(const key_type& __k)
 {
     iterator __i = find(__k);
-#ifndef _LIBCPP_NO_EXCEPTIONS
     if (__i == end())
-        throw out_of_range("unordered_map::at: key not found");
-#endif  // _LIBCPP_NO_EXCEPTIONS
+        __throw_out_of_range("unordered_map::at: key not found");
     return __i->second;
 }
 
@@ -1614,10 +1612,8 @@ const _Tp&
 unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::at(const key_type& __k) const
 {
     const_iterator __i = find(__k);
-#ifndef _LIBCPP_NO_EXCEPTIONS
     if (__i == end())
-        throw out_of_range("unordered_map::at: key not found");
-#endif  // _LIBCPP_NO_EXCEPTIONS
+        __throw_out_of_range("unordered_map::at: key not found");
     return __i->second;
 }
 

Modified: libcxx/trunk/src/hash.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/hash.cpp?rev=353850&r1=353849&r2=353850&view=diff
==============================================================================
--- libcxx/trunk/src/hash.cpp (original)
+++ libcxx/trunk/src/hash.cpp Tue Feb 12 08:06:02 2019
@@ -153,12 +153,8 @@ inline _LIBCPP_INLINE_VISIBILITY
 typename enable_if<_Sz == 4, void>::type
 __check_for_overflow(size_t N)
 {
-#ifndef _LIBCPP_NO_EXCEPTIONS
     if (N > 0xFFFFFFFB)
-        throw overflow_error("__next_prime overflow");
-#else
-    (void)N;
-#endif
+        __throw_overflow_error("__next_prime overflow");
 }
 
 template <size_t _Sz = sizeof(size_t)>
@@ -166,12 +162,8 @@ inline _LIBCPP_INLINE_VISIBILITY
 typename enable_if<_Sz == 8, void>::type
 __check_for_overflow(size_t N)
 {
-#ifndef _LIBCPP_NO_EXCEPTIONS
     if (N > 0xFFFFFFFFFFFFFFC5ull)
-        throw overflow_error("__next_prime overflow");
-#else
-    (void)N;
-#endif
+        __throw_overflow_error("__next_prime overflow");
 }
 
 size_t

Modified: libcxx/trunk/src/ios.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/ios.cpp?rev=353850&r1=353849&r2=353850&view=diff
==============================================================================
--- libcxx/trunk/src/ios.cpp (original)
+++ libcxx/trunk/src/ios.cpp Tue Feb 12 08:06:02 2019
@@ -266,10 +266,9 @@ ios_base::clear(iostate state)
         __rdstate_ = state;
     else
         __rdstate_ = state | badbit;
-#ifndef _LIBCPP_NO_EXCEPTIONS
+
     if (((state | (__rdbuf_ ? goodbit : badbit)) & __exceptions_) != 0)
-        throw failure("ios_base::clear");
-#endif  // _LIBCPP_NO_EXCEPTIONS
+        __throw_failure("ios_base::clear");
 }
 
 // init
@@ -309,35 +308,27 @@ ios_base::copyfmt(const ios_base& rhs)
     {
         size_t newesize = sizeof(event_callback) * rhs.__event_size_;
         new_callbacks.reset(static_cast<event_callback*>(malloc(newesize)));
-#ifndef _LIBCPP_NO_EXCEPTIONS
         if (!new_callbacks)
-            throw bad_alloc();
-#endif  // _LIBCPP_NO_EXCEPTIONS
+            __throw_bad_alloc();
 
         size_t newisize = sizeof(int) * rhs.__event_size_;
         new_ints.reset(static_cast<int *>(malloc(newisize)));
-#ifndef _LIBCPP_NO_EXCEPTIONS
         if (!new_ints)
-            throw bad_alloc();
-#endif  // _LIBCPP_NO_EXCEPTIONS
+            __throw_bad_alloc();
     }
     if (__iarray_cap_ < rhs.__iarray_size_)
     {
         size_t newsize = sizeof(long) * rhs.__iarray_size_;
         new_longs.reset(static_cast<long*>(malloc(newsize)));
-#ifndef _LIBCPP_NO_EXCEPTIONS
         if (!new_longs)
-            throw bad_alloc();
-#endif  // _LIBCPP_NO_EXCEPTIONS
+            __throw_bad_alloc();
     }
     if (__parray_cap_ < rhs.__parray_size_)
     {
         size_t newsize = sizeof(void*) * rhs.__parray_size_;
         new_pointers.reset(static_cast<void**>(malloc(newsize)));
-#ifndef _LIBCPP_NO_EXCEPTIONS
         if (!new_pointers)
-            throw bad_alloc();
-#endif  // _LIBCPP_NO_EXCEPTIONS
+            __throw_bad_alloc();
     }
     // Got everything we need.  Copy everything but __rdstate_, __rdbuf_ and __exceptions_
     __fmtflags_ = rhs.__fmtflags_;

Modified: libcxx/trunk/src/locale.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/locale.cpp?rev=353850&r1=353849&r2=353850&view=diff
==============================================================================
--- libcxx/trunk/src/locale.cpp (original)
+++ libcxx/trunk/src/locale.cpp Tue Feb 12 08:06:02 2019
@@ -468,10 +468,8 @@ locale::__imp::install(facet* f, long id
 const locale::facet*
 locale::__imp::use_facet(long id) const
 {
-#ifndef _LIBCPP_NO_EXCEPTIONS
     if (!has_facet(id))
-        throw bad_cast();
-#endif  // _LIBCPP_NO_EXCEPTIONS
+        __throw_bad_cast();
     return facets_[static_cast<size_t>(id)];
 }
 
@@ -537,12 +535,8 @@ locale::operator=(const locale& other)
 }
 
 locale::locale(const char* name)
-#ifndef _LIBCPP_NO_EXCEPTIONS
     : __locale_(name ? new __imp(name)
-                     : throw runtime_error("locale constructed with null"))
-#else  // _LIBCPP_NO_EXCEPTIONS
-    : __locale_(new __imp(name))
-#endif
+                     : (__throw_runtime_error("locale constructed with null"), (__imp*)0))
 {
     __locale_->__add_shared();
 }
@@ -554,12 +548,8 @@ locale::locale(const string& name)
 }
 
 locale::locale(const locale& other, const char* name, category c)
-#ifndef _LIBCPP_NO_EXCEPTIONS
     : __locale_(name ? new __imp(*other.__locale_, name, c)
-                     : throw runtime_error("locale constructed with null"))
-#else  // _LIBCPP_NO_EXCEPTIONS
-    : __locale_(new __imp(*other.__locale_, name, c))
-#endif
+                     : (__throw_runtime_error("locale constructed with null"), (__imp*)0))
 {
     __locale_->__add_shared();
 }

Added: libcxx/trunk/test/libcxx/containers/associative/map/at.abort.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/containers/associative/map/at.abort.pass.cpp?rev=353850&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/containers/associative/map/at.abort.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/containers/associative/map/at.abort.pass.cpp Tue Feb 12 08:06:02 2019
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <map>
+
+// class map
+
+// mapped_type& at(const key_type& k);
+
+// Make sure we abort() when exceptions are disabled and we fetch a key that
+// is not in the map.
+
+// REQUIRES: libcpp-no-exceptions
+
+#include <csignal>
+#include <cstdlib>
+#include <map>
+
+
+void exit_success(int) {
+    std::_Exit(EXIT_SUCCESS);
+}
+
+int main(int, char**) {
+    std::signal(SIGABRT, exit_success);
+    std::map<int, int> map;
+    map.at(1);
+    return EXIT_FAILURE;
+}

Added: libcxx/trunk/test/libcxx/containers/associative/map/at.const.abort.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/containers/associative/map/at.const.abort.pass.cpp?rev=353850&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/containers/associative/map/at.const.abort.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/containers/associative/map/at.const.abort.pass.cpp Tue Feb 12 08:06:02 2019
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <map>
+
+// class map
+
+// const mapped_type& at(const key_type& k) const;
+
+// Make sure we abort() when exceptions are disabled and we fetch a key that
+// is not in the map.
+
+// REQUIRES: libcpp-no-exceptions
+
+#include <csignal>
+#include <cstdlib>
+#include <map>
+
+
+void exit_success(int) {
+    std::_Exit(EXIT_SUCCESS);
+}
+
+int main(int, char**) {
+    std::signal(SIGABRT, exit_success);
+    std::map<int, int> const map;
+    map.at(1);
+    return EXIT_FAILURE;
+}

Added: libcxx/trunk/test/libcxx/containers/unord/unord.map/at.abort.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/containers/unord/unord.map/at.abort.pass.cpp?rev=353850&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/containers/unord/unord.map/at.abort.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/containers/unord/unord.map/at.abort.pass.cpp Tue Feb 12 08:06:02 2019
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// class unordered_map
+
+// mapped_type& at(const key_type& k);
+
+// Make sure we abort() when exceptions are disabled and we fetch a key that
+// is not in the map.
+
+// REQUIRES: libcpp-no-exceptions
+// UNSUPPORTED: c++98, c++03
+
+#include <csignal>
+#include <cstdlib>
+#include <unordered_map>
+
+
+int main(int, char**) {
+    std::signal(SIGABRT, [](int) { std::_Exit(EXIT_SUCCESS); });
+    std::unordered_map<int, int> map;
+    map.at(1);
+    return EXIT_FAILURE;
+}

Added: libcxx/trunk/test/libcxx/containers/unord/unord.map/at.const.abort.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/containers/unord/unord.map/at.const.abort.pass.cpp?rev=353850&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/containers/unord/unord.map/at.const.abort.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/containers/unord/unord.map/at.const.abort.pass.cpp Tue Feb 12 08:06:02 2019
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <unordered_map>
+
+// class unordered_map
+
+// const mapped_type& at(const key_type& k) const;
+
+// Make sure we abort() when exceptions are disabled and we fetch a key that
+// is not in the map.
+
+// REQUIRES: libcpp-no-exceptions
+// UNSUPPORTED: c++98, c++03
+
+#include <csignal>
+#include <cstdlib>
+#include <unordered_map>
+
+
+int main(int, char**) {
+    std::signal(SIGABRT, [](int) { std::_Exit(EXIT_SUCCESS); });
+    std::unordered_map<int, int> const map;
+    map.at(1);
+    return EXIT_FAILURE;
+}

Added: libcxx/trunk/test/libcxx/input.output/iostreams.base/ios/iostate.flags/clear.abort.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/input.output/iostreams.base/ios/iostate.flags/clear.abort.pass.cpp?rev=353850&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/input.output/iostreams.base/ios/iostate.flags/clear.abort.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/input.output/iostreams.base/ios/iostate.flags/clear.abort.pass.cpp Tue Feb 12 08:06:02 2019
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <ios>
+
+// template <class charT, class traits> class basic_ios
+
+// void clear(iostate state);
+
+// Make sure that we abort() when exceptions are disabled and the exception
+// flag is set for the iostate we pass to clear().
+
+// REQUIRES: libcpp-no-exceptions
+
+#include <csignal>
+#include <cstdlib>
+#include <ios>
+#include <streambuf>
+
+
+void exit_success(int) {
+    std::_Exit(EXIT_SUCCESS);
+}
+
+struct testbuf : public std::streambuf {};
+
+int main(int, char**) {
+    std::signal(SIGABRT, exit_success);
+
+    testbuf buf;
+    std::ios ios(&buf);
+    ios.exceptions(std::ios::badbit);
+    ios.clear(std::ios::badbit);
+
+    return EXIT_FAILURE;
+}

Added: libcxx/trunk/test/libcxx/localization/locales/locale.abort.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/localization/locales/locale.abort.pass.cpp?rev=353850&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/localization/locales/locale.abort.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/localization/locales/locale.abort.pass.cpp Tue Feb 12 08:06:02 2019
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <locale>
+
+// class locale;
+
+// explicit locale( const char* std_name );
+
+// REQUIRES: libcpp-no-exceptions
+
+// Make sure we abort() when we construct a locale with a null name and
+// exceptions are disabled.
+
+#include <csignal>
+#include <cstdlib>
+#include <locale>
+
+
+void exit_success(int) {
+    std::_Exit(EXIT_SUCCESS);
+}
+
+int main(int, char**) {
+    std::signal(SIGABRT, exit_success);
+    std::locale loc(NULL);
+    (void)loc;
+    return EXIT_FAILURE;
+}

Added: libcxx/trunk/test/libcxx/localization/locales/locale.category.abort.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/localization/locales/locale.category.abort.pass.cpp?rev=353850&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/localization/locales/locale.category.abort.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/localization/locales/locale.category.abort.pass.cpp Tue Feb 12 08:06:02 2019
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <locale>
+
+// class locale;
+
+// locale(const locale& other, const char* std_name, category cat);
+
+// REQUIRES: libcpp-no-exceptions
+
+// Make sure we abort() when we construct a locale with a null name and
+// exceptions are disabled.
+
+#include <csignal>
+#include <cstdlib>
+#include <locale>
+
+
+void exit_success(int) {
+    std::_Exit(EXIT_SUCCESS);
+}
+
+int main(int, char**) {
+    std::signal(SIGABRT, exit_success);
+    std::locale loc(std::locale(), NULL, std::locale::ctype);
+    (void)loc;
+    return EXIT_FAILURE;
+}

Added: libcxx/trunk/test/libcxx/localization/locales/use_facet.abort.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/localization/locales/use_facet.abort.pass.cpp?rev=353850&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/localization/locales/use_facet.abort.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/localization/locales/use_facet.abort.pass.cpp Tue Feb 12 08:06:02 2019
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <locale>
+
+// template <class Facet> const Facet& use_facet(const locale& loc);
+
+// REQUIRES: libcpp-no-exceptions
+
+// Make sure we abort() when we pass a facet not associated to the locale to
+// use_facet() and exceptions are disabled.
+
+#include <csignal>
+#include <cstdlib>
+#include <locale>
+
+
+struct my_facet : public std::locale::facet {
+    static std::locale::id id;
+};
+
+std::locale::id my_facet::id;
+
+void exit_success(int) {
+    std::_Exit(EXIT_SUCCESS);
+}
+
+int main(int, char**) {
+    std::signal(SIGABRT, exit_success);
+    std::use_facet<my_facet>(std::locale());
+    return EXIT_FAILURE;
+}




More information about the libcxx-commits mailing list