1 //===-- flang/unittests/Runtime/CrashHandlerFixture.cpp ---------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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.
12 //===----------------------------------------------------------------------===//
13 #include "CrashHandlerFixture.h"
15 #include "../../runtime/terminator.h"
16 #include "flang/Runtime/io-api.h"
17 #include "flang/Runtime/transformational.h"
18 #include <gtest/gtest.h>
20 using namespace Fortran::runtime
;
21 using namespace Fortran::runtime::io
;
22 using Fortran::common::TypeCategory
;
24 //------------------------------------------------------------------------------
25 /// Test crashes through direct calls to terminator methods
26 //------------------------------------------------------------------------------
27 struct TestTerminator
: CrashHandlerFixture
{};
29 #define TEST_CRASH_HANDLER_MESSAGE \
30 "Intentionally crashing runtime for unit test"
32 TEST(TestTerminator
, CrashTest
) {
33 static Fortran::runtime::Terminator t
;
34 ASSERT_DEATH(t
.Crash(TEST_CRASH_HANDLER_MESSAGE
), TEST_CRASH_HANDLER_MESSAGE
);
37 #undef TEST_CRASH_HANDLER_MESSAGE
39 TEST(TestTerminator
, CheckFailedLocationTest
) {
40 static Fortran::runtime::Terminator t
;
41 ASSERT_DEATH(t
.CheckFailed("predicate", "someFileName", 789),
42 "RUNTIME_CHECK\\(predicate\\) failed at someFileName\\(789\\)");
45 TEST(TestTerminator
, CheckFailedTest
) {
46 static Fortran::runtime::Terminator t
;
47 ASSERT_DEATH(t
.CheckFailed("predicate"),
48 "RUNTIME_CHECK\\(predicate\\) failed at \\(null\\)\\(0\\)");
51 //------------------------------------------------------------------------------
52 /// Test misuse of io api
53 //------------------------------------------------------------------------------
54 struct TestIOCrash
: CrashHandlerFixture
{};
56 TEST(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");
66 TEST(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");
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 //------------------------------------------------------------------------------
82 TEST(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");
93 TEST(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");
104 TEST(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");
115 TEST(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");
125 std::memset(buffer
, '\0', bufferSize
);
126 cookie
= IONAME(BeginInternalFormattedOutput
)(
127 buffer
, bufferSize
, format
, std::strlen(format
));
128 IONAME(OutputReal64
)(cookie
, 1.);
129 EXPECT_DEATH(IONAME(OutputReal64
)(cookie
, 1.),
130 "Internal write overran available records");
133 TEST(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");
143 std::memset(buffer
, '\0', bufferSize
);
144 cookie
= IONAME(BeginInternalFormattedOutput
)(
145 buffer
, bufferSize
, format
, std::strlen(format
));
146 IONAME(OutputComplex64
)(cookie
, 1., 1.);
147 EXPECT_DEATH(IONAME(OutputComplex64
)(cookie
, 1., 1.),
148 "Internal write overran available records");
151 TEST(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");
162 //------------------------------------------------------------------------------
163 /// Test conformity issue reports in transformational intrinsics
164 //------------------------------------------------------------------------------
165 struct TestIntrinsicCrash
: CrashHandlerFixture
{};
167 TEST(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()};
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");