xref: /llvm-project/flang/unittests/Runtime/RuntimeCrashTest.cpp (revision c91ba04328e1ded6f284469a7828d181324d4e30)
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