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 <gtest/gtest.h> 17 18 using namespace Fortran::runtime; 19 using namespace Fortran::runtime::io; 20 21 //------------------------------------------------------------------------------ 22 /// Test crashes through direct calls to terminator methods 23 //------------------------------------------------------------------------------ 24 struct TestTerminator : CrashHandlerFixture {}; 25 26 #define TEST_CRASH_HANDLER_MESSAGE \ 27 "Intentionally crashing runtime for unit test" 28 29 TEST(TestTerminator, CrashTest) { 30 static Fortran::runtime::Terminator t; 31 ASSERT_DEATH(t.Crash(TEST_CRASH_HANDLER_MESSAGE), TEST_CRASH_HANDLER_MESSAGE); 32 } 33 34 #undef TEST_CRASH_HANDLER_MESSAGE 35 36 TEST(TestTerminator, CheckFailedLocationTest) { 37 static Fortran::runtime::Terminator t; 38 ASSERT_DEATH(t.CheckFailed("predicate", "someFileName", 789), 39 "RUNTIME_CHECK\\(predicate\\) failed at someFileName\\(789\\)"); 40 } 41 42 TEST(TestTerminator, CheckFailedTest) { 43 static Fortran::runtime::Terminator t; 44 ASSERT_DEATH(t.CheckFailed("predicate"), 45 "RUNTIME_CHECK\\(predicate\\) failed at \\(null\\)\\(0\\)"); 46 } 47 48 //------------------------------------------------------------------------------ 49 /// Test misuse of io api 50 //------------------------------------------------------------------------------ 51 struct TestIOCrash : CrashHandlerFixture {}; 52 53 TEST(TestIOCrash, FormatDescriptorWriteMismatchTest) { 54 static constexpr int bufferSize{4}; 55 static char buffer[bufferSize]; 56 static const char *format{"(A4)"}; 57 auto *cookie{IONAME(BeginInternalFormattedOutput)( 58 buffer, bufferSize, format, std::strlen(format))}; 59 ASSERT_DEATH(IONAME(OutputLogical)(cookie, true), 60 "Data edit descriptor 'A' may not be used with a LOGICAL data item"); 61 } 62 63 TEST(TestIOCrash, InvalidFormatCharacterTest) { 64 static constexpr int bufferSize{1}; 65 static char buffer[bufferSize]; 66 static const char *format{"(C1)"}; 67 auto *cookie{IONAME(BeginInternalFormattedOutput)( 68 buffer, bufferSize, format, std::strlen(format))}; 69 ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xfeedface), 70 "Unknown 'C' edit descriptor in FORMAT"); 71 } 72 73 //------------------------------------------------------------------------------ 74 /// Test buffer overwrites with Output* functions 75 /// Each test performs the tested IO operation correctly first, before causing 76 /// an overwrite to demonstrate that the failure is caused by the overwrite and 77 /// not a misuse of the API. 78 //------------------------------------------------------------------------------ 79 TEST(TestIOCrash, OverwriteBufferAsciiTest) { 80 static constexpr int bufferSize{4}; 81 static char buffer[bufferSize]; 82 static const char *format{"(A4)"}; 83 auto *cookie{IONAME(BeginInternalFormattedOutput)( 84 buffer, bufferSize, format, std::strlen(format))}; 85 IONAME(OutputAscii)(cookie, "four", bufferSize); 86 ASSERT_DEATH(IONAME(OutputAscii)(cookie, "Too many characters!", 20), 87 "Internal write overran available records"); 88 } 89 90 TEST(TestIOCrash, OverwriteBufferCharacterTest) { 91 static constexpr int bufferSize{1}; 92 static char buffer[bufferSize]; 93 static const char *format{"(A1)"}; 94 auto *cookie{IONAME(BeginInternalFormattedOutput)( 95 buffer, bufferSize, format, std::strlen(format))}; 96 IONAME(OutputCharacter)(cookie, "a", 1); 97 ASSERT_DEATH(IONAME(OutputCharacter)(cookie, "a", 1), 98 "Internal write overran available records"); 99 } 100 101 TEST(TestIOCrash, OverwriteBufferLogicalTest) { 102 static constexpr int bufferSize{1}; 103 static char buffer[bufferSize]; 104 static const char *format{"(L1)"}; 105 auto *cookie{IONAME(BeginInternalFormattedOutput)( 106 buffer, bufferSize, format, std::strlen(format))}; 107 IONAME(OutputLogical)(cookie, true); 108 ASSERT_DEATH(IONAME(OutputLogical)(cookie, true), 109 "Internal write overran available records"); 110 } 111 112 TEST(TestIOCrash, OverwriteBufferRealTest) { 113 static constexpr int bufferSize{1}; 114 static char buffer[bufferSize]; 115 static const char *format{"(F1)"}; 116 auto *cookie{IONAME(BeginInternalFormattedOutput)( 117 buffer, bufferSize, format, std::strlen(format))}; 118 IONAME(OutputReal32)(cookie, 1.); 119 EXPECT_DEATH(IONAME(OutputReal32)(cookie, 1.), 120 "Internal write overran available records"); 121 122 std::memset(buffer, '\0', bufferSize); 123 cookie = IONAME(BeginInternalFormattedOutput)( 124 buffer, bufferSize, format, std::strlen(format)); 125 IONAME(OutputReal64)(cookie, 1.); 126 EXPECT_DEATH(IONAME(OutputReal64)(cookie, 1.), 127 "Internal write overran available records"); 128 } 129 130 TEST(TestIOCrash, OverwriteBufferComplexTest) { 131 static constexpr int bufferSize{8}; 132 static char buffer[bufferSize]; 133 static const char *format{"(Z1,Z1)"}; 134 auto *cookie{IONAME(BeginInternalFormattedOutput)( 135 buffer, bufferSize, format, std::strlen(format))}; 136 IONAME(OutputComplex32)(cookie, 1., 1.); 137 EXPECT_DEATH(IONAME(OutputComplex32)(cookie, 1., 1.), 138 "Internal write overran available records"); 139 140 std::memset(buffer, '\0', bufferSize); 141 cookie = IONAME(BeginInternalFormattedOutput)( 142 buffer, bufferSize, format, std::strlen(format)); 143 IONAME(OutputComplex64)(cookie, 1., 1.); 144 EXPECT_DEATH(IONAME(OutputComplex64)(cookie, 1., 1.), 145 "Internal write overran available records"); 146 } 147 148 TEST(TestIOCrash, OverwriteBufferIntegerTest) { 149 static constexpr int bufferSize{1}; 150 static char buffer[bufferSize]; 151 static const char *format{"(I1)"}; 152 auto *cookie{IONAME(BeginInternalFormattedOutput)( 153 buffer, bufferSize, format, std::strlen(format))}; 154 IONAME(OutputInteger64)(cookie, 0xdeadbeef); 155 ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xdeadbeef), 156 "Internal write overran available records"); 157 } 158