diff --git a/offline_compiler/CMakeLists.txt b/offline_compiler/CMakeLists.txt index 4287ec9ecf..6e1a86b6f8 100644 --- a/offline_compiler/CMakeLists.txt +++ b/offline_compiler/CMakeLists.txt @@ -78,6 +78,8 @@ set(CLOC_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt ) add_executable(cloc ${CLOC_SRCS}) +add_subdirectories() + create_project_source_tree(cloc ${IGDRCL_SOURCE_DIR}/runtime) set(CLOC_INCLUDES @@ -94,6 +96,10 @@ target_include_directories(cloc BEFORE PRIVATE ${CLOC_INCLUDES}) target_compile_definitions(cloc PUBLIC ${CLOC_LIB_FLAGS_DEFINITIONS} ${SUPPORTED_GEN_FLAGS_DEFINITONS} DEFAULT_PLATFORM=${DEFAULT_SUPPORTED_PLATFORM}) +if(MSVC) + target_link_libraries(cloc dbghelp) +endif() + if(UNIX) target_link_libraries(cloc dl pthread) endif() diff --git a/offline_compiler/main.cpp b/offline_compiler/main.cpp index dc5c87a3fc..bdf4e5b6a0 100644 --- a/offline_compiler/main.cpp +++ b/offline_compiler/main.cpp @@ -21,6 +21,7 @@ */ #include "offline_compiler/offline_compiler.h" +#include "offline_compiler/utilities/safety_caller.h" #include "runtime/os_interface/os_library.h" #include @@ -32,7 +33,7 @@ int main(int numArgs, const char *argv[]) { OfflineCompiler *pCompiler = OfflineCompiler::create(numArgs, argv, retVal); if (retVal == CL_SUCCESS) { - retVal = pCompiler->build(); + retVal = buildWithSafetyGuard(pCompiler); std::string buildLog = pCompiler->getBuildLog(); if (buildLog.empty() == false) { diff --git a/offline_compiler/utilities/CMakeLists.txt b/offline_compiler/utilities/CMakeLists.txt new file mode 100644 index 0000000000..7ad4fda0ef --- /dev/null +++ b/offline_compiler/utilities/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (c) 2018, Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +set(CLOC_SRCS_UTILITIES + ${CMAKE_CURRENT_SOURCE_DIR}/safety_caller.h +) + +if(WIN32) + list(APPEND CLOC_SRCS_UTILITIES + ${CMAKE_CURRENT_SOURCE_DIR}/windows/safety_caller_windows.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/windows/safety_guard_windows.h + ${CMAKE_CURRENT_SOURCE_DIR}/windows/seh_exception.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/windows/seh_exception.h + ) +else() + list(APPEND CLOC_SRCS_UTILITIES + ${CMAKE_CURRENT_SOURCE_DIR}/linux/safety_caller_linux.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/linux/safety_guard_linux.h + ) +endif() + +target_sources(cloc PRIVATE ${CLOC_SRCS_UTILITIES}) diff --git a/offline_compiler/utilities/linux/safety_caller_linux.cpp b/offline_compiler/utilities/linux/safety_caller_linux.cpp new file mode 100644 index 0000000000..d263c22f9d --- /dev/null +++ b/offline_compiler/utilities/linux/safety_caller_linux.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "runtime/os_interface/os_library.h" +#include "offline_compiler/offline_compiler.h" +#include "offline_compiler/utilities/linux/safety_guard_linux.h" + +using namespace OCLRT; + +int buildWithSafetyGuard(OfflineCompiler *compiler) { + SafetyGuardLinux safetyGuard; + int retVal = 0; + + return safetyGuard.call(compiler, &OfflineCompiler::build, retVal); +} diff --git a/offline_compiler/utilities/linux/safety_guard_linux.h b/offline_compiler/utilities/linux/safety_guard_linux.h new file mode 100644 index 0000000000..783e16e88c --- /dev/null +++ b/offline_compiler/utilities/linux/safety_guard_linux.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#include "runtime/helpers/abort.h" +#include +#include +#include +#include +#include + +static jmp_buf jmpbuf; + +class SafetyGuardLinux { + public: + SafetyGuardLinux() { + struct sigaction sigact; + + sigact.sa_sigaction = sigAction; + sigact.sa_flags = SA_RESTART | SA_SIGINFO; + sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL); + sigaction(SIGILL, &sigact, (struct sigaction *)NULL); + } + + static void sigAction(int sig_num, siginfo_t *info, void *ucontext) { + const int callstackDepth = 30; + void *addresses[callstackDepth]; + char **callstack; + int backtraceSize = 0; + + backtraceSize = backtrace(addresses, callstackDepth); + callstack = backtrace_symbols(addresses, backtraceSize); + + for (int i = 0; i < backtraceSize; ++i) { + printf("[%d]: %s\n", i, callstack[i]); + } + + free(callstack); + longjmp(jmpbuf, 1); + } + + template + T call(Object *object, Method method, T retValueOnCrash) { + int jump = 0; + jump = setjmp(jmpbuf); + + if (jump == 0) { + return (object->*method)(); + } else { + if (onSigSegv) { + onSigSegv(); + } else { + OCLRT::abortExecution(); + } + } + return retValueOnCrash; + } + + typedef void (*callbackFunction)(); + callbackFunction onSigSegv = nullptr; +}; diff --git a/offline_compiler/utilities/safety_caller.h b/offline_compiler/utilities/safety_caller.h new file mode 100644 index 0000000000..11a19993d9 --- /dev/null +++ b/offline_compiler/utilities/safety_caller.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once +namespace OCLRT { +class OfflineCompiler; +} + +extern int buildWithSafetyGuard(OCLRT::OfflineCompiler *compiler); \ No newline at end of file diff --git a/offline_compiler/utilities/windows/safety_caller_windows.cpp b/offline_compiler/utilities/windows/safety_caller_windows.cpp new file mode 100644 index 0000000000..b3b9afdbdc --- /dev/null +++ b/offline_compiler/utilities/windows/safety_caller_windows.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "offline_compiler/offline_compiler.h" +#include "offline_compiler/utilities/windows/safety_guard_windows.h" + +using namespace OCLRT; + +int buildWithSafetyGuard(OfflineCompiler *compiler) { + SafetyGuardWindows safetyGuard; + int retVal = 0; + return safetyGuard.call(compiler, &OfflineCompiler::build, retVal); +} diff --git a/offline_compiler/utilities/windows/safety_guard_windows.h b/offline_compiler/utilities/windows/safety_guard_windows.h new file mode 100644 index 0000000000..ca86c24d56 --- /dev/null +++ b/offline_compiler/utilities/windows/safety_guard_windows.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#include "offline_compiler/utilities/windows/seh_exception.h" +#include "runtime/helpers/abort.h" + +#include + +static jmp_buf jmpbuf; + +class SafetyGuardWindows { + public: + template + T call(Object *object, Method method, T retValueOnCrash) { + int jump = 0; + jump = setjmp(jmpbuf); + + if (jump == 0) { + __try { + return (object->*method)(); + } __except (SehException::filter(GetExceptionCode(), GetExceptionInformation())) { + if (onExcept) { + onExcept(); + } else { + OCLRT::abortExecution(); + } + longjmp(jmpbuf, 1); + } + } + return retValueOnCrash; + } + + typedef void (*callbackFunction)(); + callbackFunction onExcept = nullptr; +}; diff --git a/offline_compiler/utilities/windows/seh_exception.cpp b/offline_compiler/utilities/windows/seh_exception.cpp new file mode 100644 index 0000000000..d1a61361e8 --- /dev/null +++ b/offline_compiler/utilities/windows/seh_exception.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "seh_exception.h" +#include "runtime/os_interface/os_library.h" + +#include +#include + +#pragma warning(push) +#pragma warning(disable : 4091) +#include +#pragma warning(pop) + +#include +#include +#include + +using namespace std; + +string SehException::getExceptionDescription(unsigned int code) { + switch (code) { + case EXCEPTION_ACCESS_VIOLATION: + return "Access violation"; + case EXCEPTION_DATATYPE_MISALIGNMENT: + return "Datatype misalignement"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_INT_DIVIDE_BY_ZERO: + return "Divide by zero"; + case EXCEPTION_STACK_OVERFLOW: + return "Stack overflow"; + + default: + break; + } + return "Unknown"; +} + +int SehException::filter(unsigned int code, struct _EXCEPTION_POINTERS *ep) { + + printf("EXCEPTION: %s\n", SehException::getExceptionDescription(code).c_str()); + + if (code != EXCEPTION_STACK_OVERFLOW) { + string callstack; + + SehException::getCallStack(code, ep, callstack); + printf("Callstack:\n\n%s", callstack.c_str()); + } + return EXCEPTION_EXECUTE_HANDLER; +} + +void SehException::getCallStack(unsigned int code, struct _EXCEPTION_POINTERS *ep, string &stack) { + DWORD machine = 0; + HANDLE hProcess = GetCurrentProcess(); + HANDLE hThread = GetCurrentThread(); + + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + + if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { + machine = IMAGE_FILE_MACHINE_I386; + } else if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { + machine = IMAGE_FILE_MACHINE_AMD64; + } else { + stack = "invalid processor arch"; + return; + } + + stack.clear(); + + BOOL result = SymInitialize(hProcess, NULL, TRUE); + STACKFRAME64 stackFrame; + memset(&stackFrame, 0, sizeof(STACKFRAME64)); + const int nameSize = 255; + char buffer[sizeof(IMAGEHLP_SYMBOL64) + (nameSize + 1) * sizeof(char)]; + IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast(buffer); + symbol->MaxNameLength = nameSize; + + DWORD displacement = 0; + DWORD64 displacement64 = 0; + + unique_ptr psApiLib(OCLRT::OsLibrary::load("psapi.dll")); + auto getMappedFileName = reinterpret_cast(psApiLib->getProcAddress("GetMappedFileNameA")); + + size_t callstackCounter = 0; + const size_t maxCallstackDepth = 1000; + +#ifdef _WIN64 + stackFrame.AddrPC.Offset = ep->ContextRecord->Rip; + stackFrame.AddrPC.Mode = AddrModeFlat; + stackFrame.AddrStack.Offset = ep->ContextRecord->Rsp; + stackFrame.AddrStack.Mode = AddrModeFlat; + stackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp; + stackFrame.AddrFrame.Mode = AddrModeFlat; +#else + stackFrame.AddrPC.Offset = ep->ContextRecord->Eip; + stackFrame.AddrPC.Mode = AddrModeFlat; + stackFrame.AddrStack.Offset = ep->ContextRecord->Esp; + stackFrame.AddrStack.Mode = AddrModeFlat; + stackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; + stackFrame.AddrFrame.Mode = AddrModeFlat; + +#endif + + while (callstackCounter < maxCallstackDepth) { + symbol->Name[255] = '\0'; + + if (!StackWalk64(machine, hProcess, hThread, &stackFrame, ep->ContextRecord, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, 0)) { + break; + } + + if (stackFrame.AddrFrame.Offset == 0) { + break; + } + + string lineInCode; + string module; + string symbolName; + + DWORD64 address = stackFrame.AddrPC.Offset; + IMAGEHLP_LINE64 imageLine; + imageLine.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + if (SymGetLineFromAddr64(hProcess, address, &displacement, &imageLine)) { + lineInCode = imageLine.FileName; + char filename[MAX_PATH + 1]; + filename[MAX_PATH] = '\0'; + + if (getMappedFileName(hProcess, reinterpret_cast(imageLine.Address), filename, MAX_PATH)) { + module = filename; + } + } + + if (SymGetSymFromAddr64(hProcess, address, &displacement64, symbol)) { + + symbolName = symbol->Name; + } + addLineToCallstack(stack, callstackCounter, module, lineInCode, symbolName); + callstackCounter++; + } +} + +void SehException::addLineToCallstack(std::string &callstack, size_t counter, std::string &module, std::string &line, std::string &symbol) { + callstack += "["; + callstack += to_string(counter); + callstack += "]: "; + + if (module.size()) { + callstack += "Module:"; + callstack += module + "\n\t"; + } + if (line.size()) { + callstack += line + ":"; + } + callstack += symbol + "\n"; +} diff --git a/offline_compiler/utilities/windows/seh_exception.h b/offline_compiler/utilities/windows/seh_exception.h new file mode 100644 index 0000000000..3009c587fb --- /dev/null +++ b/offline_compiler/utilities/windows/seh_exception.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once + +#include "windows.h" +#include "excpt.h" +#include + +class SehException { + public: + static std::string getExceptionDescription(unsigned int code); + static void getCallStack(unsigned int code, struct _EXCEPTION_POINTERS *ep, std::string &stack); + static int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep); + + protected: + static void addLineToCallstack(std::string &callstack, size_t counter, std::string &module, std::string &line, std::string &symbol); + typedef DWORD(WINAPI *getMappedFileNameFunction)(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename, DWORD nSize); +}; diff --git a/unit_tests/offline_compiler/CMakeLists.txt b/unit_tests/offline_compiler/CMakeLists.txt index bee0ee5d00..cf2219caf9 100644 --- a/unit_tests/offline_compiler/CMakeLists.txt +++ b/unit_tests/offline_compiler/CMakeLists.txt @@ -126,4 +126,6 @@ else() WORKING_DIRECTORY ${TargetDir} ) endif() + +add_subdirectories() create_project_source_tree(cloc_tests ${IGDRCL_SOURCE_DIR}/runtime ${IGDRCL_SOURCE_DIR}/unit_tests ${IGDRCL_SOURCE_DIR}) diff --git a/unit_tests/offline_compiler/segfault_test/CMakeLists.txt b/unit_tests/offline_compiler/segfault_test/CMakeLists.txt new file mode 100644 index 0000000000..e866526340 --- /dev/null +++ b/unit_tests/offline_compiler/segfault_test/CMakeLists.txt @@ -0,0 +1,83 @@ +# Copyright (c) 2018, Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +set(CLOC_SEGFAULT_TEST_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt + ${CMAKE_CURRENT_SOURCE_DIR}/segfault_helper.h + ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${IGDRCL_SOURCE_DIR}/runtime/helpers/abort.cpp + ${IGDRCL_SOURCE_DIR}/runtime/os_interface/os_library.h + ${IGDRCL_SOURCE_DIR}/unit_tests/helpers/debug_helpers.cpp +) + +if(WIN32) + list(APPEND CLOC_SEGFAULT_TEST_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/windows/safety_guard_caller_windows.cpp + ${IGDRCL_SOURCE_DIR}/offline_compiler/utilities/windows/safety_guard_windows.h + ${IGDRCL_SOURCE_DIR}/offline_compiler/utilities/windows/seh_exception.cpp + ${IGDRCL_SOURCE_DIR}/offline_compiler/utilities/windows/seh_exception.h + ${IGDRCL_SOURCE_DIR}/runtime/os_interface/windows/os_library.cpp + ) +else() + list(APPEND CLOC_SEGFAULT_TEST_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/linux/safety_guard_caller_linux.cpp + ${IGDRCL_SOURCE_DIR}/runtime/os_interface/linux/os_library.cpp + ) +endif() + +add_executable(cloc_segfault_test ${CLOC_SEGFAULT_TEST_SOURCES}) +target_link_libraries(cloc_segfault_test gmock-gtest) +if(MSVC) + target_compile_options(cloc_segfault_test PRIVATE /Zi) + set_property(TARGET cloc_segfault_test APPEND PROPERTY LINK_FLAGS /DEBUG) + target_link_libraries(cloc_segfault_test dbghelp) +endif() +if(UNIX) + target_link_libraries(cloc_segfault_test dl pthread) +endif() + +set(CLOC_SEGFAULT_TEST_INCLUDES + ${IGDRCL_SOURCE_DIR} + ${THIRD_PARTY_DIR} +) + +if(CMAKE_COMPILER_IS_GNUCC) + target_compile_definitions(cloc_segfault_test PRIVATE SKIP_SEGFAULT_TEST=1) +endif() + +get_property(CLOC_FOLDER TARGET cloc PROPERTY FOLDER) +set_property(TARGET cloc_segfault_test PROPERTY FOLDER ${CLOC_FOLDER}) + +target_include_directories(cloc_segfault_test BEFORE PRIVATE ${CLOC_SEGFAULT_TEST_INCLUDES}) +create_project_source_tree(cloc_segfault_test ${IGDRCL_SOURCE_DIR}/offline_compiler ${IGDRCL_SOURCE_DIR}/runtime ${IGDRCL_SOURCE_DIR}/unit_tests) + +add_custom_target(run_cloc_segfault_test ALL + DEPENDS cloc_segfault_test +) + +add_custom_command( + TARGET run_cloc_segfault_test + POST_BUILD + COMMAND echo Running cloc_segfault_test + COMMAND cloc_segfault_test + WORKING_DIRECTORY ${TargetDir} +) + +set_property(TARGET run_cloc_segfault_test PROPERTY FOLDER ${CLOC_FOLDER}) diff --git a/unit_tests/offline_compiler/segfault_test/linux/safety_guard_caller_linux.cpp b/unit_tests/offline_compiler/segfault_test/linux/safety_guard_caller_linux.cpp new file mode 100644 index 0000000000..262de1bf9d --- /dev/null +++ b/unit_tests/offline_compiler/segfault_test/linux/safety_guard_caller_linux.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "../segfault_helper.h" +#include "offline_compiler/utilities/linux/safety_guard_linux.h" + +void generateSegfaultWithSafetyGuard(SegfaultHelper *segfaultHelper) { + SafetyGuardLinux safetyGuard; + safetyGuard.onSigSegv = segfaultHelper->segfaultHandlerCallback; + int retVal = 0; + + safetyGuard.call(segfaultHelper, &SegfaultHelper::generateSegfault, retVal); +} diff --git a/unit_tests/offline_compiler/segfault_test/main.cpp b/unit_tests/offline_compiler/segfault_test/main.cpp new file mode 100644 index 0000000000..229643d355 --- /dev/null +++ b/unit_tests/offline_compiler/segfault_test/main.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "segfault_helper.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include + +using namespace std; + +extern void generateSegfaultWithSafetyGuard(SegfaultHelper *segfaultHelper); + +int main(int argc, char **argv) { + int retVal = 0; + ::testing::InitGoogleTest(&argc, argv); + + retVal = RUN_ALL_TESTS(); + + return retVal; +} + +void captureAndCheckStdOut() { + string callstack = ::testing::internal::GetCapturedStdout(); + + EXPECT_THAT(callstack, ::testing::HasSubstr(string("Callstack"))); + EXPECT_THAT(callstack, ::testing::HasSubstr(string("cloc_segfault_test"))); + EXPECT_THAT(callstack, ::testing::HasSubstr(string("generateSegfaultWithSafetyGuard"))); +} + +TEST(SegFault, givenCallWithSafetyGuardWhenSegfaultHappensThenCallstackIsPrintedToStdOut) { +#if !defined(SKIP_SEGFAULT_TEST) + ::testing::internal::CaptureStdout(); + SegfaultHelper segfault; + segfault.segfaultHandlerCallback = captureAndCheckStdOut; + + generateSegfaultWithSafetyGuard(&segfault); +#endif +} diff --git a/unit_tests/offline_compiler/segfault_test/segfault_helper.h b/unit_tests/offline_compiler/segfault_test/segfault_helper.h new file mode 100644 index 0000000000..64c70740f9 --- /dev/null +++ b/unit_tests/offline_compiler/segfault_test/segfault_helper.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#pragma once +#if defined(__clang__) +#define NO_SANITIZE __attribute__((no_sanitize("address", "undefined"))) +#elif defined(__GNUC__) +#define NO_SANITIZE __attribute__((no_sanitize_address)) +#else +#define NO_SANITIZE +#endif + +class SegfaultHelper { + public: + int NO_SANITIZE generateSegfault() { + int *pointer = reinterpret_cast(0); + *pointer = 0; + return 0; + } + + typedef void (*callbackFunction)(); + + callbackFunction segfaultHandlerCallback = nullptr; +}; diff --git a/unit_tests/offline_compiler/segfault_test/windows/safety_guard_caller_windows.cpp b/unit_tests/offline_compiler/segfault_test/windows/safety_guard_caller_windows.cpp new file mode 100644 index 0000000000..b026064680 --- /dev/null +++ b/unit_tests/offline_compiler/segfault_test/windows/safety_guard_caller_windows.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018, Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIA BLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "unit_tests/offline_compiler/segfault_test/segfault_helper.h" +#include "offline_compiler/utilities/windows/safety_guard_windows.h" + +void generateSegfaultWithSafetyGuard(SegfaultHelper *segfaultHelper) { + SafetyGuardWindows safetyGuard; + safetyGuard.onExcept = segfaultHelper->segfaultHandlerCallback; + int retVal = 0; + + safetyGuard.call(segfaultHelper, &SegfaultHelper::generateSegfault, retVal); +} \ No newline at end of file