Skip to content

Commit 9998ee3

Browse files
committed
[IR] Use alloc markers for operator delete variants
1 parent 4ba2778 commit 9998ee3

File tree

2 files changed

+71
-57
lines changed

2 files changed

+71
-57
lines changed

llvm/include/llvm/IR/User.h

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ 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+
const unsigned NumOps;
60+
};
5861

5962
/// Indicates this User has operands co-allocated.
6063
struct IntrusiveOperandsAllocMarker {
@@ -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: 64 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ class BasicBlock;
2020

2121
bool User::replaceUsesOfWith(Value *From, Value *To) {
2222
bool Changed = false;
23-
if (From == To) return Changed; // Duh what?
23+
if (From == To)
24+
return Changed; // Duh what?
2425

2526
assert((!isa<Constant>(this) || isa<GlobalValue>(this)) &&
2627
"Cannot call User::replaceUsesOfWith on a constant!");
2728

2829
for (unsigned i = 0, E = getNumOperands(); i != E; ++i)
29-
if (getOperand(i) == From) { // Is This operand is pointing to oldval?
30+
if (getOperand(i) == From) { // Is This operand is pointing to oldval?
3031
// The side effects of this setOperand call include linking to
3132
// "To", adding "this" to the uses list of To, and
3233
// most importantly, removing "this" from the use list of "From".
@@ -57,7 +58,7 @@ void User::allocHungoffUses(unsigned N, bool IsPhi) {
5758
size_t size = N * sizeof(Use);
5859
if (IsPhi)
5960
size += N * sizeof(BasicBlock *);
60-
Use *Begin = static_cast<Use*>(::operator new(size));
61+
Use *Begin = static_cast<Use *>(::operator new(size));
6162
Use *End = Begin + N;
6263
setOperandList(Begin);
6364
for (; Begin != End; Begin++)
@@ -89,7 +90,6 @@ void User::growHungoffUses(unsigned NewNumUses, bool IsPhi) {
8990
Use::zap(OldOps, OldOps + OldNumUses, true);
9091
}
9192

92-
9393
// This is a private struct used by `User` to track the co-allocated descriptor
9494
// section.
9595
struct DescriptorInfo {
@@ -191,28 +191,70 @@ void *User::operator new(size_t Size, HungOffOperandsAllocMarker) {
191191
LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE void User::operator delete(void *Usr) {
192192
// Hung off uses use a single Use* before the User, while other subclasses
193193
// use a Use[] allocated prior to the user.
194-
User *Obj = static_cast<User *>(Usr);
194+
const auto *Obj = static_cast<User *>(Usr);
195195
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);
196+
const HungOffOperandsAllocMarker Marker{
197+
Obj->NumUserOperands,
198+
};
199+
operator delete(Usr, Marker);
203200
} 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);
201+
const IntrusiveOperandsAndDescriptorAllocMarker Marker{
202+
Obj->NumUserOperands,
203+
Obj->HasDescriptor,
204+
};
205+
operator delete(Usr, Marker);
210206
} else {
211-
Use *Storage = static_cast<Use *>(Usr) - Obj->NumUserOperands;
212-
Use::zap(Storage, Storage + Obj->NumUserOperands,
213-
/* Delete */ false);
214-
::operator delete(Storage);
207+
const IntrusiveOperandsAllocMarker Marker{
208+
Obj->NumUserOperands,
209+
};
210+
operator delete(Usr, Marker);
215211
}
216212
}
217213

214+
// Repress memory sanitization, due to use-after-destroy by operator
215+
// delete. Bug report 24578 identifies this issue.
216+
LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE void
217+
User::operator delete(void *Usr, const HungOffOperandsAllocMarker Marker) {
218+
// Note: If a subclass manipulates the information which is required to
219+
// calculate the Usr memory pointer, e.g. NumUserOperands, the operator
220+
// delete of that subclass has to restore the changed information to the
221+
// original value, since the dtor of that class is not called if the ctor
222+
// fails.
223+
Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
224+
// drop the hung off uses.
225+
Use::zap(*HungOffOperandList, *HungOffOperandList + Marker.NumOps,
226+
/* Delete */ true);
227+
::operator delete(HungOffOperandList);
228+
}
229+
230+
// Repress memory sanitization, due to use-after-destroy by operator
231+
// delete. Bug report 24578 identifies this issue.
232+
LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE void
233+
User::operator delete(void *Usr, const IntrusiveOperandsAllocMarker Marker) {
234+
// Note: If a subclass manipulates the information which is required to
235+
// calculate the Usr memory pointer, e.g. NumUserOperands, the operator delete
236+
// of that subclass has to restore the changed information to the original
237+
// value, since the dtor of that class is not called if the ctor fails.
238+
Use *Storage = static_cast<Use *>(Usr) - Marker.NumOps;
239+
Use::zap(Storage, Storage + Marker.NumOps, /* Delete */ false);
240+
::operator delete(Storage);
241+
}
242+
243+
// Repress memory sanitization, due to use-after-destroy by operator
244+
// delete. Bug report 24578 identifies this issue.
245+
LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE void
246+
User::operator delete(void *Usr,
247+
const IntrusiveOperandsAndDescriptorAllocMarker Marker) {
248+
// Note: If a subclass manipulates the information which is required to
249+
// calculate the Usr memory pointer, e.g. NumUserOperands, the operator delete
250+
// of that subclass has to restore the changed information to the original
251+
// value, since the dtor of that class is not called if the ctor fails.
252+
Use *UseBegin = static_cast<Use *>(Usr) - Marker.NumOps;
253+
Use::zap(UseBegin, UseBegin + Marker.NumOps, /* Delete */ false);
254+
255+
auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
256+
uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
257+
::operator delete(Storage);
258+
}
259+
218260
} // namespace llvm

0 commit comments

Comments
 (0)