Skip to content

Commit 6ed58c6

Browse files
committed
Add debug_value [poison] flag.
If the '[poison]' flag is set, then all references within this debug value will be overwritten with a sentinel at this point in the program. This is used in debug builds when shortening non-trivial value lifetimes to ensure the debugger cannot inspect invalid memory. `debug_value` instructions with the poison flag are not generated until OSSA islowered. They are not expected to be serialized within the module, and the pipeline is not expected to do any significant code motion after lowering.
1 parent 0aba7b6 commit 6ed58c6

File tree

12 files changed

+74
-20
lines changed

12 files changed

+74
-20
lines changed

docs/SIL.rst

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3466,7 +3466,7 @@ debug_value
34663466

34673467
::
34683468

3469-
sil-instruction ::= debug_value sil-operand (',' debug-var-attr)*
3469+
sil-instruction ::= debug_value '[poison]'? sil-operand (',' debug-var-attr)*
34703470

34713471
debug_value %1 : $Int
34723472

@@ -3488,6 +3488,15 @@ variable that is being described, including the name of the
34883488
variable. For function and closure arguments ``argno`` is the number
34893489
of the function argument starting with 1.
34903490

3491+
If the '[poison]' flag is set, then all references within this debug
3492+
value will be overwritten with a sentinel at this point in the
3493+
program. This is used in debug builds when shortening non-trivial
3494+
value lifetimes to ensure the debugger cannot inspect invalid
3495+
memory. `debug_value` instructions with the poison flag are not
3496+
generated until OSSA islowered. They are not expected to be serialized
3497+
within the module, and the pipeline is not expected to do any
3498+
significant code motion after lowering.
3499+
34913500
debug_value_addr
34923501
````````````````
34933502

include/swift/SIL/SILBuilder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,8 @@ class SILBuilder {
956956
}
957957

958958
DebugValueInst *createDebugValue(SILLocation Loc, SILValue src,
959-
SILDebugVariable Var);
959+
SILDebugVariable Var,
960+
bool poisonRefs = false);
960961
DebugValueAddrInst *createDebugValueAddr(SILLocation Loc, SILValue src,
961962
SILDebugVariable Var);
962963

include/swift/SIL/SILCloner.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1280,7 +1280,8 @@ SILCloner<ImplClass>::visitDebugValueInst(DebugValueInst *Inst) {
12801280
recordClonedInstruction(
12811281
Inst, getBuilder().createDebugValue(Inst->getLoc(),
12821282
getOpValue(Inst->getOperand()),
1283-
*Inst->getVarInfo()));
1283+
*Inst->getVarInfo(),
1284+
Inst->poisonRefs()));
12841285
}
12851286
template<typename ImplClass>
12861287
void

include/swift/SIL/SILInstruction.h

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4524,9 +4524,10 @@ class DebugValueInst final
45244524
TailAllocatedDebugVariable VarInfo;
45254525

45264526
DebugValueInst(SILDebugLocation DebugLoc, SILValue Operand,
4527-
SILDebugVariable Var);
4527+
SILDebugVariable Var, bool poisonRefs);
45284528
static DebugValueInst *create(SILDebugLocation DebugLoc, SILValue Operand,
4529-
SILModule &M, SILDebugVariable Var);
4529+
SILModule &M, SILDebugVariable Var,
4530+
bool poisonRefs);
45304531

45314532
size_t numTrailingObjects(OverloadToken<char>) const { return 1; }
45324533

@@ -4538,6 +4539,21 @@ class DebugValueInst final
45384539
Optional<SILDebugVariable> getVarInfo() const {
45394540
return VarInfo.get(getDecl(), getTrailingObjects<char>());
45404541
}
4542+
4543+
/// True if all references within this debug value will be overwritten with a
4544+
/// poison sentinel at this point in the program. This is used in debug builds
4545+
/// when shortening non-trivial value lifetimes to ensure the debugger cannot
4546+
/// inspect invalid memory. These are not generated until OSSA is
4547+
/// lowered. They are not expected to be serialized within the module, and the
4548+
/// debug pipeline is not expected to do any significant code motion after
4549+
/// OSSA lowering. It should not be necessary to model the poison operation as
4550+
/// a side effect, which would violate the rule that debug_values cannot
4551+
/// affect optimization.
4552+
bool poisonRefs() const { return SILNode::Bits.DebugValueInst.PoisonRefs; }
4553+
4554+
void setPoisonRefs(bool poisonRefs = true) {
4555+
SILNode::Bits.DebugValueInst.PoisonRefs = poisonRefs;
4556+
}
45414557
};
45424558

45434559
/// Define the start or update to a symbolic variable value (for address-only
@@ -7142,6 +7158,14 @@ class DestroyValueInst
71427158
}
71437159

71447160
public:
7161+
/// If true, then all references within the destroyed value will be
7162+
/// overwritten with a sentinel. This is used in debug builds when shortening
7163+
/// non-trivial value lifetimes to ensure the debugger cannot inspect invalid
7164+
/// memory. These semantics are part of the destroy_value instruction to
7165+
/// avoid representing use-after-destroy in OSSA form and so that OSSA
7166+
/// transformations keep the poison operation associated with the destroy
7167+
/// point. After OSSA, these are lowered to 'debug_values [poison]'
7168+
/// instructions, after which the Onone pipeline should avoid code motion.
71457169
bool poisonRefs() const { return SILNode::Bits.DestroyValueInst.PoisonRefs; }
71467170

