Skip to content

Commit 92c8bed

Browse files
committed
[IR] Use alloc markers for operator delete variants
1 parent 46f5852 commit 92c8bed

File tree

2 files changed

+56
-64
lines changed

2 files changed

+56
-64
lines changed

llvm/include/llvm/IR/User.h

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -54,21 +54,24 @@ class User : public Value {
5454
void *operator new(size_t Size) = delete;
5555

5656
/// Indicates this User has operands "hung off" in another allocation.
57-
struct HungOffOperandsAllocMarker {};
57+
struct HungOffOperandsAllocMarker {
58+
/// The number of operands for this User.
59+
unsigned NumOps;
60+
};
5861

5962
/// Indicates this User has operands co-allocated.
6063
struct IntrusiveOperandsAllocMarker {
6164
/// The number of operands for this User.
62-
const unsigned NumOps;
65+
unsigned NumOps;
6366
};
6467

65-
/// Indicates this User has operands and a descriptor co-allocated .
68+
/// Indicates this User has operands and a descriptor co-allocated.
6669
struct IntrusiveOperandsAndDescriptorAllocMarker {
6770
/// The number of operands for this User.
68-
const unsigned NumOps;
71+
unsigned NumOps;
6972
/// The number of bytes to allocate for the descriptor. Must be divisible by
7073
/// `sizeof(void *)`.
71-
const unsigned DescBytes;
74+
unsigned DescBytes;
7275
};
7376

7477
/// Information about how a User object was allocated, to be passed into the
@@ -145,42 +148,11 @@ class User : public Value {
145148
/// Free memory allocated for User and Use objects.
146149
void operator delete(void *Usr);
147150
/// Placement delete - required by std, called if the ctor throws.
148-
void operator delete(void *Usr, HungOffOperandsAllocMarker) {
149-
// Note: If a subclass manipulates the information which is required to
150-
// calculate the Usr memory pointer, e.g. NumUserOperands, the operator
151-
// delete of that subclass has to restore the changed information to the
152-
// original value, since the dtor of that class is not called if the ctor
153-
// fails.
154-
User::operator delete(Usr);
155-
156-
#ifndef LLVM_ENABLE_EXCEPTIONS
157-
llvm_unreachable("Constructor throws?");
158-
#endif
159-
}
151+
void operator delete(void *Usr, HungOffOperandsAllocMarker);
160152
/// Placement delete - required by std, called if the ctor throws.
161-
void operator delete(void *Usr, IntrusiveOperandsAllocMarker) {
162-
// Note: If a subclass manipulates the information which is required to calculate the
163-
// Usr memory pointer, e.g. NumUserOperands, the operator delete of that subclass has
164-
// to restore the changed information to the original value, since the dtor of that class
165-
// is not called if the ctor fails.
166-
User::operator delete(Usr);
167-
168-
#ifndef LLVM_ENABLE_EXCEPTIONS
169-
llvm_unreachable("Constructor throws?");
170-
#endif
171-
}
153+
void operator delete(void *Usr, IntrusiveOperandsAllocMarker Marker);
172154
/// Placement delete - required by std, called if the ctor throws.
173-
void operator delete(void *Usr, IntrusiveOperandsAndDescriptorAllocMarker) {
174-
// Note: If a subclass manipulates the information which is required to calculate the
175-
// Usr memory pointer, e.g. NumUserOperands, the operator delete of that subclass has
176-
// to restore the changed information to the original value, since the dtor of that class
177-
// is not called if the ctor fails.
178-
User::operator delete(Usr);
179-
180-
#ifndef LLVM_ENABLE_EXCEPTIONS
181-
llvm_unreachable("Constructor throws?");
182-
#endif
183-
}
155+
void operator delete(void *Usr, IntrusiveOperandsAndDescriptorAllocMarker);
184156

185157
protected:
186158
template <int Idx, typename U> static Use &OpFrom(const U *that) {

llvm/lib/IR/User.cpp

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ bool User::replaceUsesOfWith(Value *From, Value *To) {
2626
"Cannot call User::replaceUsesOfWith on a constant!");
2727

2828
for (unsigned i = 0, E = getNumOperands(); i != E; ++i)
29-
if (getOperand(i) == From) { // Is This operand is pointing to oldval?
29+
if (getOperand(i) == From) { // Is This operand is pointing to oldval?
3030
// The side effects of this setOperand call include linking to
3131
// "To", adding "this" to the uses list of To, and
3232
// most importantly, removing "this" from the use list of "From".
@@ -146,9 +146,6 @@ void *User::allocateFixedOperandUser(size_t Size, unsigned Us,
146146
Use *Start = reinterpret_cast<Use *>(Storage + DescBytesToAllocate);
147147
Use *End = Start + Us;
148148
User *Obj = reinterpret_cast<User *>(End);
149-
Obj->NumUserOperands = Us;
150-
Obj->HasHungOffUses = false;
151-
Obj->HasDescriptor = DescBytes != 0;
152149
for (; Start != End; Start++)
153150
new (Start) Use(Obj);
154151

@@ -175,9 +172,6 @@ void *User::operator new(size_t Size, HungOffOperandsAllocMarker) {
175172
void *Storage = ::operator new(Size + sizeof(Use *));
176173
Use **HungOffOperandList = static_cast<Use **>(Storage);
177174
User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1);
178-
Obj->NumUserOperands = 0;
179-
Obj->HasHungOffUses = true;
180-
Obj->HasDescriptor = false;
181175
*HungOffOperandList = nullptr;
182176
return Obj;
183177
}
@@ -191,28 +185,54 @@ void *User::operator new(size_t Size, HungOffOperandsAllocMarker) {
191185
LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE void User::operator delete(void *Usr) {
192186
// Hung off uses use a single Use* before the User, while other subclasses
193187
// use a Use[] allocated prior to the user.
194-
User *Obj = static_cast<User *>(Usr);
188+
const auto *Obj = static_cast<User *>(Usr);
195189
if (Obj->HasHungOffUses) {
196-
assert(!Obj->HasDescriptor && "not supported!");
197-
198-
Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
199-
// drop the hung off uses.
200-
Use::zap(*HungOffOperandList, *HungOffOperandList + Obj->NumUserOperands,
201-
/* Delete */ true);
202-
::operator delete(HungOffOperandList);
190+
const HungOffOperandsAllocMarker Marker{
191+
Obj->NumUserOperands,
192+
};
193+
operator delete(Usr, Marker);
203194
} else if (Obj->HasDescriptor) {
204-
Use *UseBegin = static_cast<Use *>(Usr) - Obj->NumUserOperands;
205-
Use::zap(UseBegin, UseBegin + Obj->NumUserOperands, /* Delete */ false);
206-
207-
auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
208-
uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
209-
::operator delete(Storage);
195+
const IntrusiveOperandsAndDescriptorAllocMarker Marker{
196+
Obj->NumUserOperands,
197+
Obj->HasDescriptor,
198+
};
199+
operator delete(Usr, Marker);
210200
} else {
211-
Use *Storage = static_cast<Use *>(Usr) - Obj->NumUserOperands;
212-
Use::zap(Storage, Storage + Obj->NumUserOperands,
213-
/* Delete */ false);
214-
::operator delete(Storage);
201+
const IntrusiveOperandsAllocMarker Marker{
202+
Obj->NumUserOperands,
203+
};
204+
operator delete(Usr, Marker);
215205
}
216206
}
217207

208+
// Repress memory sanitization, due to use-after-destroy by operator
209+
// delete. Bug report 24578 identifies this issue.
210+
void User::operator delete(void *Usr, HungOffOperandsAllocMarker Marker) {
211+
Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
212+
// drop the hung off uses.
213+
Use::zap(*HungOffOperandList, *HungOffOperandList + Marker.NumOps,
214+
/* Delete */ true);
215+
::operator delete(HungOffOperandList);
216+
}
217+
218+
// Repress memory sanitization, due to use-after-destroy by operator
219+
// delete. Bug report 24578 identifies this issue.
220+
void User::operator delete(void *Usr, IntrusiveOperandsAllocMarker Marker) {
221+
Use *Storage = static_cast<Use *>(Usr) - Marker.NumOps;
222+
Use::zap(Storage, Storage + Marker.NumOps, /* Delete */ false);
223+
::operator delete(Storage);
224+
}
225+
226+
// Repress memory sanitization, due to use-after-destroy by operator
227+
// delete. Bug report 24578 identifies this issue.
228+
void User::operator delete(void *Usr,
229+
IntrusiveOperandsAndDescriptorAllocMarker Marker) {
230+
Use *UseBegin = static_cast<Use *>(Usr) - Marker.NumOps;
231+
Use::zap(UseBegin, UseBegin + Marker.NumOps, /* Delete */ false);
232+
233+
auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
234+
uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
235+
::operator delete(Storage);
236+
}
237+
218238
} // namespace llvm

0 commit comments

Comments
 (0)