Ver Fonte

Merge pull request #3297 from MalcolmTyrrell/aiAssertHandler

Allow users to customize the behavior of assert violations
Kim Kulling há 5 anos atrás
pai
commit
50b55726d2

+ 1 - 0
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})
 

+ 72 - 0
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 <iostream>
+#include <cstdlib>
+
+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);
+}

+ 75 - 0
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 <assimp/ai_assert.h>
+#include <assimp/defs.h>
+
+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

+ 11 - 8
include/assimp/ai_assert.h

@@ -42,14 +42,17 @@ 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
-
-#ifdef ASSIMP_BUILD_DEBUG
-#   include <assert.h>
-#   define ai_assert(expression) assert( expression )
-#   define ai_assert_entry()     assert( false )
+#if defined(ASSIMP_BUILD_DEBUG)
+
+namespace Assimp
+{
+    // Assert violation behavior can be customized: see AssertHandler.h.
+    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)
+
 #else
 #   define  ai_assert(expression)
 #   define  ai_assert_entry() 

+ 1 - 0
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

+ 110 - 0
test/unit/Common/utAssertHandler.cpp

@@ -0,0 +1,110 @@
+/*
+---------------------------------------------------------------------------
+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_DEBUG)
+#define ASSIMP_BUILD_DEBUG
+#endif
+
+#include <assimp/ai_assert.h>
+#include <code/Common/AssertHandler.h>
+
+namespace
+{
+    /// An exception which is thrown by the testAssertHandler
+    struct TestAssertException
+    {
+        TestAssertException(const char* failedExpression, const char* file, int line)
+            : 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);
+    }
+}