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/io-api.h"
15 #include "../../runtime/terminator.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 
TEST(TestTerminator,CrashTest)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 
TEST(TestTerminator,CheckFailedLocationTest)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 
TEST(TestTerminator,CheckFailedTest)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 
TEST(TestIOCrash,FormatDescriptorWriteMismatchTest)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(OutputInteger64)(cookie, 0xfeedface),
60       "Data edit descriptor 'A' may not be used with an INTEGER data item");
61 }
62 
TEST(TestIOCrash,InvalidFormatCharacterTest)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 //------------------------------------------------------------------------------
TEST(TestIOCrash,OverwriteBufferAsciiTest)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 
TEST(TestIOCrash,OverwriteBufferCharacterTest)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 
TEST(TestIOCrash,OverwriteBufferLogicalTest)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 
TEST(TestIOCrash,OverwriteBufferRealTest)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 
TEST(TestIOCrash,OverwriteBufferComplexTest)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 
TEST(TestIOCrash,OverwriteBufferIntegerTest)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