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

source code of flang/unittests/Runtime/RuntimeCrashTest.cpp