151c0b2f7Stbbdev /*
2*c21e688aSSergey Zheltov     Copyright (c) 2005-2022 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
1751c0b2f7Stbbdev //! \file test_malloc_new_handler.cpp
1851c0b2f7Stbbdev //! \brief Test for [memory_allocation] functionality
1951c0b2f7Stbbdev 
2051c0b2f7Stbbdev #define __TBB_NO_IMPLICIT_LINKAGE 1
2151c0b2f7Stbbdev 
2251c0b2f7Stbbdev #include "common/test.h"
2351c0b2f7Stbbdev #include "common/utils.h"
2451c0b2f7Stbbdev 
2551c0b2f7Stbbdev #include "common/allocator_overload.h"
2651c0b2f7Stbbdev 
273a658065SAnton Potapov // Under ASAN current approach is not viable as it breaks the ASAN itself as well
283e4ab550SIvan Kochin #if !HARNESS_SKIP_TEST && TBB_USE_EXCEPTIONS && !__TBB_USE_ADDRESS_SANITIZER
2951c0b2f7Stbbdev 
3055f9b178SIvan Kochin #if _MSC_VER
3155f9b178SIvan Kochin #pragma warning (push)
3255f9b178SIvan Kochin // Forcing value to bool 'true' or 'false' (occurred inside tls.h)
3355f9b178SIvan Kochin #pragma warning (disable: 4800)
3455f9b178SIvan Kochin #endif //#if _MSC_VER
3555f9b178SIvan Kochin 
365a643c23Svlserov thread_local bool new_handler_called = false;
customNewHandler()3751c0b2f7Stbbdev void customNewHandler() {
3851c0b2f7Stbbdev     new_handler_called = true;
3951c0b2f7Stbbdev     throw std::bad_alloc();
4051c0b2f7Stbbdev }
4151c0b2f7Stbbdev 
4251c0b2f7Stbbdev // Return true if operator new threw exception
allocateWithException(size_t big_mem)4351c0b2f7Stbbdev bool allocateWithException(size_t big_mem) {
4451c0b2f7Stbbdev     bool exception_caught = false;
4551c0b2f7Stbbdev     try {
4651c0b2f7Stbbdev         // Allocate big array (should throw exception)
4751c0b2f7Stbbdev         char* volatile big_array = new char[big_mem];
4851c0b2f7Stbbdev         // If succeeded, double the size (unless it overflows) and recursively retry
4951c0b2f7Stbbdev         if (big_mem * 2 > big_mem) {
5051c0b2f7Stbbdev             exception_caught = allocateWithException(big_mem * 2);
5151c0b2f7Stbbdev         }
5251c0b2f7Stbbdev         delete[] big_array;
5351c0b2f7Stbbdev     } catch (const std::bad_alloc&) {
5451c0b2f7Stbbdev         bool is_called = new_handler_called;
5551c0b2f7Stbbdev         REQUIRE_MESSAGE(is_called, "User provided new_handler was not called.");
5651c0b2f7Stbbdev         exception_caught = true;
5751c0b2f7Stbbdev     }
5851c0b2f7Stbbdev     return exception_caught;
5951c0b2f7Stbbdev }
6051c0b2f7Stbbdev 
6151c0b2f7Stbbdev class AllocLoopBody : utils::NoAssign {
6251c0b2f7Stbbdev public:
operator ()(int) const6351c0b2f7Stbbdev     void operator()(int) const {
6451c0b2f7Stbbdev         size_t BIG_MEM = 100 * 1024 * 1024;
6551c0b2f7Stbbdev         new_handler_called = false;
6651c0b2f7Stbbdev         REQUIRE_MESSAGE(allocateWithException(BIG_MEM), "Operator new did not throw bad_alloc.");
6751c0b2f7Stbbdev     }
6851c0b2f7Stbbdev };
6951c0b2f7Stbbdev 
7051c0b2f7Stbbdev //! \brief \ref error_guessing
7151c0b2f7Stbbdev TEST_CASE("New handler callback") {
7251c0b2f7Stbbdev #if __TBB_CPP11_GET_NEW_HANDLER_PRESENT
7351c0b2f7Stbbdev     std::new_handler default_handler = std::get_new_handler();
7451c0b2f7Stbbdev     REQUIRE_MESSAGE(default_handler == nullptr, "No handler should be set at this point.");
7551c0b2f7Stbbdev #endif
7651c0b2f7Stbbdev     // Define the handler for new operations
7751c0b2f7Stbbdev     std::set_new_handler(customNewHandler);
7851c0b2f7Stbbdev     // Run the test
7951c0b2f7Stbbdev     utils::NativeParallelFor(8, AllocLoopBody());
8051c0b2f7Stbbdev     // Undo custom handler
8157f524caSIlya Isaev     std::set_new_handler(nullptr);
8251c0b2f7Stbbdev }
8355f9b178SIvan Kochin 
8455f9b178SIvan Kochin #if _MSC_VER
8555f9b178SIvan Kochin #pragma warning (pop)
8655f9b178SIvan Kochin #endif
8755f9b178SIvan Kochin 
8851c0b2f7Stbbdev #endif // !HARNESS_SKIP_TEST && TBB_USE_EXCEPTIONS
89