71477171
void setPoisonRefs(bool poisonRefs = true) {

include/swift/SIL/SILNode.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,9 @@ class alignas(8) SILNode {
341341
SWIFT_INLINE_BITFIELD(DestroyValueInst, NonValueInstruction, 1,
342342
PoisonRefs : 1);
343343

344+
SWIFT_INLINE_BITFIELD(DebugValueInst, NonValueInstruction, 1,
345+
PoisonRefs : 1);
346+
344347
SWIFT_INLINE_BITFIELD(EndCOWMutationInst, NonValueInstruction, 1,
345348
KeepUnique : 1
346349
);

lib/SIL/IR/SILBuilder.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,12 +618,14 @@ void SILBuilder::emitDestructureValueOperation(
618618
}
619619

620620
DebugValueInst *SILBuilder::createDebugValue(SILLocation Loc, SILValue src,
621-
SILDebugVariable Var) {
621+
SILDebugVariable Var,
622+
bool poisonRefs) {
622623
assert(isLoadableOrOpaque(src->getType()));
623624
// Debug location overrides cannot apply to debug value instructions.
624625
DebugLocOverrideRAII LocOverride{*this, None};
625626
return insert(
626-
DebugValueInst::create(getSILDebugLocation(Loc), src, getModule(), Var));
627+
DebugValueInst::create(getSILDebugLocation(Loc), src, getModule(), Var,
628+
poisonRefs));
627629
}
628630

629631
DebugValueAddrInst *SILBuilder::createDebugValueAddr(SILLocation Loc,

lib/SIL/IR/SILInstruction.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,11 @@ namespace {
389389
return left->poisonRefs() == RHS->poisonRefs();
390390
}
391391

392+
bool visitDebugValue(const DebugValueInst *RHS) {
393+
auto *left = cast<DebugValueInst>(LHS);
394+
return left->poisonRefs() == RHS->poisonRefs();
395+
}
396+
392397
bool visitBeginCOWMutationInst(const BeginCOWMutationInst *RHS) {
393398
auto *left = cast<BeginCOWMutationInst>(LHS);
394399
return left->isNative() == RHS->isNative();

lib/SIL/IR/SILInstructions.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,15 +291,17 @@ SILType AllocBoxInst::getAddressType() const {
291291
}
292292

293293
DebugValueInst::DebugValueInst(SILDebugLocation DebugLoc, SILValue Operand,
294-
SILDebugVariable Var)
294+
SILDebugVariable Var, bool poisonRefs)
295295
: UnaryInstructionBase(DebugLoc, Operand),
296-
VarInfo(Var, getTrailingObjects<char>()) {}
296+
VarInfo(Var, getTrailingObjects<char>()) {
297+
setPoisonRefs(poisonRefs);
298+
}
297299

298300
DebugValueInst *DebugValueInst::create(SILDebugLocation DebugLoc,
299301
SILValue Operand, SILModule &M,
300-
SILDebugVariable Var) {
302+
SILDebugVariable Var, bool poisonRefs) {
301303
void *buf = allocateDebugVarCarryingInst<DebugValueInst>(M, Var);
302-
return ::new (buf) DebugValueInst(DebugLoc, Operand, Var);
304+
return ::new (buf) DebugValueInst(DebugLoc, Operand, Var, poisonRefs);
303305
}
304306

305307
DebugValueAddrInst::DebugValueAddrInst(SILDebugLocation DebugLoc,

lib/SIL/IR/SILPrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,8 @@ class SILPrinter : public SILInstructionVisitor<SILPrinter> {
15021502
}
15031503

15041504
void visitDebugValueInst(DebugValueInst *DVI) {
1505+
if (DVI->poisonRefs())
1506+
*this << "[poison] ";
15051507
*this << getIDAndType(DVI->getOperand());
15061508
printDebugVar(DVI->getVarInfo());
15071509
}

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3097,14 +3097,18 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
30973097

30983098
case SILInstructionKind::DebugValueInst:
30993099
case SILInstructionKind::DebugValueAddrInst: {
3100+
bool poisonRefs = false;
31003101
SILDebugVariable VarInfo;
3101-
if (parseTypedValueRef(Val, B) || parseSILDebugVar(VarInfo) ||
3102+
if (parseSILOptional(poisonRefs, *this, "poison")
3103+
|| parseTypedValueRef(Val, B) || parseSILDebugVar(VarInfo) ||
31023104
parseSILDebugLocation(InstLoc, B))
31033105
return true;
31043106
if (Opcode == SILInstructionKind::DebugValueInst)
3105-
ResultVal = B.createDebugValue(InstLoc, Val, VarInfo);
3106-
else
3107+
ResultVal = B.createDebugValue(InstLoc, Val, VarInfo, poisonRefs);
3108+
else {
3109+
assert(!poisonRefs && "debug_value_addr does not support poison");
31073110
ResultVal = B.createDebugValueAddr(InstLoc, Val, VarInfo);
3111+
}
31083112
break;
31093113
}
31103114

0 commit comments

Comments
 (0)