https://github.com/schittir created
https://github.com/llvm/llvm-project/pull/184558
This is an x86_64 MSVC issue where "Negative store size!" assert fails when
SplitAfterSize is negative, because the memory regions after second (or
subsequent) vbptrs are calculated incorrectly.
The old calculation was:
SplitAfterSize = LastStoreSize - SplitAfterOffset;
The correct size should be:
SplitAfterSize = (LastStoreOffset + LastStoreSize) -
SplitAfterOffset;
Since all store regions extend to the end of the non-virtual portion (NVSize),
this patch simplifies it to:
SplitAfterSize = NVSize - SplitAfterOffset;
>From 47babc5ed2d405bcc9a330b44b619967919d6a46 Mon Sep 17 00:00:00 2001
From: Sindhu Chittireddy <[email protected]>
Date: Tue, 3 Mar 2026 21:00:28 -0800
Subject: [PATCH] Fix bug in the calculation of vbptr memory region split.
This is an x86_64 MSVC issue where "Negative store size!" assert fails
because SplitAfterSize is negative, i.e., the memory regions after second
(or subsequent) vbptrs are calculated incorrectly.
The old calculation was:
SplitAfterSize = LastStoreSize - SplitAfterOffset;
The correct size should be:
SplitAfterSize = (LastStoreOffset + LastStoreSize) -
SplitAfterOffset;
Since all store regions extend to the end of the non-virtual portion
(NVSize), this patch simplifies it to:
SplitAfterSize = NVSize - SplitAfterOffset;
---
clang/lib/CodeGen/CGExprCXX.cpp | 3 +-
.../microsoft-abi-multiple-vbptrs.cpp | 86 +++++++++++++++++++
2 files changed, 87 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 074c124dbf01b..c202d3612f734 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -539,7 +539,6 @@ static void EmitNullBaseClassInitialization(CodeGenFunction
&CGF,
break;
std::pair<CharUnits, CharUnits> LastStore = Stores.pop_back_val();
CharUnits LastStoreOffset = LastStore.first;
- CharUnits LastStoreSize = LastStore.second;
CharUnits SplitBeforeOffset = LastStoreOffset;
CharUnits SplitBeforeSize = VBPtrOffset - SplitBeforeOffset;
@@ -548,7 +547,7 @@ static void EmitNullBaseClassInitialization(CodeGenFunction
&CGF,
Stores.emplace_back(SplitBeforeOffset, SplitBeforeSize);
CharUnits SplitAfterOffset = VBPtrOffset + VBPtrWidth;
- CharUnits SplitAfterSize = LastStoreSize - SplitAfterOffset;
+ CharUnits SplitAfterSize = NVSize - SplitAfterOffset;
assert(!SplitAfterSize.isNegative() && "negative store size!");
if (!SplitAfterSize.isZero())
Stores.emplace_back(SplitAfterOffset, SplitAfterSize);
diff --git a/clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp
b/clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp
new file mode 100644
index 0000000000000..f89c1a3f5c3a0
--- /dev/null
+++ b/clang/test/CodeGenCXX/microsoft-abi-multiple-vbptrs.cpp
@@ -0,0 +1,86 @@
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=c++11 -emit-llvm -o - %s |
FileCheck %s
+
+// Test for the fix in EmitNullBaseClassInitialization where the calculation
+// of SplitAfterSize was incorrect when multiple vbptrs are present.
+
+struct VBase1 {
+ virtual ~VBase1();
+ int x;
+};
+
+struct VBase2 {
+ virtual ~VBase2();
+ int y;
+};
+
+// Base class with two virtual base classes.
+struct Base : virtual VBase1, virtual VBase2 {
+ int data;
+};
+
+// Derived class that needs to initialize Base.
+// The constructor will call EmitNullBaseClassInitialization for Base.
+struct Derived : Base {
+ Derived();
+ int more_data;
+};
+
+// CHECK-LABEL: define dso_local noundef ptr @"??0Derived@@QEAA@XZ"
+// Check that memory initialization (memset or memcpy) correctly covers
+// the non-virtual portion of the base class, properly handling vbptrs.
+
+// CHECK: call void @llvm.memset
+
+Derived::Derived() : Base() {
+ // Constructor body
+ data = 42;
+ more_data = 100;
+}
+
+// Test case with three virtual bases.
+struct VBase3 {
+ virtual ~VBase3();
+ int z;
+};
+
+struct ComplexBase : virtual VBase1, virtual VBase2, virtual VBase3 {
+ int a, b, c;
+};
+
+struct ComplexDerived : ComplexBase {
+ ComplexDerived();
+ int d;
+};
+
+// CHECK-LABEL: define dso_local noundef ptr @"??0ComplexDerived@@QEAA@XZ"
+// CHECK: call void @llvm.memset
+
+ComplexDerived::ComplexDerived() : ComplexBase() {
+ a = 1;
+ b = 2;
+ c = 3;
+ d = 4;
+}
+
+// Test case with data members initialized using memcpy
+struct VBase4 {
+ virtual ~VBase4();
+ int w;
+};
+
+struct BaseWithPtrToMember : virtual VBase1, virtual VBase4 {
+ int Base::*member_ptr;
+ int value;
+};
+
+struct DerivedWithPtrToMember : BaseWithPtrToMember {
+ DerivedWithPtrToMember();
+};
+
+// CHECK-LABEL: define dso_local noundef ptr
@"??0DerivedWithPtrToMember@@QEAA@XZ"
+// This should use memcpy instead of memset due to the pointer-to-member.
+// CHECK: call void @llvm.memcpy
+
+DerivedWithPtrToMember::DerivedWithPtrToMember() : BaseWithPtrToMember() {
+ value = 50;
+}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits