[llvm] [IR] Use alloc markers for operator delete variants (PR #138261)
Marc Auberer via llvm-commits
llvm-commits at lists.llvm.org
Mon May 5 13:14:53 PDT 2025
https://github.com/marcauberer updated https://github.com/llvm/llvm-project/pull/138261
>From 92c8bedf07d9c7f9f18f269f5a1dbb9825c4e255 Mon Sep 17 00:00:00 2001
From: Marc Auberer <marc.auberer at chillibits.com>
Date: Sat, 26 Apr 2025 01:10:41 +0200
Subject: [PATCH] [IR] Use alloc markers for operator delete variants
---
llvm/include/llvm/IR/User.h | 50 ++++++--------------------
llvm/lib/IR/User.cpp | 70 ++++++++++++++++++++++++-------------
2 files changed, 56 insertions(+), 64 deletions(-)
diff --git a/llvm/include/llvm/IR/User.h b/llvm/include/llvm/IR/User.h
index 39e1314bd8130..32b8490c4b031 100644
--- a/llvm/include/llvm/IR/User.h
+++ b/llvm/include/llvm/IR/User.h
@@ -54,21 +54,24 @@ class User : public Value {
void *operator new(size_t Size) = delete;
/// Indicates this User has operands "hung off" in another allocation.
- struct HungOffOperandsAllocMarker {};
+ struct HungOffOperandsAllocMarker {
+ /// The number of operands for this User.
+ unsigned NumOps;
+ };
/// Indicates this User has operands co-allocated.
struct IntrusiveOperandsAllocMarker {
/// The number of operands for this User.
- const unsigned NumOps;
+ unsigned NumOps;
};
- /// Indicates this User has operands and a descriptor co-allocated .
+ /// Indicates this User has operands and a descriptor co-allocated.
struct IntrusiveOperandsAndDescriptorAllocMarker {
/// The number of operands for this User.
- const unsigned NumOps;
+ unsigned NumOps;
/// The number of bytes to allocate for the descriptor. Must be divisible by
/// `sizeof(void *)`.
- const unsigned DescBytes;
+ unsigned DescBytes;
};
/// Information about how a User object was allocated, to be passed into the
@@ -145,42 +148,11 @@ class User : public Value {
/// Free memory allocated for User and Use objects.
void operator delete(void *Usr);
/// Placement delete - required by std, called if the ctor throws.
- void operator delete(void *Usr, HungOffOperandsAllocMarker) {
- // Note: If a subclass manipulates the information which is required to
- // calculate the Usr memory pointer, e.g. NumUserOperands, the operator
- // delete of that subclass has to restore the changed information to the
- // original value, since the dtor of that class is not called if the ctor
- // fails.
- User::operator delete(Usr);
-
-#ifndef LLVM_ENABLE_EXCEPTIONS
- llvm_unreachable("Constructor throws?");
-#endif
- }
+ void operator delete(void *Usr, HungOffOperandsAllocMarker);
/// Placement delete - required by std, called if the ctor throws.
- void operator delete(void *Usr, IntrusiveOperandsAllocMarker) {
- // Note: If a subclass manipulates the information which is required to calculate the
- // Usr memory pointer, e.g. NumUserOperands, the operator delete of that subclass has
- // to restore the changed information to the original value, since the dtor of that class
- // is not called if the ctor fails.
- User::operator delete(Usr);
-
-#ifndef LLVM_ENABLE_EXCEPTIONS
- llvm_unreachable("Constructor throws?");
-#endif
- }
+ void operator delete(void *Usr, IntrusiveOperandsAllocMarker Marker);
/// Placement delete - required by std, called if the ctor throws.
- void operator delete(void *Usr, IntrusiveOperandsAndDescriptorAllocMarker) {
- // Note: If a subclass manipulates the information which is required to calculate the
- // Usr memory pointer, e.g. NumUserOperands, the operator delete of that subclass has
- // to restore the changed information to the original value, since the dtor of that class
- // is not called if the ctor fails.
- User::operator delete(Usr);
-
-#ifndef LLVM_ENABLE_EXCEPTIONS
- llvm_unreachable("Constructor throws?");
-#endif
- }
+ void operator delete(void *Usr, IntrusiveOperandsAndDescriptorAllocMarker);
protected:
template <int Idx, typename U> static Use &OpFrom(const U *that) {
diff --git a/llvm/lib/IR/User.cpp b/llvm/lib/IR/User.cpp
index ab44cb4b8a3f7..d27cf35862cdd 100644
--- a/llvm/lib/IR/User.cpp
+++ b/llvm/lib/IR/User.cpp
@@ -26,7 +26,7 @@ bool User::replaceUsesOfWith(Value *From, Value *To) {
"Cannot call User::replaceUsesOfWith on a constant!");
for (unsigned i = 0, E = getNumOperands(); i != E; ++i)
- if (getOperand(i) == From) { // Is This operand is pointing to oldval?
+ if (getOperand(i) == From) { // Is This operand is pointing to oldval?
// The side effects of this setOperand call include linking to
// "To", adding "this" to the uses list of To, and
// most importantly, removing "this" from the use list of "From".
@@ -146,9 +146,6 @@ void *User::allocateFixedOperandUser(size_t Size, unsigned Us,
Use *Start = reinterpret_cast<Use *>(Storage + DescBytesToAllocate);
Use *End = Start + Us;
User *Obj = reinterpret_cast<User *>(End);
- Obj->NumUserOperands = Us;
- Obj->HasHungOffUses = false;
- Obj->HasDescriptor = DescBytes != 0;
for (; Start != End; Start++)
new (Start) Use(Obj);
@@ -175,9 +172,6 @@ void *User::operator new(size_t Size, HungOffOperandsAllocMarker) {
void *Storage = ::operator new(Size + sizeof(Use *));
Use **HungOffOperandList = static_cast<Use **>(Storage);
User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1);
- Obj->NumUserOperands = 0;
- Obj->HasHungOffUses = true;
- Obj->HasDescriptor = false;
*HungOffOperandList = nullptr;
return Obj;
}
@@ -191,28 +185,54 @@ void *User::operator new(size_t Size, HungOffOperandsAllocMarker) {
LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE void User::operator delete(void *Usr) {
// Hung off uses use a single Use* before the User, while other subclasses
// use a Use[] allocated prior to the user.
- User *Obj = static_cast<User *>(Usr);
+ const auto *Obj = static_cast<User *>(Usr);
if (Obj->HasHungOffUses) {
- assert(!Obj->HasDescriptor && "not supported!");
-
- Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
- // drop the hung off uses.
- Use::zap(*HungOffOperandList, *HungOffOperandList + Obj->NumUserOperands,
- /* Delete */ true);
- ::operator delete(HungOffOperandList);
+ const HungOffOperandsAllocMarker Marker{
+ Obj->NumUserOperands,
+ };
+ operator delete(Usr, Marker);
} else if (Obj->HasDescriptor) {
- Use *UseBegin = static_cast<Use *>(Usr) - Obj->NumUserOperands;
- Use::zap(UseBegin, UseBegin + Obj->NumUserOperands, /* Delete */ false);
-
- auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
- uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
- ::operator delete(Storage);
+ const IntrusiveOperandsAndDescriptorAllocMarker Marker{
+ Obj->NumUserOperands,
+ Obj->HasDescriptor,
+ };
+ operator delete(Usr, Marker);
} else {
- Use *Storage = static_cast<Use *>(Usr) - Obj->NumUserOperands;
- Use::zap(Storage, Storage + Obj->NumUserOperands,
- /* Delete */ false);
- ::operator delete(Storage);
+ const IntrusiveOperandsAllocMarker Marker{
+ Obj->NumUserOperands,
+ };
+ operator delete(Usr, Marker);
}
}
+// Repress memory sanitization, due to use-after-destroy by operator
+// delete. Bug report 24578 identifies this issue.
+void User::operator delete(void *Usr, HungOffOperandsAllocMarker Marker) {
+ Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
+ // drop the hung off uses.
+ Use::zap(*HungOffOperandList, *HungOffOperandList + Marker.NumOps,
+ /* Delete */ true);
+ ::operator delete(HungOffOperandList);
+}
+
+// Repress memory sanitization, due to use-after-destroy by operator
+// delete. Bug report 24578 identifies this issue.
+void User::operator delete(void *Usr, IntrusiveOperandsAllocMarker Marker) {
+ Use *Storage = static_cast<Use *>(Usr) - Marker.NumOps;
+ Use::zap(Storage, Storage + Marker.NumOps, /* Delete */ false);
+ ::operator delete(Storage);
+}
+
+// Repress memory sanitization, due to use-after-destroy by operator
+// delete. Bug report 24578 identifies this issue.
+void User::operator delete(void *Usr,
+ IntrusiveOperandsAndDescriptorAllocMarker Marker) {
+ Use *UseBegin = static_cast<Use *>(Usr) - Marker.NumOps;
+ Use::zap(UseBegin, UseBegin + Marker.NumOps, /* Delete */ false);
+
+ auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
+ uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
+ ::operator delete(Storage);
+}
+
} // namespace llvm
More information about the llvm-commits
mailing list