Skip to content

[C++20] [Modules] Fix the duplicated static initializer problem #114193

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 30, 2024

Conversation

ChuanqiXu9
Copy link
Member

Reproducer:

//--- a.cppm
export module a;
int func();
static int a = func();

//--- a.cpp
import a;

The func() should only execute once. However, before this patch we will somehow import static int a from a.cppm incorrectly and initialize that again.

This is super bad and can introduce serious runtime behaviors.

And also surprisingly, it looks like the root cause of the problem is simply some oversight choosing APIs.

Reproducer:

```
//--- a.cppm
export module a;
int func();
static int a = func();

//--- a.cpp
import a;
```

The `func()` should only execute once. However, before this patch
we will somehow import `static int a` from a.cppm incorrectly and
initialize that again.

This is super bad and can introduce serious runtime behaviors.

And also surprisingly, it looks like the root cause of the problem is
simply some oversight choosing APIs.
@ChuanqiXu9 ChuanqiXu9 added clang:modules C++20 modules and Clang Header Modules skip-precommit-approval PR for CI feedback, not intended for review labels Oct 30, 2024
@ChuanqiXu9 ChuanqiXu9 self-assigned this Oct 30, 2024
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels Oct 30, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 30, 2024

@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-modules

Author: Chuanqi Xu (ChuanqiXu9)

Changes

Reproducer:

//--- a.cppm
export module a;
int func();
static int a = func();

//--- a.cpp
import a;

The func() should only execute once. However, before this patch we will somehow import static int a from a.cppm incorrectly and initialize that again.

This is super bad and can introduce serious runtime behaviors.

And also surprisingly, it looks like the root cause of the problem is simply some oversight choosing APIs.


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

2 Files Affected:

  • (modified) clang/lib/CodeGen/CodeGenModule.cpp (+2-2)
  • (added) clang/test/Modules/static-initializer.cppm (+18)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 2bcca5e85bdfeb..ba376f9ecfacde 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -7146,8 +7146,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
     // For C++ standard modules we are done - we will call the module
     // initializer for imported modules, and that will likewise call those for
     // any imports it has.
-    if (CXX20ModuleInits && Import->getImportedOwningModule() &&
-        !Import->getImportedOwningModule()->isModuleMapModule())
+    if (CXX20ModuleInits && Import->getImportedModule() &&
+        Import->getImportedModule()->isNamedModule())
       break;
 
     // For clang C++ module map modules the initializers for sub-modules are
diff --git a/clang/test/Modules/static-initializer.cppm b/clang/test/Modules/static-initializer.cppm
new file mode 100644
index 00000000000000..10d4854ee67fa6
--- /dev/null
+++ b/clang/test/Modules/static-initializer.cppm
@@ -0,0 +1,18 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %t/a.cpp -fmodule-file=a=%t/a.pcm -emit-llvm -o - | FileCheck %t/a.cpp
+
+//--- a.cppm
+export module a;
+int func();
+static int a = func();
+
+//--- a.cpp
+import a;
+
+// CHECK-NOT: internal global
+// CHECK-NOT: __cxx_global_var_init
+

@ChuanqiXu9 ChuanqiXu9 merged commit 259eaa6 into llvm:main Oct 30, 2024
13 checks passed
@ChuanqiXu9 ChuanqiXu9 added this to the LLVM 19.X Release milestone Oct 30, 2024
@ChuanqiXu9
Copy link
Member Author

Given the problem is very serious and the solution is pretty simple, I'd like to backport this to 19.x.

@ChuanqiXu9
Copy link
Member Author

/cherry-pick 259eaa6

@llvmbot
Copy link
Member

llvmbot commented Oct 30, 2024

/pull-request #114197

NoumanAmir657 pushed a commit to NoumanAmir657/llvm-project that referenced this pull request Nov 4, 2024
…#114193)

Reproducer:

```
//--- a.cppm
export module a;
int func();
static int a = func();

//--- a.cpp
import a;
```

The `func()` should only execute once. However, before this patch we
will somehow import `static int a` from a.cppm incorrectly and
initialize that again.

This is super bad and can introduce serious runtime behaviors.

And also surprisingly, it looks like the root cause of the problem is
simply some oversight choosing APIs.
tru pushed a commit to llvmbot/llvm-project that referenced this pull request Nov 15, 2024
…#114193)

Reproducer:

```
//--- a.cppm
export module a;
int func();
static int a = func();

//--- a.cpp
import a;
```

The `func()` should only execute once. However, before this patch we
will somehow import `static int a` from a.cppm incorrectly and
initialize that again.

This is super bad and can introduce serious runtime behaviors.

And also surprisingly, it looks like the root cause of the problem is
simply some oversight choosing APIs.

(cherry picked from commit 259eaa6)
nikic pushed a commit to rust-lang/llvm-project that referenced this pull request Nov 20, 2024
…#114193)

Reproducer:

```
//--- a.cppm
export module a;
int func();
static int a = func();

//--- a.cpp
import a;
```

The `func()` should only execute once. However, before this patch we
will somehow import `static int a` from a.cppm incorrectly and
initialize that again.

This is super bad and can introduce serious runtime behaviors.

And also surprisingly, it looks like the root cause of the problem is
simply some oversight choosing APIs.

(cherry picked from commit 259eaa6)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category skip-precommit-approval PR for CI feedback, not intended for review
Projects
Development

Successfully merging this pull request may close these issues.

2 participants