[flang-commits] [flang] [flang][test] Fix ASAN error in unit tests (PR #218917)

via flang-commits flang-commits at lists.llvm.org
Wed Aug 26 06:05:26 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-semantics

Author: David Spickett (DavidSpickett)

<details>
<summary>Changes</summary>

When flang is built with ASAN, one of the unit tests fails:
```
[ RUN      ] FrontendActionTest.ParseSyntaxOnly
=================================================================
==94036==ERROR: AddressSanitizer: heap-use-after-free on address 0xef60299e1268 at pc 0xbf00842915d0 bp 0xffffcc819e50 sp 0xffffcc819e48
READ of size 2 at 0xef60299e1268 thread T0
    #<!-- -->0 0xbf00842915cc in getShowColors /home/davspi01/llvm-project/llvm/../clang/include/clang/Basic/DiagnosticOptions.def:68:14
    #<!-- -->1 0xbf00842915cc in showColors /home/davspi01/llvm-project/llvm/../clang/include/clang/Basic/DiagnosticOptions.h:159:13
    #<!-- -->2 0xbf00842915cc in Fortran::frontend::TextDiagnosticPrinter::HandleDiagnostic(clang::DiagnosticsEngine::Level, clang::Diagnostic const&) /home/davspi01/llvm-project/flang/lib/Frontend/TextDiagnosticPrinter.cpp:116:27
    #<!-- -->3 0xbf0088f08ef0 in clang::DiagnosticsEngine::Report(clang::DiagnosticsEngine::Level, clang::Diagnostic const&) /home/davspi01/llvm-project/clang/lib/Basic/Diagnostic.cpp:625:11
    #<!-- -->4 0xbf0088f09584 in clang::DiagnosticsEngine::ProcessDiag(clang::DiagnosticBuilder const&) /home/davspi01/llvm-project/clang/lib/Basic/Diagnostic.cpp:705:3
    #<!-- -->5 0xbf0088f099ac in clang::DiagnosticsEngine::EmitDiagnostic(clang::DiagnosticBuilder const&, bool) /home/davspi01/llvm-project/clang/lib/Basic/Diagnostic.cpp:727:15
    #<!-- -->6 0xbf0082d78778 in Emit /home/davspi01/llvm-project/llvm/../clang/include/clang/Basic/Diagnostic.h:1332:28
    #<!-- -->7 0xbf0082d78778 in clang::DiagnosticBuilder::~DiagnosticBuilder() /home/davspi01/llvm-project/llvm/../clang/include/clang/Basic/Diagnostic.h:1367:26
    #<!-- -->8 0xbf0083dacd7c in Fortran::frontend::FrontendAction::reportFatalSemanticErrors() /home/davspi01/llvm-project/flang/lib/Frontend/FrontendAction.cpp:310:5
<...>
```
* CompilerInstance is defaut constructed, which means it has a default constructed CompilerInvocation.
* CompilerInstance::createDiagnostics is called.
* It makes a clang::DiagnosticsEngine and gives it a reference to whatever getDiagnosticOpts() returns.
* That returns invocation->getDiagnosticOpts().
* CompilerInstance::setInvocation is called with a new invocation, replacing the original invocation.
* The clang::DiagnosticsEngine now has a dangling reference to the options in the original invocation.

To fix this, I have implemented the same thing that b69dcb873476cd8e7d3f6f9ffd5b6d0bbe1a3a17 did for Clang.

Pass the invocation to the CompilerInstance constructor, and remove the setInvocation method. So that you cannot mix up the order.

---
Full diff: https://github.com/llvm/llvm-project/pull/218917.diff


6 Files Affected:

- (modified) flang/include/flang/Frontend/CompilerInstance.h (+2-5) 
- (modified) flang/lib/Frontend/CompilerInstance.cpp (+4-8) 
- (modified) flang/unittests/Frontend/CodeGenActionTest.cpp (+1-2) 
- (modified) flang/unittests/Frontend/CompilerInstanceTest.cpp (+2-4) 
- (modified) flang/unittests/Frontend/FrontendActionTest.cpp (+4-7) 
- (modified) flang/unittests/Semantics/OpenMPUtils.cpp (+4-7) 


``````````diff
diff --git a/flang/include/flang/Frontend/CompilerInstance.h b/flang/include/flang/Frontend/CompilerInstance.h
index c0acd57cdc9ee..9dc1701f290fc 100644
--- a/flang/include/flang/Frontend/CompilerInstance.h
+++ b/flang/include/flang/Frontend/CompilerInstance.h
@@ -111,7 +111,8 @@ class CompilerInstance {
   /// @}
 
 public:
-  explicit CompilerInstance();
+  explicit CompilerInstance(std::shared_ptr<CompilerInvocation> invocation =
+                                std::make_shared<CompilerInvocation>());
 
   ~CompilerInstance();
 
@@ -119,13 +120,9 @@ class CompilerInstance {
   /// {
 
   CompilerInvocation &getInvocation() {
-    assert(invocation && "Compiler instance has no invocation!");
     return *invocation;
   };
 
-  /// Replace the current invocation.
-  void setInvocation(std::shared_ptr<CompilerInvocation> value);
-
   /// }
   /// @name File manager
   /// {
diff --git a/flang/lib/Frontend/CompilerInstance.cpp b/flang/lib/Frontend/CompilerInstance.cpp
index 2416d3b593481..caeb58d9f8fdc 100644
--- a/flang/lib/Frontend/CompilerInstance.cpp
+++ b/flang/lib/Frontend/CompilerInstance.cpp
@@ -33,11 +33,12 @@
 
 using namespace Fortran::frontend;
 
-CompilerInstance::CompilerInstance()
-    : invocation(new CompilerInvocation()),
-      allSources(new Fortran::parser::AllSources()),
+CompilerInstance::CompilerInstance(
+    std::shared_ptr<CompilerInvocation> invocation)
+    : invocation(invocation), allSources(new Fortran::parser::AllSources()),
       allCookedSources(new Fortran::parser::AllCookedSources(*allSources)),
       parsing(new Fortran::parser::Parsing(*allCookedSources)) {
+  assert(invocation && "Invocation must not be null.");
   // TODO: This is a good default during development, but ultimately we should
   // give the user the opportunity to specify this.
   allSources->set_encoding(Fortran::parser::Encoding::UTF_8);
@@ -47,11 +48,6 @@ CompilerInstance::~CompilerInstance() {
   assert(outputFiles.empty() && "Still output files in flight?");
 }
 
-void CompilerInstance::setInvocation(
-    std::shared_ptr<CompilerInvocation> value) {
-  invocation = std::move(value);
-}
-
 void CompilerInstance::setSemaOutputStream(raw_ostream &value) {
   ownedSemaOutputStream.release();
   semaOutputStream = &value;
diff --git a/flang/unittests/Frontend/CodeGenActionTest.cpp b/flang/unittests/Frontend/CodeGenActionTest.cpp
index e606456663eec..2d1aa1cf188e4 100644
--- a/flang/unittests/Frontend/CodeGenActionTest.cpp
+++ b/flang/unittests/Frontend/CodeGenActionTest.cpp
@@ -99,9 +99,8 @@ TEST(CodeGenAction, GracefullyHandleLLVMConversionFailure) {
   auto diagPrinter = std::make_unique<Fortran::frontend::TextDiagnosticPrinter>(
       diagnosticsOS, diagOpts);
 
-  CompilerInstance ci;
+  CompilerInstance ci(std::make_shared<CompilerInvocation>());
   ci.createDiagnostics(diagPrinter.get(), /*ShouldOwnClient=*/false);
-  ci.setInvocation(std::make_shared<CompilerInvocation>());
   ci.setOutputStream(std::make_unique<llvm::raw_null_ostream>());
   ci.getInvocation().getCodeGenOpts().OptimizationLevel = 0;
 
diff --git a/flang/unittests/Frontend/CompilerInstanceTest.cpp b/flang/unittests/Frontend/CompilerInstanceTest.cpp
index 5cd360e7a2828..98953531acb4e 100644
--- a/flang/unittests/Frontend/CompilerInstanceTest.cpp
+++ b/flang/unittests/Frontend/CompilerInstanceTest.cpp
@@ -101,17 +101,15 @@ TEST(CompilerInstance, AllowDiagnosticLogWithUnownedDiagnosticConsumer) {
 
 TEST(CompilerInstance,
     OpenAccDefaultNoneScalarsStrictDisableOptionUsesDriverTable) {
-  CompilerInstance compInst;
-  compInst.createDiagnostics();
-
   auto invocation = std::make_shared<CompilerInvocation>();
+  CompilerInstance compInst(invocation);
+  compInst.createDiagnostics();
   invocation->getTargetOpts().triple =
       llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());
 
   llvm::InitializeAllTargets();
   llvm::InitializeAllTargetMCs();
 
-  compInst.setInvocation(std::move(invocation));
   ASSERT_TRUE(compInst.setUpTargetMachine());
   auto &context = compInst.createNewSemanticsContext();
 
diff --git a/flang/unittests/Frontend/FrontendActionTest.cpp b/flang/unittests/Frontend/FrontendActionTest.cpp
index bdf5a23fdbf6a..ef14149d539fa 100644
--- a/flang/unittests/Frontend/FrontendActionTest.cpp
+++ b/flang/unittests/Frontend/FrontendActionTest.cpp
@@ -37,8 +37,9 @@ class FrontendActionTest : public ::testing::Test {
 
   std::error_code ec;
 
-  CompilerInstance compInst;
-  std::shared_ptr<CompilerInvocation> invoc;
+  std::shared_ptr<CompilerInvocation> invoc =
+      std::make_shared<CompilerInvocation>();
+  CompilerInstance compInst{invoc};
 
   void SetUp() override {
     // Generate a unique test file name.
@@ -60,10 +61,6 @@ class FrontendActionTest : public ::testing::Test {
     inputFilePath = cwd.c_str();
     inputFilePath += "/" + inputFileName;
 
-    // Prepare the compiler (CompilerInvocation + CompilerInstance)
-    compInst.createDiagnostics();
-    invoc = std::make_shared<CompilerInvocation>();
-
     // Set-up default target triple and initialize LLVM Targets so that the
     // target data layout can be passed to the frontend.
     invoc->getTargetOpts().triple =
@@ -71,7 +68,7 @@ class FrontendActionTest : public ::testing::Test {
     llvm::InitializeAllTargets();
     llvm::InitializeAllTargetMCs();
 
-    compInst.setInvocation(std::move(invoc));
+    compInst.createDiagnostics();
     compInst.getFrontendOpts().inputs.push_back(
         FrontendInputFile(inputFilePath, Language::Fortran));
   }
diff --git a/flang/unittests/Semantics/OpenMPUtils.cpp b/flang/unittests/Semantics/OpenMPUtils.cpp
index 7b003d8fa4af8..9a662b108005e 100644
--- a/flang/unittests/Semantics/OpenMPUtils.cpp
+++ b/flang/unittests/Semantics/OpenMPUtils.cpp
@@ -45,8 +45,9 @@ class OpenMPUtilsTest : public ::testing::Test {
 
   std::error_code ec;
 
-  CompilerInstance compInst;
-  std::shared_ptr<CompilerInvocation> invoc;
+  std::shared_ptr<CompilerInvocation> invoc =
+      std::make_shared<CompilerInvocation>();
+  CompilerInstance compInst{invoc};
 
   void SetUp() override {
     // Generate a unique test file name.
@@ -68,10 +69,6 @@ class OpenMPUtilsTest : public ::testing::Test {
     inputFilePath = cwd.c_str();
     inputFilePath += "/" + inputFileName;
 
-    // Prepare the compiler (CompilerInvocation + CompilerInstance)
-    compInst.createDiagnostics();
-    invoc = std::make_shared<CompilerInvocation>();
-
     // Set-up default target triple and initialize LLVM Targets so that the
     // target data layout can be passed to the frontend.
     invoc->getTargetOpts().triple =
@@ -80,7 +77,7 @@ class OpenMPUtilsTest : public ::testing::Test {
     llvm::InitializeAllTargets();
     llvm::InitializeAllTargetMCs();
 
-    compInst.setInvocation(std::move(invoc));
+    compInst.createDiagnostics();
     compInst.getFrontendOpts().inputs.push_back(
         FrontendInputFile(inputFilePath, Language::Fortran));
     compInst.getFrontendOpts().features.Enable(common::LanguageFeature::OpenMP);

``````````

</details>


https://github.com/llvm/llvm-project/pull/218917


More information about the flang-commits mailing list