Skip to content

Commit db23731

Browse files
author
Davide Italiano
committed
[IRGen] Zero-init stack shadow copies of values at -Onone.
We already zero init AllocStack, and here's the same. The debugger's variable view shows up variables on the line where they're declared (before they've been initialized). In some cases, we just print garbage. In some others, it's dangerous (imagine an array which we believe has 2^32 elements because we ended up reusing a stack slot). This way it's always consistent, as lldb uses the first word to understand whether an object is initialized or not here. Fixes <rdar://problem/39883298>
1 parent 43e5417 commit db23731

File tree

4 files changed

+38
-31
lines changed

4 files changed

+38
-31
lines changed

lib/IRGen/IRGenSIL.cpp

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,32 @@ class IRGenSILFunction :
719719
}
720720
}
721721

722+
/// To make it unambiguous whether a `var` binding has been initialized,
723+
/// zero-initialize the first pointer-sized field. LLDB uses this to
724+
/// recognize to detect uninitizialized variables. This can be removed once
725+
/// swiftc switches to @llvm.dbg.addr() intrinsics.
726+
void zeroInit(llvm::AllocaInst *AI) {
727+
if (!AI)
728+
return;
729+
730+
// Only do this at -Onone.
731+
if (IGM.IRGen.Opts.shouldOptimize())
732+
return;
733+
734+
auto &DL = IGM.DataLayout;
735+
if (DL.getTypeSizeInBits(AI->getAllocatedType()) <
736+
DL.getPointerSizeInBits())
737+
return;
738+
739+
llvm::IRBuilder<> ZeroInitBuilder(AI->getNextNode());
740+
ZeroInitBuilder.SetCurrentDebugLocation(nullptr);
741+
auto *BC =
742+
ZeroInitBuilder.CreateBitCast(AI, IGM.OpaquePtrTy->getPointerTo());
743+
ZeroInitBuilder.CreateAlignedStore(
744+
llvm::ConstantPointerNull::get(IGM.OpaquePtrTy), BC,
745+
IGM.getPointerAlignment().getValue());
746+
}
747+
722748
/// Account for bugs in LLVM.
723749
///
724750
/// - The LLVM type legalizer currently doesn't update debug
@@ -742,6 +768,7 @@ class IRGenSILFunction :
742768
auto &Alloca = ShadowStackSlots[{ArgNo, {Scope, Name}}];
743769
if (!Alloca.isValid())
744770
Alloca = createAlloca(Storage->getType(), Align, Name+".addr");
771+
zeroInit(dyn_cast<llvm::AllocaInst>(Alloca.getAddress()));
745772

746773
ArtificialLocation AutoRestore(Scope, IGM.DebugInfo, Builder);
747774
Builder.CreateStore(Storage, Alloca.getAddress(), Align);
@@ -4000,31 +4027,10 @@ void IRGenSILFunction::visitAllocStackInst(swift::AllocStackInst *i) {
40004027
if (!Decl)
40014028
return;
40024029

4003-
// To make it unambiguous whether a `var` binding has been initialized,
4004-
// zero-initialize the first pointer-sized field. LLDB uses this to
4005-
// recognize to detect uninitizialized variables. This can be removed once
4006-
// swiftc switches to @llvm.dbg.addr() intrinsics.
4007-
auto zeroInit = [&]() {
4008-
if (IGM.IRGen.Opts.shouldOptimize())
4009-
return;
4010-
Type Desugared = Decl->getType()->getDesugaredType();
4011-
if (!Desugared->getClassOrBoundGenericClass() &&
4012-
!Desugared->getStructOrBoundGenericStruct())
4013-
return;
4014-
4015-
auto *AI = dyn_cast<llvm::AllocaInst>(addr.getAddress().getAddress());
4016-
if (!AI)
4017-
return;
4018-
4019-
auto &DL = IGM.DataLayout;
4020-
if (DL.getTypeSizeInBits(AI->getAllocatedType()) < DL.getPointerSizeInBits())
4021-
return;
4022-
4023-
auto *BC = Builder.CreateBitCast(AI, IGM.OpaquePtrTy->getPointerTo());
4024-
Builder.CreateStore(llvm::ConstantPointerNull::get(IGM.OpaquePtrTy), BC,
4025-
IGM.getPointerAlignment());
4026-
};
4027-
zeroInit();
4030+
Type Desugared = Decl->getType()->getDesugaredType();
4031+
if (Desugared->getClassOrBoundGenericClass() ||
4032+
Desugared->getStructOrBoundGenericStruct())
4033+
zeroInit(dyn_cast<llvm::AllocaInst>(addr.getAddress().getAddress()));
40284034
emitDebugInfoForAllocStack(i, type, addr.getAddress().getAddress());
40294035
}
40304036

