From 92c8bedf07d9c7f9f18f269f5a1dbb9825c4e255 Mon Sep 17 00:00:00 2001 From: Marc Auberer 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 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(Storage + DescBytesToAllocate); Use *End = Start + Us; User *Obj = reinterpret_cast(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(Storage); User *Obj = reinterpret_cast(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(Usr); + const auto *Obj = static_cast(Usr); if (Obj->HasHungOffUses) { - assert(!Obj->HasDescriptor && "not supported!"); - - Use **HungOffOperandList = static_cast(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(Usr) - Obj->NumUserOperands; - Use::zap(UseBegin, UseBegin + Obj->NumUserOperands, /* Delete */ false); - - auto *DI = reinterpret_cast(UseBegin) - 1; - uint8_t *Storage = reinterpret_cast(DI) - DI->SizeInBytes; - ::operator delete(Storage); + const IntrusiveOperandsAndDescriptorAllocMarker Marker{ + Obj->NumUserOperands, + Obj->HasDescriptor, + }; + operator delete(Usr, Marker); } else { - Use *Storage = static_cast(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(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(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(Usr) - Marker.NumOps; + Use::zap(UseBegin, UseBegin + Marker.NumOps, /* Delete */ false); + + auto *DI = reinterpret_cast(UseBegin) - 1; + uint8_t *Storage = reinterpret_cast(DI) - DI->SizeInBytes; + ::operator delete(Storage); +} + } // namespace llvm