Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit da512d0

Browse files
committed
[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 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@353850 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent f2b22f5 commit da512d0

File tree

14 files changed

+301
-50
lines changed

14 files changed

+301
-50
lines changed

include/ios

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,16 @@ public:
426426
virtual ~failure() throw();
427427
};
428428

429+
_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY
430+
void __throw_failure(char const* __msg) {
431+
#ifndef _LIBCPP_NO_EXCEPTIONS
432+
throw ios_base::failure(__msg);
433+
#else
434+
((void)__msg);
435+
_VSTD::abort();
436+
#endif
437+
}
438+
429439
class _LIBCPP_TYPE_VIS ios_base::Init
430440
{
431441
public:

include/map

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,10 +1536,8 @@ map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k)
15361536
{
15371537
__parent_pointer __parent;
15381538
__node_base_pointer& __child = __tree_.__find_equal(__parent, __k);
1539-
#ifndef _LIBCPP_NO_EXCEPTIONS
15401539
if (__child == nullptr)
1541-
throw out_of_range("map::at: key not found");
1542-
#endif // _LIBCPP_NO_EXCEPTIONS
1540+
__throw_out_of_range("map::at: key not found");
15431541
return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
15441542
}
15451543

@@ -1549,10 +1547,8 @@ map<_Key, _Tp, _Compare, _Allocator>::at(const key_type& __k) const
15491547
{
15501548
__parent_pointer __parent;
15511549
__node_base_pointer __child = __tree_.__find_equal(__parent, __k);
1552-
#ifndef _LIBCPP_NO_EXCEPTIONS
15531550
if (__child == nullptr)
1554-
throw out_of_range("map::at: key not found");
1555-
#endif // _LIBCPP_NO_EXCEPTIONS
1551+
__throw_out_of_range("map::at: key not found");
15561552
return static_cast<__node_pointer>(__child)->__value_.__get_value().second;
15571553
}
15581554

include/unordered_map

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1603,10 +1603,8 @@ _Tp&
16031603
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::at(const key_type& __k)
16041604
{
16051605
iterator __i = find(__k);
1606-
#ifndef _LIBCPP_NO_EXCEPTIONS
16071606
if (__i == end())
1608-
throw out_of_range("unordered_map::at: key not found");
1609-
#endif // _LIBCPP_NO_EXCEPTIONS
1607+
__throw_out_of_range("unordered_map::at: key not found");
16101608
return __i->second;
16111609
}
16121610

@@ -1615,10 +1613,8 @@ const _Tp&
16151613
unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::at(const key_type& __k) const
16161614
{
16171615
const_iterator __i = find(__k);
1618-
#ifndef _LIBCPP_NO_EXCEPTIONS
16191616
if (__i == end())
1620-
throw out_of_range("unordered_map::at: key not found");
1621-
#endif // _LIBCPP_NO_EXCEPTIONS
1617+
__throw_out_of_range("unordered_map::at: key not found");
16221618
return __i->second;
16231619
}
16241620

src/hash.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,25 +154,17 @@ inline _LIBCPP_INLINE_VISIBILITY
154154
typename enable_if<_Sz == 4, void>::type
155155
__check_for_overflow(size_t N)
156156
{
157-
#ifndef _LIBCPP_NO_EXCEPTIONS
158157
if (N > 0xFFFFFFFB)
159-
throw overflow_error("__next_prime overflow");
160-
#else
161-
(void)N;
162-
#endif
158+
__throw_overflow_error("__next_prime overflow");
163159
}
164160

165161
template <size_t _Sz = sizeof(size_t)>
166162
inline _LIBCPP_INLINE_VISIBILITY
167163
typename enable_if<_Sz == 8, void>::type
168164
__check_for_overflow(size_t N)
169165
{
170-
#ifndef _LIBCPP_NO_EXCEPTIONS
171166
if (N > 0xFFFFFFFFFFFFFFC5ull)
172-
throw overflow_error("__next_prime overflow");
173-
#else
174-
(void)N;
175-
#endif
167+
__throw_overflow_error("__next_prime overflow");
176168
}
177169

178170
size_t

