1*51c0b2f7Stbbdev /*
2*51c0b2f7Stbbdev     Copyright (c) 2005-2020 Intel Corporation
3*51c0b2f7Stbbdev 
4*51c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5*51c0b2f7Stbbdev     you may not use this file except in compliance with the License.
6*51c0b2f7Stbbdev     You may obtain a copy of the License at
7*51c0b2f7Stbbdev 
8*51c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
9*51c0b2f7Stbbdev 
10*51c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
11*51c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12*51c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*51c0b2f7Stbbdev     See the License for the specific language governing permissions and
14*51c0b2f7Stbbdev     limitations under the License.
15*51c0b2f7Stbbdev */
16*51c0b2f7Stbbdev 
17*51c0b2f7Stbbdev //! \file test_malloc_new_handler.cpp
18*51c0b2f7Stbbdev //! \brief Test for [memory_allocation] functionality
19*51c0b2f7Stbbdev 
20*51c0b2f7Stbbdev #define __TBB_NO_IMPLICIT_LINKAGE 1
21*51c0b2f7Stbbdev 
22*51c0b2f7Stbbdev #include "common/test.h"
23*51c0b2f7Stbbdev #include "common/utils.h"
24*51c0b2f7Stbbdev 
25*51c0b2f7Stbbdev #include "common/allocator_overload.h"
26*51c0b2f7Stbbdev 
27*51c0b2f7Stbbdev #if !HARNESS_SKIP_TEST && TBB_USE_EXCEPTIONS
28*51c0b2f7Stbbdev 
29*51c0b2f7Stbbdev #include "../../src/tbb/tls.h"
30*51c0b2f7Stbbdev 
31*51c0b2f7Stbbdev tbb::detail::r1::tls<bool> new_handler_called;
32*51c0b2f7Stbbdev void customNewHandler() {
33*51c0b2f7Stbbdev     new_handler_called = true;
34*51c0b2f7Stbbdev     throw std::bad_alloc();
35*51c0b2f7Stbbdev }
36*51c0b2f7Stbbdev 
37*51c0b2f7Stbbdev // Return true if operator new threw exception
38*51c0b2f7Stbbdev bool allocateWithException(size_t big_mem) {
39*51c0b2f7Stbbdev     bool exception_caught = false;
40*51c0b2f7Stbbdev     try {
41*51c0b2f7Stbbdev         // Allocate big array (should throw exception)
42*51c0b2f7Stbbdev         char* volatile big_array = new char[big_mem];
43*51c0b2f7Stbbdev         // If succeeded, double the size (unless it overflows) and recursively retry
44*51c0b2f7Stbbdev         if (big_mem * 2 > big_mem) {
45*51c0b2f7Stbbdev             exception_caught = allocateWithException(big_mem * 2);
46*51c0b2f7Stbbdev         }
47*51c0b2f7Stbbdev         delete[] big_array;
48*51c0b2f7Stbbdev     } catch (const std::bad_alloc&) {
49*51c0b2f7Stbbdev         bool is_called = new_handler_called;
50*51c0b2f7Stbbdev         REQUIRE_MESSAGE(is_called, "User provided new_handler was not called.");
51*51c0b2f7Stbbdev         exception_caught = true;
52*51c0b2f7Stbbdev     }
53*51c0b2f7Stbbdev     return exception_caught;
54*51c0b2f7Stbbdev }
55*51c0b2f7Stbbdev 
56*51c0b2f7Stbbdev class AllocLoopBody : utils::NoAssign {
57*51c0b2f7Stbbdev public:
58*51c0b2f7Stbbdev     void operator()(int) const {
59*51c0b2f7Stbbdev         size_t BIG_MEM = 100 * 1024 * 1024;
60*51c0b2f7Stbbdev         new_handler_called = false;
61*51c0b2f7Stbbdev         REQUIRE_MESSAGE(allocateWithException(BIG_MEM), "Operator new did not throw bad_alloc.");
62*51c0b2f7Stbbdev     }
63*51c0b2f7Stbbdev };
64*51c0b2f7Stbbdev 
65*51c0b2f7Stbbdev //! \brief \ref error_guessing
66*51c0b2f7Stbbdev TEST_CASE("New handler callback") {
67*51c0b2f7Stbbdev #if __TBB_CPP11_GET_NEW_HANDLER_PRESENT
68*51c0b2f7Stbbdev     std::new_handler default_handler = std::get_new_handler();
69*51c0b2f7Stbbdev     REQUIRE_MESSAGE(default_handler == nullptr, "No handler should be set at this point.");
70*51c0b2f7Stbbdev #endif
71*51c0b2f7Stbbdev     // Define the handler for new operations
72*51c0b2f7Stbbdev     std::set_new_handler(customNewHandler);
73*51c0b2f7Stbbdev     // Run the test
74*51c0b2f7Stbbdev     utils::NativeParallelFor(8, AllocLoopBody());
75*51c0b2f7Stbbdev     // Undo custom handler
76*51c0b2f7Stbbdev     std::set_new_handler(0);
77*51c0b2f7Stbbdev }
78*51c0b2f7Stbbdev #endif // !HARNESS_SKIP_TEST && TBB_USE_EXCEPTIONS
79