[flang-commits] [flang] 168b206 - [flang] Unittests for runtime terminator

Andrzej Warzynski via flang-commits flang-commits at lists.llvm.org
Thu Mar 18 08:55:05 PDT 2021


Author: Asher Mancinelli
Date: 2021-03-18T15:54:48Z
New Revision: 168b206cd8efb59438a1db65d8e1639ae2c9f662

URL: https://github.com/llvm/llvm-project/commit/168b206cd8efb59438a1db65d8e1639ae2c9f662
DIFF: https://github.com/llvm/llvm-project/commit/168b206cd8efb59438a1db65d8e1639ae2c9f662.diff

LOG: [flang] Unittests for runtime terminator

Create test fixture for runtime tests which enables verification
of failure cases. Test some runtime IO APIs for failure cases.
Support testing efforts in D98303. Expand on effort discussed
in D98601.

Reviewed By: awarzynski

Differential Revision: https://reviews.llvm.org/D98652

Added: 
    flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp
    flang/unittests/RuntimeGTest/CrashHandlerFixture.h
    flang/unittests/RuntimeGTest/RuntimeCrashTest.cpp

Modified: 
    flang/unittests/RuntimeGTest/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/flang/unittests/RuntimeGTest/CMakeLists.txt b/flang/unittests/RuntimeGTest/CMakeLists.txt