test/DebugInfo/returnlocation.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import Foundation
1212
// CHECK_NONE: define{{( protected)?}} {{.*}}void {{.*}}none
1313
public func none(_ a: inout Int64) {
1414
// CHECK_NONE: call void @llvm.dbg{{.*}}, !dbg
15-
// CHECK_NONE: store{{.*}}, !dbg
16-
// CHECK_NONE: !dbg ![[NONE_INIT:.*]]
15+
// CHECK_NONE: store i64{{.*}}, !dbg ![[NONE_INIT:.*]]
1716
a -= 2
1817
// CHECK_NONE: ret {{.*}}, !dbg ![[NONE_RET:.*]]
1918
// CHECK_NONE: ![[NONE_INIT]] = !DILocation(line: [[@LINE-2]], column:

test/DebugInfo/shadowcopy-linetable.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ func foo(_ x: inout Int64) {
88
// not.
99
// CHECK: %[[X:.*]] = alloca %Ts5Int64V*, align {{(4|8)}}
1010
// CHECK-NEXT: call void @llvm.dbg.declare
11+
// CHECK-NEXT: [[ZEROED:%[0-9]+]] = bitcast %Ts5Int64V** %[[X]] to %swift.opaque**
12+
// CHECK-NEXT: store %swift.opaque* null, %swift.opaque** [[ZEROED]], align {{(4|8)}}
1113
// CHECK: store %Ts5Int64V* %0, %Ts5Int64V** %[[X]], align {{(4|8)}}
1214
// CHECK-SAME: !dbg ![[LOC0:.*]]
1315
// CHECK-NEXT: getelementptr inbounds %Ts5Int64V, %Ts5Int64V* %0, i32 0, i32 0,

test/DebugInfo/uninitialized.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ public func f() {
88
var object: MyClass
99
// CHECK: %[[OBJ:.*]] = alloca %[[T1:.*]]*, align
1010
// CHECK: call void @llvm.dbg.declare(metadata %[[T1]]** %[[OBJ]],
11-
// CHECK: %[[BC1:.*]] = bitcast %[[T1]]** %[[OBJ]] to %swift.opaque**, !dbg
12-
// CHECK: store %swift.opaque* null, %swift.opaque** %[[BC1]], align {{.*}}, !dbg
11+
// CHECK: %[[BC1:.*]] = bitcast %[[T1]]** %[[OBJ]] to %swift.opaque**
12+
// CHECK: store %swift.opaque* null, %swift.opaque** %[[BC1]], align {{.*}}
1313
// OPT-NOT: store
1414
// OPT: ret
1515
}
@@ -20,8 +20,8 @@ public func g() {
2020
var dict: Dictionary<Int64, Int64>
2121
// CHECK: %[[DICT:.*]] = alloca %[[T2:.*]], align
2222
// CHECK: call void @llvm.dbg.declare(metadata %[[T2]]* %[[DICT]],
23-
// CHECK: %[[BC2:.*]] = bitcast %[[T2]]* %[[DICT]] to %swift.opaque**, !dbg
24-
// CHECK: store %swift.opaque* null, %swift.opaque** %[[BC2]], align {{.*}}, !dbg
23+
// CHECK: %[[BC2:.*]] = bitcast %[[T2]]* %[[DICT]] to %swift.opaque**
24+
// CHECK: store %swift.opaque* null, %swift.opaque** %[[BC2]], align {{.*}}
2525
// OPT-NOT: store
2626
// OPT: ret
2727
}

0 commit comments

Comments
 (0)