src/ios.cpp

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,9 @@ ios_base::clear(iostate state)
267267
__rdstate_ = state;
268268
else
269269
__rdstate_ = state | badbit;
270-
#ifndef _LIBCPP_NO_EXCEPTIONS
270+
271271
if (((state | (__rdbuf_ ? goodbit : badbit)) & __exceptions_) != 0)
272-
throw failure("ios_base::clear");
273-
#endif // _LIBCPP_NO_EXCEPTIONS
272+
__throw_failure("ios_base::clear");
274273
}
275274

276275
// init
@@ -310,35 +309,27 @@ ios_base::copyfmt(const ios_base& rhs)
310309
{
311310
size_t newesize = sizeof(event_callback) * rhs.__event_size_;
312311
new_callbacks.reset(static_cast<event_callback*>(malloc(newesize)));
313-
#ifndef _LIBCPP_NO_EXCEPTIONS
314312
if (!new_callbacks)
315-
throw bad_alloc();
316-
#endif // _LIBCPP_NO_EXCEPTIONS
313+
__throw_bad_alloc();
317314

318315
size_t newisize = sizeof(int) * rhs.__event_size_;
319316
new_ints.reset(static_cast<int *>(malloc(newisize)));
320-
#ifndef _LIBCPP_NO_EXCEPTIONS
321317
if (!new_ints)
322-
throw bad_alloc();
323-
#endif // _LIBCPP_NO_EXCEPTIONS
318+
__throw_bad_alloc();
324319
}
325320
if (__iarray_cap_ < rhs.__iarray_size_)
326321
{
327322
size_t newsize = sizeof(long) * rhs.__iarray_size_;
328323
new_longs.reset(static_cast<long*>(malloc(newsize)));
329-
#ifndef _LIBCPP_NO_EXCEPTIONS
330324
if (!new_longs)
331-
throw bad_alloc();
332-
#endif // _LIBCPP_NO_EXCEPTIONS
325+
__throw_bad_alloc();
333326
}
334327
if (__parray_cap_ < rhs.__parray_size_)
335328
{
336329
size_t newsize = sizeof(void*) * rhs.__parray_size_;
337330
new_pointers.reset(static_cast<void**>(malloc(newsize)));
338-
#ifndef _LIBCPP_NO_EXCEPTIONS
339331
if (!new_pointers)
340-
throw bad_alloc();
341-
#endif // _LIBCPP_NO_EXCEPTIONS
332+
__throw_bad_alloc();
342333
}
343334
// Got everything we need. Copy everything but __rdstate_, __rdbuf_ and __exceptions_
344335
__fmtflags_ = rhs.__fmtflags_;

src/locale.cpp

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -469,10 +469,8 @@ locale::__imp::install(facet* f, long id)
469469
const locale::facet*
470470
locale::__imp::use_facet(long id) const
471471
{
472-
#ifndef _LIBCPP_NO_EXCEPTIONS
473472
if (!has_facet(id))
474-
throw bad_cast();
475-
#endif // _LIBCPP_NO_EXCEPTIONS
473+
__throw_bad_cast();
476474
return facets_[static_cast<size_t>(id)];
477475
}
478476

@@ -538,12 +536,8 @@ locale::operator=(const locale& other) _NOEXCEPT
538536
}
539537

540538
locale::locale(const char* name)
541-
#ifndef _LIBCPP_NO_EXCEPTIONS
542539
: __locale_(name ? new __imp(name)
543-
: throw runtime_error("locale constructed with null"))
544-
#else // _LIBCPP_NO_EXCEPTIONS
545-
: __locale_(new __imp(name))
546-
#endif
540+
: (__throw_runtime_error("locale constructed with null"), (__imp*)0))
547541
{
548542
__locale_->__add_shared();
549543
}
@@ -555,12 +549,8 @@ locale::locale(const string& name)
555549
}
556550

557551
locale::locale(const locale& other, const char* name, category c)
558-
#ifndef _LIBCPP_NO_EXCEPTIONS
559552
: __locale_(name ? new __imp(*other.__locale_, name, c)
560-
: throw runtime_error("locale constructed with null"))
561-
#else // _LIBCPP_NO_EXCEPTIONS
562-
: __locale_(new __imp(*other.__locale_, name, c))
563-
#endif
553+
: (__throw_runtime_error("locale constructed with null"), (__imp*)0))
564554
{
565555
__locale_->__add_shared();
566556
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <map>
10+
11+
// class map
12+
13+
// mapped_type& at(const key_type& k);
14+
15+
// Make sure we abort() when exceptions are disabled and we fetch a key that
16+
// is not in the map.
17+
18+
// REQUIRES: libcpp-no-exceptions
19+
20+
#include <csignal>
21+
#include <cstdlib>
22+
#include <map>
23+
24+
25+
void exit_success(int) {
26+
std::_Exit(EXIT_SUCCESS);
27+
}
28+
29+
int main(int, char**) {
30+
std::signal(SIGABRT, exit_success);
31+
std::map<int, int> map;
32+
map.at(1);
33+
return EXIT_FAILURE;
34+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <map>
10+
11+
// class map
12+
13+
// const mapped_type& at(const key_type& k) const;
14+
15+
// Make sure we abort() when exceptions are disabled and we fetch a key that
16+
// is not in the map.
17+
18+
// REQUIRES: libcpp-no-exceptions
19+
20+
#include <csignal>
21+
#include <cstdlib>
22+
#include <map>
23+
24+
25+
void exit_success(int) {
26+
std::_Exit(EXIT_SUCCESS);
27+
}
28+
29+
int main(int, char**) {
30+
std::signal(SIGABRT, exit_success);
31+
std::map<int, int> const map;
32+
map.at(1);
33+
return EXIT_FAILURE;
34+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <unordered_map>
10+
11+
// class unordered_map
12+
13+
// mapped_type& at(const key_type& k);
14+
15+
// Make sure we abort() when exceptions are disabled and we fetch a key that
16+
// is not in the map.
17+
18+
// REQUIRES: libcpp-no-exceptions
19+
// UNSUPPORTED: c++98, c++03
20+
21+
#include <csignal>
22+
#include <cstdlib>
23+
#include <unordered_map>
24+
25+
26+
int main(int, char**) {
27+
std::signal(SIGABRT, [](int) { std::_Exit(EXIT_SUCCESS); });
28+
std::unordered_map<int, int> map;
29+
map.at(1);
30+
return EXIT_FAILURE;
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <unordered_map>
10+
11+
// class unordered_map
12+
13+
// const mapped_type& at(const key_type& k) const;
14+
15+
// Make sure we abort() when exceptions are disabled and we fetch a key that
16+
// is not in the map.
17+
18+
// REQUIRES: libcpp-no-exceptions
19+
// UNSUPPORTED: c++98, c++03
20+
21+
#include <csignal>
22+
#include <cstdlib>
23+
#include <unordered_map>
24+
25+
26+
int main(int, char**) {
27+
std::signal(SIGABRT, [](int) { std::_Exit(EXIT_SUCCESS); });
28+
std::unordered_map<int, int> const map;
29+
map.at(1);
30+
return EXIT_FAILURE;
31+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <ios>
10+
11+
// template <class charT, class traits> class basic_ios
12+
13+
// void clear(iostate state);
14+
15+
// Make sure that we abort() when exceptions are disabled and the exception
16+
// flag is set for the iostate we pass to clear().
17+
18+
// REQUIRES: libcpp-no-exceptions
19+
20+
#include <csignal>
21+
#include <cstdlib>
22+
#include <ios>
23+
#include <streambuf>
24+
25+
26+
void exit_success(int) {
27+
std::_Exit(EXIT_SUCCESS);
28+
}
29+
30+
struct testbuf : public std::streambuf {};
31+
32+
int main(int, char**) {
33+
std::signal(SIGABRT, exit_success);
34+
35+
testbuf buf;
36+
std::ios ios(&buf);
37+
ios.exceptions(std::ios::badbit);
38+
ios.clear(std::ios::badbit);
39+
40+
return EXIT_FAILURE;
41+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// <locale>
10+
11+
// class locale;
12+
13+
// explicit locale( const char* std_name );
14+
15+
// REQUIRES: libcpp-no-exceptions
16+
17+
// Make sure we abort() when we construct a locale with a null name and
18+
// exceptions are disabled.
19+
20+
#include <csignal>
21+
#include <cstdlib>
22+
#include <locale>
23+
24+
25+
void exit_success(int) {
26+
std::_Exit(EXIT_SUCCESS);
27+
}
28+
29+
int main(int, char**) {
30+
std::signal(SIGABRT, exit_success);
31+
std::locale loc(NULL);
32+
(void)loc;
33+
return EXIT_FAILURE;
34+
}

0 commit comments

Comments
 (0)