index 77aff3069f14..f26cb44be5fe 100644
--- a/flang/unittests/RuntimeGTest/CMakeLists.txt
+++ b/flang/unittests/RuntimeGTest/CMakeLists.txt
@@ -1,5 +1,7 @@
 add_flang_unittest(FlangRuntimeTests
   CharacterTest.cpp
+  RuntimeCrashTest.cpp
+  CrashHandlerFixture.cpp
 )
 
 target_link_libraries(FlangRuntimeTests

diff  --git a/flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp b/flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp
new file mode 100644
index 000000000000..315a555789e7
--- /dev/null
+++ b/flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp
@@ -0,0 +1,34 @@
+//===-- flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "CrashHandlerFixture.h"
+#include "../../runtime/terminator.h"
+#include <cstdarg>
+#include <cstdlib>
+
+// Replaces Fortran runtime's crash handler so we can verify the crash message
+[[noreturn]] static void CatchCrash(
+    const char *sourceFile, int sourceLine, const char *message, va_list &ap) {
+  char buffer[1000];
+  std::vsnprintf(buffer, sizeof buffer, message, ap);
+  va_end(ap);
+  llvm::errs()
+      << "Test "
+      << ::testing::UnitTest::GetInstance()->current_test_info()->name()
+      << " crashed in file "
+      << (sourceFile ? sourceFile : "unknown source file") << '(' << sourceLine
+      << "): " << buffer << '\n';
+  std::exit(EXIT_FAILURE);
+}
+
+// Register the crash handler above when creating each unit test in this suite
+void CrashHandlerFixture::SetUp() {
+  static bool isCrashHanlderRegistered{false};
+  if (not isCrashHanlderRegistered)
+    Fortran::runtime::Terminator::RegisterCrashHandler(CatchCrash);
+  isCrashHanlderRegistered = true;
+}

diff  --git a/flang/unittests/RuntimeGTest/CrashHandlerFixture.h b/flang/unittests/RuntimeGTest/CrashHandlerFixture.h
new file mode 100644
index 000000000000..d368c6fb55ba
--- /dev/null
+++ b/flang/unittests/RuntimeGTest/CrashHandlerFixture.h
@@ -0,0 +1,21 @@
+//===-- flang/unittests/RuntimeGTest/CrashHandlerFixture.h ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// Test fixture registers a custom crash handler to ensure death tests fail
+/// with expected message.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_FLANG_UNITTESTS_RUNTIMEGTEST_CRASHHANDLERFIXTURE_H
+#define LLVM_FLANG_UNITTESTS_RUNTIMEGTEST_CRASHHANDLERFIXTURE_H
+#include <gtest/gtest.h>
+
+struct CrashHandlerFixture : testing::Test {
+  void SetUp();
+};
+
+#endif

diff  --git a/flang/unittests/RuntimeGTest/RuntimeCrashTest.cpp b/flang/unittests/RuntimeGTest/RuntimeCrashTest.cpp
new file mode 100644
index 000000000000..c8945409c8c7
--- /dev/null
+++ b/flang/unittests/RuntimeGTest/RuntimeCrashTest.cpp
@@ -0,0 +1,157 @@
+//===-- flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// Selected APIs are tested here to support development of unit tests for other
+/// runtime components and ensure the test fixture handles crashes as we expect.
+//
+//===----------------------------------------------------------------------===//
+#include "CrashHandlerFixture.h"
+#include "../../runtime/io-api.h"
+#include "../../runtime/terminator.h"
+#include <gtest/gtest.h>
+
+using namespace Fortran::runtime;
+using namespace Fortran::runtime::io;
+
+//------------------------------------------------------------------------------
+/// Test crashes through direct calls to terminator methods
+//------------------------------------------------------------------------------
+struct TestTerminator : CrashHandlerFixture {};
+
+#define TEST_CRASH_HANDLER_MESSAGE \
+  "Intentionally crashing runtime for unit test"
+
+TEST(TestTerminator, CrashTest) {
+  static Fortran::runtime::Terminator t;
+  ASSERT_DEATH(t.Crash(TEST_CRASH_HANDLER_MESSAGE), TEST_CRASH_HANDLER_MESSAGE);
+}
+
+#undef TEST_CRASH_HANDLER_MESSAGE
+
+TEST(TestTerminator, CheckFailedLocationTest) {
+  static Fortran::runtime::Terminator t;
+  ASSERT_DEATH(t.CheckFailed("predicate", "someFileName", 789),
+      "RUNTIME_CHECK\\(predicate\\) failed at someFileName\\(789\\)");
+}
+
+TEST(TestTerminator, CheckFailedTest) {
+  static Fortran::runtime::Terminator t;
+  ASSERT_DEATH(t.CheckFailed("predicate"),
+      "RUNTIME_CHECK\\(predicate\\) failed at \\(null\\)\\(0\\)");
+}
+
+//------------------------------------------------------------------------------
+/// Test misuse of io api
+//------------------------------------------------------------------------------
+struct TestIOCrash : CrashHandlerFixture {};
+
+TEST(TestIOCrash, FormatDescriptorWriteMismatchTest) {
+  static constexpr int bufferSize{4};
+  static char buffer[bufferSize];
+  static const char *format{"(A4)"};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(
+      buffer, bufferSize, format, std::strlen(format))};
+  ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xfeedface),
+      "Data edit descriptor 'A' may not be used with an INTEGER data item");
+}
+
+TEST(TestIOCrash, InvalidFormatCharacterTest) {
+  static constexpr int bufferSize{1};
+  static char buffer[bufferSize];
+  static const char *format{"(C1)"};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(
+      buffer, bufferSize, format, std::strlen(format))};
+  ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xfeedface),
+      "Unknown 'C' edit descriptor in FORMAT");
+}
+
+//------------------------------------------------------------------------------
+/// Test buffer overwrites with Output* functions
+/// Each test performs the tested IO operation correctly first, before causing
+/// an overwrite to demonstrate that the failure is caused by the overwrite and
+/// not a misuse of the API.
+//------------------------------------------------------------------------------
+TEST(TestIOCrash, OverwriteBufferAsciiTest) {
+  static constexpr int bufferSize{4};
+  static char buffer[bufferSize];
+  static const char *format{"(A4)"};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(
+      buffer, bufferSize, format, std::strlen(format))};
+  IONAME(OutputAscii)(cookie, "four", bufferSize);
+  ASSERT_DEATH(IONAME(OutputAscii)(cookie, "Too many characters!", 20),
+      "Internal write overran available records");
+}
+
+TEST(TestIOCrash, OverwriteBufferCharacterTest) {
+  static constexpr int bufferSize{1};
+  static char buffer[bufferSize];
+  static const char *format{"(A1)"};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(
+      buffer, bufferSize, format, std::strlen(format))};
+  IONAME(OutputCharacter)(cookie, "a", 1);
+  ASSERT_DEATH(IONAME(OutputCharacter)(cookie, "a", 1),
+      "Internal write overran available records");
+}
+
+TEST(TestIOCrash, OverwriteBufferLogicalTest) {
+  static constexpr int bufferSize{1};
+  static char buffer[bufferSize];
+  static const char *format{"(L1)"};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(
+      buffer, bufferSize, format, std::strlen(format))};
+  IONAME(OutputLogical)(cookie, true);
+  ASSERT_DEATH(IONAME(OutputLogical)(cookie, true),
+      "Internal write overran available records");
+}
+
+TEST(TestIOCrash, OverwriteBufferRealTest) {
+  static constexpr int bufferSize{1};
+  static char buffer[bufferSize];
+  static const char *format{"(F1)"};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(
+      buffer, bufferSize, format, std::strlen(format))};
+  IONAME(OutputReal32)(cookie, 1.);
+  EXPECT_DEATH(IONAME(OutputReal32)(cookie, 1.),
+      "Internal write overran available records");
+
+  std::memset(buffer, '\0', bufferSize);
+  cookie = IONAME(BeginInternalFormattedOutput)(
+      buffer, bufferSize, format, std::strlen(format));
+  IONAME(OutputReal64)(cookie, 1.);
+  EXPECT_DEATH(IONAME(OutputReal64)(cookie, 1.),
+      "Internal write overran available records");
+}
+
+TEST(TestIOCrash, OverwriteBufferComplexTest) {
+  static constexpr int bufferSize{8};
+  static char buffer[bufferSize];
+  static const char *format{"(Z1,Z1)"};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(
+      buffer, bufferSize, format, std::strlen(format))};
+  IONAME(OutputComplex32)(cookie, 1., 1.);
+  EXPECT_DEATH(IONAME(OutputComplex32)(cookie, 1., 1.),
+      "Internal write overran available records");
+
+  std::memset(buffer, '\0', bufferSize);
+  cookie = IONAME(BeginInternalFormattedOutput)(
+      buffer, bufferSize, format, std::strlen(format));
+  IONAME(OutputComplex64)(cookie, 1., 1.);
+  EXPECT_DEATH(IONAME(OutputComplex64)(cookie, 1., 1.),
+      "Internal write overran available records");
+}
+
+TEST(TestIOCrash, OverwriteBufferIntegerTest) {
+  static constexpr int bufferSize{1};
+  static char buffer[bufferSize];
+  static const char *format{"(I1)"};
+  auto *cookie{IONAME(BeginInternalFormattedOutput)(
+      buffer, bufferSize, format, std::strlen(format))};
+  IONAME(OutputInteger64)(cookie, 0xdeadbeef);
+  ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xdeadbeef),
+      "Internal write overran available records");
+}


        


More information about the flang-commits mailing list