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