diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 000ebad6c..9f8f519d9 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -199,6 +199,7 @@ SET( Common_SRCS Common/simd.h Common/simd.cpp Common/material.cpp + Common/AssertHandler.cpp ) SOURCE_GROUP(Common FILES ${Common_SRCS}) diff --git a/code/Common/AssertHandler.cpp b/code/Common/AssertHandler.cpp new file mode 100644 index 000000000..63b64f828 --- /dev/null +++ b/code/Common/AssertHandler.cpp @@ -0,0 +1,72 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +/** @file AssertHandler.cpp + * @brief Implementation of assert handling logic. + */ + +#include "AssertHandler.h" + +#include +#include + +void Assimp::defaultAiAssertHandler(const char* failedExpression, const char* file, int line) +{ + std::cerr << "ai_assert failure in " << file << "(" << line << "): " << failedExpression << std::endl; + std::abort(); +} + +namespace +{ + Assimp::AiAssertHandler s_handler = Assimp::defaultAiAssertHandler; +} + +void Assimp::setAiAssertHandler(AiAssertHandler handler) +{ + s_handler = handler; +} + +void Assimp::aiAssertViolation(const char* failedExpression, const char* file, int line) +{ + s_handler(failedExpression, file, line); +} diff --git a/code/Common/AssertHandler.h b/code/Common/AssertHandler.h new file mode 100644 index 000000000..2515f0bf2 --- /dev/null +++ b/code/Common/AssertHandler.h @@ -0,0 +1,75 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +/** @file Provides facilities to replace the default assert handler. */ + +#ifndef INCLUDED_AI_ASSERTHANDLER_H +#define INCLUDED_AI_ASSERTHANDLER_H + +#include +#include + +namespace Assimp +{ + // --------------------------------------------------------------------------- + /** Signature of functions which handle assert violations. + */ + using AiAssertHandler = void (*)(const char* failedExpression, const char* file, int line); + + // --------------------------------------------------------------------------- + /** Set the assert handler. + */ + ASSIMP_API void setAiAssertHandler(AiAssertHandler handler); + + // --------------------------------------------------------------------------- + /** The assert handler which is set by default. + * + * This issues a message to stderr and calls abort. + */ + ASSIMP_API void defaultAiAssertHandler(const char* failedExpression, const char* file, int line); + + // --------------------------------------------------------------------------- + /** Dispatches an assert violation to the assert handler. + */ + ASSIMP_API void aiAssertViolation(const char* failedExpression, const char* file, int line); +} // end of namespace Assimp + +#endif // INCLUDED_AI_ASSERTHANDLER_H \ No newline at end of file diff --git a/include/assimp/ai_assert.h b/include/assimp/ai_assert.h index f018163bf..6045a9801 100644 --- a/include/assimp/ai_assert.h +++ b/include/assimp/ai_assert.h @@ -42,14 +42,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ASSERT_H_INC #define AI_ASSERT_H_INC -#ifdef __GNUC__ -# pragma GCC system_header -#endif +#if defined(ASSIMP_BUILD_DEBUG) || defined(ASSIMP_BUILD_WITH_ASSERTS) + +namespace Assimp +{ + void aiAssertViolation(const char* failedExpression, const char* file, int line); +} + +# define ai_assert(expression) (void)((!!(expression)) || (Assimp::aiAssertViolation(#expression, __FILE__, __LINE__), 0)) +# define ai_assert_entry() ai_assert(false) -#ifdef ASSIMP_BUILD_DEBUG -# include -# define ai_assert(expression) assert( expression ) -# define ai_assert_entry() assert( false ) #else # define ai_assert(expression) # define ai_assert_entry() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a5f8086e9..8e1746ce2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -87,6 +87,7 @@ SET( COMMON unit/Common/uiScene.cpp unit/Common/utLineSplitter.cpp unit/Common/utSpatialSort.cpp + unit/Common/utAssertHandler.cpp ) SET( IMPORTERS diff --git a/test/unit/Common/utAssertHandler.cpp b/test/unit/Common/utAssertHandler.cpp new file mode 100644 index 000000000..0ac4c90af --- /dev/null +++ b/test/unit/Common/utAssertHandler.cpp @@ -0,0 +1,111 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2020, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +#include "UnitTestPCH.h" + +/// Ensure this test has asserts on, even if the build type doesn't have asserts by default. +#if !defined(ASSIMP_BUILD_WITH_ASSERTS) +#define ASSIMP_BUILD_WITH_ASSERTS +#endif + +#include +#include + +namespace +{ + /// An exception which is thrown by the testAssertHandler + struct TestAssertException : std::exception + { + TestAssertException(const char* failedExpression, const char* file, int line) + : std::exception("Test Assert Exception") + , m_failedExpression(failedExpression) + , m_file(file) + , m_line(line) + { + } + + std::string m_failedExpression; + std::string m_file; + int m_line; + }; + + /// Swap the default handler, which aborts, by one which throws. + void testAssertHandler(const char* failedExpression, const char* file, int line) + { + throw TestAssertException(failedExpression, file, line); + } + + /// Ensure that the default assert handler is restored after the test is finished. + struct ReplaceHandlerScope + { + ReplaceHandlerScope() + { + Assimp::setAiAssertHandler(testAssertHandler); + } + + ~ReplaceHandlerScope() + { + Assimp::setAiAssertHandler(Assimp::defaultAiAssertHandler); + } + }; +} + +TEST(utAssertHandler, replaceWithThrow) +{ + ReplaceHandlerScope scope; + + try + { + ai_assert((2 + 2 == 5) && "Sometimes people put messages here"); + EXPECT_TRUE(false); + } + catch(const TestAssertException& e) + { + EXPECT_STREQ(e.m_failedExpression.c_str(), "(2 + 2 == 5) && \"Sometimes people put messages here\""); + EXPECT_STREQ(e.m_file.c_str(), __FILE__); + EXPECT_GT(e.m_line, 0); + EXPECT_LT(e.m_line, __LINE__); + } + catch(...) + { + EXPECT_TRUE(false); + } +}