[llvm] [VPlan][test] Fix use-after-free in dumpRecipeInPlan/dumpRecipeUnnamedVPValuesInPlan tests (PR #199275)

Thurston Dang via llvm-commits llvm-commits at lists.llvm.org
Fri May 22 13:23:07 PDT 2026


https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/199275

>From ab518722d3fcfe7869e7d4ed8eee941193544e98 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Fri, 22 May 2026 20:14:09 +0000
Subject: [PATCH 1/2] [VPlan][test] Fix use-after-free in
 dumpRecipeInPlan/dumpRecipeUnnamedVPValuesInPlan tests

https://github.com/llvm/llvm-project/pull/195891 exposed a use-after-free in the tests: `BinaryOperator *AI` [*] is deleted prior to VPlan's destructor, which expects all the operands to still be alive. This patch fixes the test (suggested by a Florian in https://github.com/llvm/llvm-project/pull/199252#pullrequestreview-4348337988), by ensuring the BinaryOperator is still at the time VPlan is deleted.

[*] No AI was harmed or used during the creation of this patch.
---
 .../Transforms/Vectorize/VPlanTest.cpp        | 218 +++++++++---------
 1 file changed, 114 insertions(+), 104 deletions(-)

diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
index 9326acb8269e6..65817472e5f70 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
@@ -1510,132 +1510,142 @@ TEST_F(VPRecipeTest, MayHaveSideEffectsAndMayReadWriteMemory) {
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 TEST_F(VPRecipeTest, dumpRecipeInPlan) {
-  VPlan &Plan = getPlan();
-  VPBasicBlock *VPBB0 = Plan.getEntry();
-  VPBasicBlock *VPBB1 = Plan.createVPBasicBlock("");
-  VPBlockUtils::connectBlocks(VPBB1, Plan.getScalarHeader());
-  VPBlockUtils::connectBlocks(VPBB0, VPBB1);
-
+  // AI must outlive VPlan &Plan
   IntegerType *Int32 = IntegerType::get(C, 32);
   auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32),
                                        PoisonValue::get(Int32));
   AI->setName("a");
-  SmallVector<VPValue *, 2> Args;
-  VPValue *ExtVPV1 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 1));
-  VPValue *ExtVPV2 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 2));
-  Args.push_back(ExtVPV1);
-  Args.push_back(ExtVPV2);
-  VPWidenRecipe *WidenR = new VPWidenRecipe(*AI, Args);
-  VPBB1->appendRecipe(WidenR);
 
   {
-    // Use EXPECT_EXIT to capture stderr and compare against expected output.
-    //
-    // Test VPValue::dump().
-    VPValue *VPV = WidenR;
-    EXPECT_EXIT(
-        {
-          VPV->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
-
-    VPRecipeBase *Def = WidenR;
-    EXPECT_EXIT(
-        {
-          Def->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
-
-    EXPECT_EXIT(
-        {
-          WidenR->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
+    VPlan &Plan = getPlan();
+    VPBasicBlock *VPBB0 = Plan.getEntry();
+    VPBasicBlock *VPBB1 = Plan.createVPBasicBlock("");
+    VPBlockUtils::connectBlocks(VPBB1, Plan.getScalarHeader());
+    VPBlockUtils::connectBlocks(VPBB0, VPBB1);
 
-    // Test VPRecipeBase::dump().
-    VPRecipeBase *R = WidenR;
-    EXPECT_EXIT(
-        {
-          R->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
+    SmallVector<VPValue *, 2> Args;
+    VPValue *ExtVPV1 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 1));
+    VPValue *ExtVPV2 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 2));
+    Args.push_back(ExtVPV1);
+    Args.push_back(ExtVPV2);
+    VPWidenRecipe *WidenR = new VPWidenRecipe(*AI, Args);
+    VPBB1->appendRecipe(WidenR);
+
+    {
+      // Use EXPECT_EXIT to capture stderr and compare against expected output.
+      //
+      // Test VPValue::dump().
+      VPValue *VPV = WidenR;
+      EXPECT_EXIT(
+          {
+            VPV->dump();
+            exit(0);
+          },
+          testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
+
+      VPRecipeBase *Def = WidenR;
+      EXPECT_EXIT(
+          {
+            Def->dump();
+            exit(0);
+          },
+          testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
+
+      EXPECT_EXIT(
+          {
+            WidenR->dump();
+            exit(0);
+          },
+          testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
+
+      // Test VPRecipeBase::dump().
+      VPRecipeBase *R = WidenR;
+      EXPECT_EXIT(
+          {
+            R->dump();
+            exit(0);
+          },
+          testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
+    }
   }
 
   delete AI;
 }
 
 TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesInPlan) {
-  VPlan &Plan = getPlan();
-  VPBasicBlock *VPBB0 = Plan.getEntry();
-  VPBasicBlock *VPBB1 = Plan.createVPBasicBlock("");
-  VPBlockUtils::connectBlocks(VPBB1, Plan.getScalarHeader());
-  VPBlockUtils::connectBlocks(VPBB0, VPBB1);
-
+  // AI must outlive VPlan &Plan
   IntegerType *Int32 = IntegerType::get(C, 32);
   auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32),
                                        PoisonValue::get(Int32));
   AI->setName("a");
-  SmallVector<VPValue *, 2> Args;
-  VPValue *ExtVPV1 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 1));
-  VPValue *ExtVPV2 = Plan.getOrAddLiveIn(AI);
-  Args.push_back(ExtVPV1);
-  Args.push_back(ExtVPV2);
-  VPInstruction *I1 =
-      new VPInstruction(Instruction::Add, {ExtVPV1, ExtVPV2},
-                        VPIRFlags::getDefaultFlags(Instruction::Add));
-  VPInstruction *I2 = new VPInstruction(
-      Instruction::Mul, {I1, I1}, VPIRFlags::getDefaultFlags(Instruction::Mul));
-  VPBB1->appendRecipe(I1);
-  VPBB1->appendRecipe(I2);
 
-  // Check printing I1.
   {
-    // Use EXPECT_EXIT to capture stderr and compare against expected output.
-    //
-    // Test VPValue::dump().
-    VPValue *VPV = I1;
-    EXPECT_EXIT(
-        {
-          VPV->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
+    VPlan &Plan = getPlan();
+    VPBasicBlock *VPBB0 = Plan.getEntry();
+    VPBasicBlock *VPBB1 = Plan.createVPBasicBlock("");
+    VPBlockUtils::connectBlocks(VPBB1, Plan.getScalarHeader());
+    VPBlockUtils::connectBlocks(VPBB0, VPBB1);
 
-    // Test VPRecipeBase::dump().
-    VPRecipeBase *R = I1;
-    EXPECT_EXIT(
-        {
-          R->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
+    SmallVector<VPValue *, 2> Args;
+    VPValue *ExtVPV1 = Plan.getOrAddLiveIn(ConstantInt::get(Int32, 1));
+    VPValue *ExtVPV2 = Plan.getOrAddLiveIn(AI);
+    Args.push_back(ExtVPV1);
+    Args.push_back(ExtVPV2);
+    VPInstruction *I1 =
+        new VPInstruction(Instruction::Add, {ExtVPV1, ExtVPV2},
+                          VPIRFlags::getDefaultFlags(Instruction::Add));
+    VPInstruction *I2 =
+        new VPInstruction(Instruction::Mul, {I1, I1},
+                          VPIRFlags::getDefaultFlags(Instruction::Mul));
+    VPBB1->appendRecipe(I1);
+    VPBB1->appendRecipe(I2);
+
+    // Check printing I1.
+    {
+      // Use EXPECT_EXIT to capture stderr and compare against expected output.
+      //
+      // Test VPValue::dump().
+      VPValue *VPV = I1;
+      EXPECT_EXIT(
+          {
+            VPV->dump();
+            exit(0);
+          },
+          testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
+
+      // Test VPRecipeBase::dump().
+      VPRecipeBase *R = I1;
+      EXPECT_EXIT(
+          {
+            R->dump();
+            exit(0);
+          },
+          testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
+    }
+    // Check printing I2.
+    {
+      // Use EXPECT_EXIT to capture stderr and compare against expected output.
+      //
+      // Test VPValue::dump().
+      VPValue *VPV = I2;
+      EXPECT_EXIT(
+          {
+            VPV->dump();
+            exit(0);
+          },
+          testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
+
+      // Test VPRecipeBase::dump().
+      VPRecipeBase *R = I2;
+      EXPECT_EXIT(
+          {
+            R->dump();
+            exit(0);
+          },
+          testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
+    }
   }
-  // Check printing I2.
-  {
-    // Use EXPECT_EXIT to capture stderr and compare against expected output.
-    //
-    // Test VPValue::dump().
-    VPValue *VPV = I2;
-    EXPECT_EXIT(
-        {
-          VPV->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
 
-    // Test VPRecipeBase::dump().
-    VPRecipeBase *R = I2;
-    EXPECT_EXIT(
-        {
-          R->dump();
-          exit(0);
-        },
-        testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
-  }
   delete AI;
 }
 

>From a6e3e93e8df07d64017ad366f2005c078d06f2cf Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Fri, 22 May 2026 20:22:42 +0000
Subject: [PATCH 2/2] Address feedback from Florian Google

---
 llvm/unittests/Transforms/Vectorize/VPlanTest.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
index 65817472e5f70..1aac7df331f66 100644
--- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
+++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp
@@ -1510,8 +1510,8 @@ TEST_F(VPRecipeTest, MayHaveSideEffectsAndMayReadWriteMemory) {
 
 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
 TEST_F(VPRecipeTest, dumpRecipeInPlan) {
-  // AI must outlive VPlan &Plan
   IntegerType *Int32 = IntegerType::get(C, 32);
+  // AI must outlive VPlan &Plan
   auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32),
                                        PoisonValue::get(Int32));
   AI->setName("a");
@@ -1573,8 +1573,8 @@ TEST_F(VPRecipeTest, dumpRecipeInPlan) {
 }
 
 TEST_F(VPRecipeTest, dumpRecipeUnnamedVPValuesInPlan) {
-  // AI must outlive VPlan &Plan
   IntegerType *Int32 = IntegerType::get(C, 32);
+  // AI must outlive VPlan &Plan
   auto *AI = BinaryOperator::CreateAdd(PoisonValue::get(Int32),
                                        PoisonValue::get(Int32));
   AI->setName("a");



More information about the llvm-commits mailing list