Skip to content

Commit ad61b46

Browse files
azhan92alisonzhang4
authored andcommitted
[libc++] Fix noexcept behaviour of operator new helper functions (#74337)
This patch removes the noexcept specifier introduced in #69407 since the Standard allows a new handler to throw an exception of type bad_alloc (or derived from it). With the noexcept specifier on the helper functions, we would immediately terminate the program. The patch also adds tests for the case that had regressed. Co-authored-by: Alison Zhang <[email protected]> NOKEYCHECK=True GitOrigin-RevId: 4207ad57707f07208dfb1d7c79889e1372c396ab
1 parent 14b9135 commit ad61b46

File tree

9 files changed

+354
-2
lines changed

9 files changed

+354
-2
lines changed

src/new.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
// in this shared library, so that they can be overridden by programs
2121
// that define non-weak copies of the functions.
2222

23-
static void* operator_new_impl(std::size_t size) noexcept {
23+
static void* operator_new_impl(std::size_t size) {
2424
if (size == 0)
2525
size = 1;
2626
void* p;
@@ -87,7 +87,7 @@ _LIBCPP_WEAK void operator delete[](void* ptr, size_t) noexcept { ::operator del
8787

8888
# if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION)
8989

90-
static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) noexcept {
90+
static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) {
9191
if (size == 0)
9292
size = 1;
9393
if (static_cast<size_t>(alignment) < sizeof(void*))
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
// UNSUPPORTED: no-exceptions
10+
// UNSUPPORTED: sanitizer-new-delete
11+
12+
#include <new>
13+
#include <cassert>
14+
#include <limits>
15+
#include <cstdlib>
16+
17+
struct construction_key {};
18+
struct my_bad_alloc : std::bad_alloc {
19+
my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
20+
my_bad_alloc(construction_key) : self(this) {}
21+
const my_bad_alloc* const self;
22+
};
23+
24+
int new_handler_called = 0;
25+
26+
void my_new_handler() {
27+
++new_handler_called;
28+
throw my_bad_alloc(construction_key());
29+
}
30+
31+
int main(int, char**) {
32+
std::set_new_handler(my_new_handler);
33+
try {
34+
void* x = operator new[](std::numeric_limits<std::size_t>::max());
35+
(void)x;
36+
assert(false);
37+
} catch (my_bad_alloc const& e) {
38+
assert(new_handler_called == 1);
39+
assert(e.self == &e);
40+
} catch (...) {
41+
assert(false);
42+
}
43+
return 0;
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
// UNSUPPORTED: no-exceptions
10+
// UNSUPPORTED: sanitizer-new-delete
11+
12+
#include <new>
13+
#include <cassert>
14+
#include <limits>
15+
#include <cstdlib>
16+
17+
struct construction_key {};
18+
struct my_bad_alloc : std::bad_alloc {
19+
my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
20+
my_bad_alloc(construction_key) : self(this) {}
21+
const my_bad_alloc* const self;
22+
};
23+
24+
int new_handler_called = 0;
25+
26+
void my_new_handler() {
27+
++new_handler_called;
28+
throw my_bad_alloc(construction_key());
29+
}
30+
31+
int main(int, char**) {
32+
std::set_new_handler(my_new_handler);
33+
try {
34+
void* x = operator new[](std::numeric_limits<std::size_t>::max(), static_cast<std::align_val_t>(32));
35+
(void)x;
36+
assert(false);
37+
} catch (my_bad_alloc const& e) {
38+
assert(new_handler_called == 1);
39+
assert(e.self == &e);
40+
} catch (...) {
41+
assert(false);
42+
}
43+
return 0;
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
// UNSUPPORTED: no-exceptions
10+
// UNSUPPORTED: sanitizer-new-delete
11+
12+
#include <new>
13+
#include <cassert>
14+
#include <limits>
15+
#include <cstdlib>
16+
17+
struct construction_key {};
18+
struct my_bad_alloc : std::bad_alloc {
19+
my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
20+
my_bad_alloc(construction_key) : self(this) {}
21+
const my_bad_alloc* const self;
22+
};
23+
24+
int new_handler_called = 0;
25+
26+
void my_new_handler() {
27+
++new_handler_called;
28+
throw my_bad_alloc(construction_key());
29+
}
30+
31+
int main(int, char**) {
32+
std::set_new_handler(my_new_handler);
33+
try {
34+
void* x = operator new[](std::numeric_limits<std::size_t>::max(), static_cast<std::align_val_t>(32), std::nothrow);
35+
(void)x;
36+
assert(x == NULL);
37+
} catch (my_bad_alloc const& e) {
38+
assert(new_handler_called == 1);
39+
assert(e.self == &e);
40+
} catch (...) {
41+
assert(false);
42+
}
43+
return 0;
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
// UNSUPPORTED: no-exceptions
10+
// UNSUPPORTED: sanitizer-new-delete
11+
12+
#include <new>
13+
#include <cassert>
14+
#include <limits>
15+
#include <cstdlib>
16+
17+
struct construction_key {};
18+
struct my_bad_alloc : std::bad_alloc {
19+
my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
20+
my_bad_alloc(construction_key) : self(this) {}
21+
const my_bad_alloc* const self;
22+
};
23+
24+
int new_handler_called = 0;
25+
26+
void my_new_handler() {
27+
++new_handler_called;
28+
throw my_bad_alloc(construction_key());
29+
}
30+
31+
int main(int, char**) {
32+
std::set_new_handler(my_new_handler);
33+
try {
34+
void* x = operator new[](std::numeric_limits<std::size_t>::max(), std::nothrow);
35+
(void)x;
36+
assert(x == NULL);
37+
} catch (my_bad_alloc const& e) {
38+
assert(new_handler_called == 1);
39+
assert(e.self == &e);
40+
} catch (...) {
41+
assert(false);
42+
}
43+
return 0;
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
// UNSUPPORTED: no-exceptions
10+
// UNSUPPORTED: sanitizer-new-delete
11+
12+
#include <new>
13+
#include <cassert>
14+
#include <limits>
15+
#include <cstdlib>
16+
17+
struct construction_key {};
18+
struct my_bad_alloc : std::bad_alloc {
19+
my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
20+
my_bad_alloc(construction_key) : self(this) {}
21+
const my_bad_alloc* const self;
22+
};
23+
24+
int new_handler_called = 0;
25+
26+
void my_new_handler() {
27+
++new_handler_called;
28+
throw my_bad_alloc(construction_key());
29+
}
30+
31+
int main(int, char**) {
32+
std::set_new_handler(my_new_handler);
33+
try {
34+
void* x = operator new(std::numeric_limits<std::size_t>::max());
35+
(void)x;
36+
assert(false);
37+
} catch (my_bad_alloc const& e) {
38+
assert(new_handler_called == 1);
39+
assert(e.self == &e);
40+
} catch (...) {
41+
assert(false);
42+
}
43+
return 0;
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
// UNSUPPORTED: no-exceptions
10+
// UNSUPPORTED: sanitizer-new-delete
11+
12+
#include <new>
13+
#include <cassert>
14+
#include <limits>
15+
#include <cstdlib>
16+
17+
struct construction_key {};
18+
struct my_bad_alloc : std::bad_alloc {
19+
my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
20+
my_bad_alloc(construction_key) : self(this) {}
21+
const my_bad_alloc* const self;
22+
};
23+
24+
int new_handler_called = 0;
25+
26+
void my_new_handler() {
27+
++new_handler_called;
28+
throw my_bad_alloc(construction_key());
29+
}
30+
31+
int main(int, char**) {
32+
std::set_new_handler(my_new_handler);
33+
try {
34+
void* x = operator new(std::numeric_limits<std::size_t>::max(), static_cast<std::align_val_t>(32));
35+
(void)x;
36+
assert(false);
37+
} catch (my_bad_alloc const& e) {
38+
assert(new_handler_called == 1);
39+
assert(e.self == &e);
40+
} catch (...) {
41+
assert(false);
42+
}
43+
return 0;
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
// UNSUPPORTED: no-exceptions
10+
// UNSUPPORTED: sanitizer-new-delete
11+
12+
#include <new>
13+
#include <cassert>
14+
#include <limits>
15+
#include <cstdlib>
16+
17+
struct construction_key {};
18+
struct my_bad_alloc : std::bad_alloc {
19+
my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
20+
my_bad_alloc(construction_key) : self(this) {}
21+
const my_bad_alloc* const self;
22+
};
23+
24+
int new_handler_called = 0;
25+
26+
void my_new_handler() {
27+
++new_handler_called;
28+
throw my_bad_alloc(construction_key());
29+
}
30+
31+
int main(int, char**) {
32+
std::set_new_handler(my_new_handler);
33+
try {
34+
void* x = operator new(std::numeric_limits<std::size_t>::max(), static_cast<std::align_val_t>(32), std::nothrow);
35+
(void)x;
36+
assert(x == NULL);
37+
} catch (my_bad_alloc const& e) {
38+
assert(new_handler_called == 1);
39+
assert(e.self == &e);
40+
} catch (...) {
41+
assert(false);
42+
}
43+
return 0;
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
// UNSUPPORTED: no-exceptions
10+
// UNSUPPORTED: sanitizer-new-delete
11+
12+
#include <new>
13+
#include <cassert>
14+
#include <limits>
15+
#include <cstdlib>
16+
17+
struct construction_key {};
18+
struct my_bad_alloc : std::bad_alloc {
19+
my_bad_alloc(const my_bad_alloc&) : self(this) { std::abort(); }
20+
my_bad_alloc(construction_key) : self(this) {}
21+
const my_bad_alloc* const self;
22+
};
23+
24+
int new_handler_called = 0;
25+
26+
void my_new_handler() {
27+
++new_handler_called;
28+
throw my_bad_alloc(construction_key());
29+
}
30+
31+
int main(int, char**) {
32+
std::set_new_handler(my_new_handler);
33+
try {
34+
void* x = operator new(std::numeric_limits<std::size_t>::max(), std::nothrow);
35+
(void)x;
36+
assert(x == NULL);
37+
} catch (my_bad_alloc const& e) {
38+
assert(new_handler_called == 1);
39+
assert(e.self == &e);
40+
} catch (...) {
41+
assert(false);
42+
}
43+
return 0;
44+
}

0 commit comments

Comments
 (0)