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