1 //===-- flang/unittests/Runtime/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 "tools.h" 15 #include "../../runtime/terminator.h" 16 #include "flang/Runtime/io-api-consts.h" 17 #include "flang/Runtime/transformational.h" 18 #include <gtest/gtest.h> 19 20 using namespace Fortran::runtime; 21 using namespace Fortran::runtime::io; 22 using Fortran::common::TypeCategory; 23 24 //------------------------------------------------------------------------------ 25 /// Test crashes through direct calls to terminator methods 26 //------------------------------------------------------------------------------ 27 struct TestTerminator : CrashHandlerFixture {}; 28 29 #define TEST_CRASH_HANDLER_MESSAGE \ 30 "Intentionally crashing runtime for unit test" 31 32 TEST(TestTerminator, CrashTest) { 33 static Fortran::runtime::Terminator t; 34 ASSERT_DEATH(t.Crash(TEST_CRASH_HANDLER_MESSAGE), TEST_CRASH_HANDLER_MESSAGE); 35 } 36 37 #undef TEST_CRASH_HANDLER_MESSAGE 38 39 TEST(TestTerminator, CheckFailedLocationTest) { 40 static Fortran::runtime::Terminator t; 41 ASSERT_DEATH(t.CheckFailed("predicate", "someFileName", 789), 42 "RUNTIME_CHECK\\(predicate\\) failed at someFileName\\(789\\)"); 43 } 44 45 TEST(TestTerminator, CheckFailedTest) { 46 static Fortran::runtime::Terminator t("someFileName"); 47 ASSERT_DEATH(t.CheckFailed("predicate"), 48 "RUNTIME_CHECK\\(predicate\\) failed at someFileName\\(0\\)"); 49 } 50 51 //------------------------------------------------------------------------------ 52 /// Test misuse of io api 53 //------------------------------------------------------------------------------ 54 struct TestIOCrash : CrashHandlerFixture {}; 55 56 TEST(TestIOCrash, InvalidFormatCharacterTest) { 57 static constexpr int bufferSize{1}; 58 static char buffer[bufferSize]; 59 static const char *format{"(C1)"}; 60 auto *cookie{IONAME(BeginInternalFormattedOutput)( 61 buffer, bufferSize, format, std::strlen(format))}; 62 ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xfeedface), 63 "Unknown 'C' edit descriptor in FORMAT"); 64 } 65 66 //------------------------------------------------------------------------------ 67 /// Test buffer overwrites with Output* functions 68 /// Each test performs the tested IO operation correctly first, before causing 69 /// an overwrite to demonstrate that the failure is caused by the overwrite and 70 /// not a misuse of the API. 71 //------------------------------------------------------------------------------ 72 TEST(TestIOCrash, OverwriteBufferAsciiTest) { 73 static constexpr int bufferSize{4}; 74 static char buffer[bufferSize]; 75 static const char *format{"(A4)"}; 76 auto *cookie{IONAME(BeginInternalFormattedOutput)( 77 buffer, bufferSize, format, std::strlen(format))}; 78 IONAME(OutputAscii)(cookie, "four", bufferSize); 79 ASSERT_DEATH(IONAME(OutputAscii)(cookie, "Too many characters!", 20), 80 "Internal write overran available records"); 81 } 82 83 TEST(TestIOCrash, OverwriteBufferCharacterTest) { 84 static constexpr int bufferSize{1}; 85 static char buffer[bufferSize]; 86 static const char *format{"(A1)"}; 87 auto *cookie{IONAME(BeginInternalFormattedOutput)( 88 buffer, bufferSize, format, std::strlen(format))}; 89 IONAME(OutputCharacter)(cookie, "a", 1); 90 ASSERT_DEATH(IONAME(OutputCharacter)(cookie, "a", 1), 91 "Internal write overran available records"); 92 } 93 94 TEST(TestIOCrash, OverwriteBufferLogicalTest) { 95 static constexpr int bufferSize{1}; 96 static char buffer[bufferSize]; 97 static const char *format{"(L1)"}; 98 auto *cookie{IONAME(BeginInternalFormattedOutput)( 99 buffer, bufferSize, format, std::strlen(format))}; 100 IONAME(OutputLogical)(cookie, true); 101 ASSERT_DEATH(IONAME(OutputLogical)(cookie, true), 102 "Internal write overran available records"); 103 } 104 105 TEST(TestIOCrash, OverwriteBufferRealTest) { 106 static constexpr int bufferSize{1}; 107 static char buffer[bufferSize]; 108 static const char *format{"(F1)"}; 109 auto *cookie{IONAME(BeginInternalFormattedOutput)( 110 buffer, bufferSize, format, std::strlen(format))}; 111 IONAME(OutputReal32)(cookie, 1.); 112 EXPECT_DEATH(IONAME(OutputReal32)(cookie, 1.), 113 "Internal write overran available records"); 114 115 std::memset(buffer, '\0', bufferSize); 116 cookie = IONAME(BeginInternalFormattedOutput)( 117 buffer, bufferSize, format, std::strlen(format)); 118 IONAME(OutputReal64)(cookie, 1.); 119 EXPECT_DEATH(IONAME(OutputReal64)(cookie, 1.), 120 "Internal write overran available records"); 121 } 122 123 TEST(TestIOCrash, OverwriteBufferComplexTest) { 124 static constexpr int bufferSize{8}; 125 static char buffer[bufferSize]; 126 static const char *format{"(Z1,Z1)"}; 127 auto *cookie{IONAME(BeginInternalFormattedOutput)( 128 buffer, bufferSize, format, std::strlen(format))}; 129 IONAME(OutputComplex32)(cookie, 1., 1.); 130 EXPECT_DEATH(IONAME(OutputComplex32)(cookie, 1., 1.), 131 "Internal write overran available records"); 132 133 std::memset(buffer, '\0', bufferSize); 134 cookie = IONAME(BeginInternalFormattedOutput)( 135 buffer, bufferSize, format, std::strlen(format)); 136 IONAME(OutputComplex64)(cookie, 1., 1.); 137 EXPECT_DEATH(IONAME(OutputComplex64)(cookie, 1., 1.), 138 "Internal write overran available records"); 139 } 140 141 TEST(TestIOCrash, OverwriteBufferIntegerTest) { 142 static constexpr int bufferSize{1}; 143 static char buffer[bufferSize]; 144 static const char *format{"(I1)"}; 145 auto *cookie{IONAME(BeginInternalFormattedOutput)( 146 buffer, bufferSize, format, std::strlen(format))}; 147 IONAME(OutputInteger64)(cookie, 0xdeadbeef); 148 ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xdeadbeef), 149 "Internal write overran available records"); 150 } 151 152 //------------------------------------------------------------------------------ 153 /// Test conformity issue reports in transformational intrinsics 154 //------------------------------------------------------------------------------ 155 struct TestIntrinsicCrash : CrashHandlerFixture {}; 156 157 TEST(TestIntrinsicCrash, ConformityErrors) { 158 // ARRAY(2,3) and MASK(2,4) should trigger a runtime error. 159 auto array{MakeArray<TypeCategory::Integer, 4>( 160 std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; 161 auto mask{MakeArray<TypeCategory::Logical, 1>(std::vector<int>{2, 4}, 162 std::vector<std::uint8_t>{ 163 false, true, true, false, false, true, true, true})}; 164 StaticDescriptor<1, true> statDesc; 165 Descriptor &result{statDesc.descriptor()}; 166 167 ASSERT_DEATH(RTNAME(Pack)(result, *array, *mask, nullptr, __FILE__, __LINE__), 168 "Incompatible array arguments to PACK: dimension 2 of ARRAY= has extent " 169 "3 but MASK= has extent 4"); 170 } 171