1 //===-- flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp ----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 /// Selected APIs are tested here to support development of unit tests for other 10 /// runtime components and ensure the test fixture handles crashes as we expect. 11 // 12 //===----------------------------------------------------------------------===// 13 #include "CrashHandlerFixture.h" 14 #include "../../runtime/terminator.h" 15 #include "flang/Runtime/io-api.h" 16 #include "flang/Runtime/stop.h" 17 #include <gtest/gtest.h> 18 19 using namespace Fortran::runtime; 20 using namespace Fortran::runtime::io; 21 22 //------------------------------------------------------------------------------ 23 /// Test crashes through direct calls to terminator methods 24 //------------------------------------------------------------------------------ 25 struct TestTerminator : CrashHandlerFixture {}; 26 27 #define TEST_CRASH_HANDLER_MESSAGE \ 28 "Intentionally crashing runtime for unit test" 29 30 TEST(TestTerminator, CrashTest) { 31 static Fortran::runtime::Terminator t; 32 ASSERT_DEATH(t.Crash(TEST_CRASH_HANDLER_MESSAGE), TEST_CRASH_HANDLER_MESSAGE); 33 } 34 35 #undef TEST_CRASH_HANDLER_MESSAGE 36 37 TEST(TestTerminator, CheckFailedLocationTest) { 38 static Fortran::runtime::Terminator t; 39 ASSERT_DEATH(t.CheckFailed("predicate", "someFileName", 789), 40 "RUNTIME_CHECK\\(predicate\\) failed at someFileName\\(789\\)"); 41 } 42 43 TEST(TestTerminator, CheckFailedTest) { 44 static Fortran::runtime::Terminator t; 45 ASSERT_DEATH(t.CheckFailed("predicate"), 46 "RUNTIME_CHECK\\(predicate\\) failed at \\(null\\)\\(0\\)"); 47 } 48 49 //------------------------------------------------------------------------------ 50 /// Test misuse of io api 51 //------------------------------------------------------------------------------ 52 struct TestIOCrash : CrashHandlerFixture {}; 53 54 TEST(TestIOCrash, FormatDescriptorWriteMismatchTest) { 55 static constexpr int bufferSize{4}; 56 static char buffer[bufferSize]; 57 static const char *format{"(A4)"}; 58 auto *cookie{IONAME(BeginInternalFormattedOutput)( 59 buffer, bufferSize, format, std::strlen(format))}; 60 ASSERT_DEATH(IONAME(OutputLogical)(cookie, true), 61 "Data edit descriptor 'A' may not be used with a LOGICAL data item"); 62 } 63 64 TEST(TestIOCrash, InvalidFormatCharacterTest) { 65 static constexpr int bufferSize{1}; 66 static char buffer[bufferSize]; 67 static const char *format{"(C1)"}; 68 auto *cookie{IONAME(BeginInternalFormattedOutput)( 69 buffer, bufferSize, format, std::strlen(format))}; 70 ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xfeedface), 71 "Unknown 'C' edit descriptor in FORMAT"); 72 } 73 74 //------------------------------------------------------------------------------ 75 /// Test buffer overwrites with Output* functions 76 /// Each test performs the tested IO operation correctly first, before causing 77 /// an overwrite to demonstrate that the failure is caused by the overwrite and 78 /// not a misuse of the API. 79 //------------------------------------------------------------------------------ 80 TEST(TestIOCrash, OverwriteBufferAsciiTest) { 81 static constexpr int bufferSize{4}; 82 static char buffer[bufferSize]; 83 static const char *format{"(A4)"}; 84 auto *cookie{IONAME(BeginInternalFormattedOutput)( 85 buffer, bufferSize, format, std::strlen(format))}; 86 IONAME(OutputAscii)(cookie, "four", bufferSize); 87 ASSERT_DEATH(IONAME(OutputAscii)(cookie, "Too many characters!", 20), 88 "Internal write overran available records"); 89 } 90 91 TEST(TestIOCrash, OverwriteBufferCharacterTest) { 92 static constexpr int bufferSize{1}; 93 static char buffer[bufferSize]; 94 static const char *format{"(A1)"}; 95 auto *cookie{IONAME(BeginInternalFormattedOutput)( 96 buffer, bufferSize, format, std::strlen(format))}; 97 IONAME(OutputCharacter)(cookie, "a", 1); 98 ASSERT_DEATH(IONAME(OutputCharacter)(cookie, "a", 1), 99 "Internal write overran available records"); 100 } 101 102 TEST(TestIOCrash, OverwriteBufferLogicalTest) { 103 static constexpr int bufferSize{1}; 104 static char buffer[bufferSize]; 105 static const char *format{"(L1)"}; 106 auto *cookie{IONAME(BeginInternalFormattedOutput)( 107 buffer, bufferSize, format, std::strlen(format))}; 108 IONAME(OutputLogical)(cookie, true); 109 ASSERT_DEATH(IONAME(OutputLogical)(cookie, true), 110 "Internal write overran available records"); 111 } 112 113 TEST(TestIOCrash, OverwriteBufferRealTest) { 114 static constexpr int bufferSize{1}; 115 static char buffer[bufferSize]; 116 static const char *format{"(F1)"}; 117 auto *cookie{IONAME(BeginInternalFormattedOutput)( 118 buffer, bufferSize, format, std::strlen(format))}; 119 IONAME(OutputReal32)(cookie, 1.); 120 EXPECT_DEATH(IONAME(OutputReal32)(cookie, 1.), 121 "Internal write overran available records"); 122 123 std::memset(buffer, '\0', bufferSize); 124 cookie = IONAME(BeginInternalFormattedOutput)( 125 buffer, bufferSize, format, std::strlen(format)); 126 IONAME(OutputReal64)(cookie, 1.); 127 EXPECT_DEATH(IONAME(OutputReal64)(cookie, 1.), 128 "Internal write overran available records"); 129 } 130 131 TEST(TestIOCrash, OverwriteBufferComplexTest) { 132 static constexpr int bufferSize{8}; 133 static char buffer[bufferSize]; 134 static const char *format{"(Z1,Z1)"}; 135 auto *cookie{IONAME(BeginInternalFormattedOutput)( 136 buffer, bufferSize, format, std::strlen(format))}; 137 IONAME(OutputComplex32)(cookie, 1., 1.); 138 EXPECT_DEATH(IONAME(OutputComplex32)(cookie, 1., 1.), 139 "Internal write overran available records"); 140 141 std::memset(buffer, '\0', bufferSize); 142 cookie = IONAME(BeginInternalFormattedOutput)( 143 buffer, bufferSize, format, std::strlen(format)); 144 IONAME(OutputComplex64)(cookie, 1., 1.); 145 EXPECT_DEATH(IONAME(OutputComplex64)(cookie, 1., 1.), 146 "Internal write overran available records"); 147 } 148 149 TEST(TestIOCrash, OverwriteBufferIntegerTest) { 150 static constexpr int bufferSize{1}; 151 static char buffer[bufferSize]; 152 static const char *format{"(I1)"}; 153 auto *cookie{IONAME(BeginInternalFormattedOutput)( 154 buffer, bufferSize, format, std::strlen(format))}; 155 IONAME(OutputInteger64)(cookie, 0xdeadbeef); 156 ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xdeadbeef), 157 "Internal write overran available records"); 158 } 159 160 TEST(TestIOCrash, StopTest) { 161 EXPECT_EXIT(RTNAME(StopStatement)(), testing::ExitedWithCode(EXIT_SUCCESS), 162 "Fortran STOP"); 163 } 164 165 TEST(TestIOCrash, FailImageTest) { 166 EXPECT_EXIT( 167 RTNAME(FailImageStatement)(), testing::ExitedWithCode(EXIT_FAILURE), ""); 168 } 169 170 TEST(TestIOCrash, ExitTest) { 171 EXPECT_EXIT(RTNAME(Exit)(), testing::ExitedWithCode(EXIT_SUCCESS), ""); 172 EXPECT_EXIT( 173 RTNAME(Exit)(EXIT_FAILURE), testing::ExitedWithCode(EXIT_FAILURE), ""); 174 } 175 176 TEST(TestIOCrash, AbortTest) { EXPECT_DEATH(RTNAME(Abort)(), ""); } 177