[flang-commits] [flang] [flang][OpenMP] Keep hermetic embedded module parse tree alive (PR #207491)
via flang-commits
flang-commits at lists.llvm.org
Sat Jul 4 00:21:35 PDT 2026
https://github.com/MattPD created https://github.com/llvm/llvm-project/pull/207491
Fix a use-after-free when lowering materializes an imported declare mapper or declare reduction owned by a module embedded in a hermetic module file (-fhermetic-module-files).
ModFileReader::Read resolved the embedded modules from a local parser::Program that was destroyed when Read returned, leaving the symbols resolved from it dangling. MapperDetails and UserReductionDetails hold raw parse-tree pointers, so a consumer that later materializes such an imported declaration dereferenced freed memory.
Retain the embedded parse tree in the SemanticsContext with SaveParseTree, as the primary module's tree already is, so those pointers stay valid through lowering. The new test covers materializing an imported declare mapper from an embedded module.
Assisted-by: Claude Opus 4.8, GPT-5.5.
>From 7cf4240e36485a7bc82e3ba9b3b9c01acc075eed Mon Sep 17 00:00:00 2001
From: "Matt P. Dziubinski" <matt-p.dziubinski at hpe.com>
Date: Thu, 2 Jul 2026 22:25:14 -0500
Subject: [PATCH] [flang][OpenMP] Keep hermetic embedded module parse tree
alive
Fix a use-after-free when lowering materializes an imported declare mapper or
declare reduction owned by a module embedded in a hermetic module file
(-fhermetic-module-files).
ModFileReader::Read resolved the embedded modules from a local parser::Program
that was destroyed when Read returned, leaving the symbols resolved from it
dangling. MapperDetails and UserReductionDetails hold raw parse-tree pointers, so
a consumer that later materializes such an imported declaration dereferenced
freed memory.
Retain the embedded parse tree in the SemanticsContext with SaveParseTree, as the
primary module's tree already is, so those pointers stay valid through lowering.
The new test covers materializing an imported declare mapper from an embedded
module.
Assisted-by: Claude Opus 4.8, GPT-5.5.
---
flang/lib/Semantics/mod-file.cpp | 7 +++-
.../Lower/OpenMP/declare-mapper-hermetic.f90 | 38 +++++++++++++++++++
2 files changed, 44 insertions(+), 1 deletion(-)
create mode 100644 flang/test/Lower/OpenMP/declare-mapper-hermetic.f90
diff --git a/flang/lib/Semantics/mod-file.cpp b/flang/lib/Semantics/mod-file.cpp
index fd1b1caa7fce1..96d749a571342 100644
--- a/flang/lib/Semantics/mod-file.cpp
+++ b/flang/lib/Semantics/mod-file.cpp
@@ -1727,7 +1727,12 @@ Scope *ModFileReader::Read(SourceName name, std::optional<bool> isIntrinsic,
// within the module file.
Scope *previousHermetic{context_.currentHermeticModuleFileScope()};
if (parseTree.v.size() > 1) {
- parser::Program hermeticModules{std::move(parseTree.v)};
+ // Retain the embedded modules' parse tree for the lifetime of the
+ // SemanticsContext: symbols resolved from it (e.g. UserReductionDetails and
+ // MapperDetails, which hold raw parse-tree pointers) outlive this function
+ // and are dereferenced later, including at lowering time.
+ parser::Program &hermeticModules{
+ context_.SaveParseTree(parser::Program{std::move(parseTree.v)})};
parseTree.v.emplace_back(std::move(hermeticModules.v.front()));
hermeticModules.v.pop_front();
Scope &hermeticScope{topScope.MakeScope(Scope::Kind::Global)};
diff --git a/flang/test/Lower/OpenMP/declare-mapper-hermetic.f90 b/flang/test/Lower/OpenMP/declare-mapper-hermetic.f90
new file mode 100644
index 0000000000000..334c8d25a8189
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-mapper-hermetic.f90
@@ -0,0 +1,38 @@
+! Hermetic module files embed the modules a module uses into its own .mod. A
+! consumer that materializes an imported declare mapper owned by such an embedded
+! module dereferences parse-tree pointers (MapperDetails) into it, so the embedded
+! module's parse tree must stay live past module-file reading. map_wrap re-exports
+! map_base (which owns the mapper) and is compiled hermetically; map_base.mod is
+! then removed so the consumer can only reach the mapper through the embedding.
+
+! RUN: rm -rf %t && split-file %s %t && cd %t
+! RUN: %flang_fc1 -fsyntax-only -fopenmp -fopenmp-version=50 map_base.f90
+! RUN: %flang_fc1 -fhermetic-module-files -fsyntax-only -fopenmp -fopenmp-version=50 map_wrap.f90
+! RUN: rm map_base.mod
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 map.use.f90 -o - | FileCheck map.use.f90
+
+!--- map_base.f90
+module map_base
+ type :: t
+ integer :: x = 0
+ end type
+ !$omp declare mapper(mymapper : t :: v) map(v%x)
+end module
+
+!--- map_wrap.f90
+module map_wrap
+ use map_base
+end module
+
+!--- map.use.f90
+! CHECK: omp.declare_mapper @[[MAPPER:_QQMmap_base[A-Za-z0-9_.]*mymapper]]
+! CHECK: mapper(@[[MAPPER]])
+program main
+ use map_wrap
+ type(t) :: obj
+ obj%x = 0
+ !$omp target map(mapper(mymapper), tofrom: obj)
+ obj%x = obj%x + 1
+ !$omp end target
+ print *, obj%x
+end program
\ No newline at end of file
More information about the flang-commits
mailing list