Skip to content

Commit 62caff6

Browse files
authored
Merge pull request swiftlang#37935 from slavapestov/ban-reference-to-uninitialized-box
SILGen: Don't allow referencing the 'var' box before it's fully initialized
2 parents 17358e4 + 2a52e4a commit 62caff6

File tree

3 files changed

+44
-37
lines changed

3 files changed

+44
-37
lines changed

lib/SILGen/SILGenDecl.cpp

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -290,13 +290,13 @@ class DestroyLocalVariable : public Cleanup {
290290
namespace {
291291
/// Cleanup to destroy an uninitialized local variable.
292292
class DeallocateUninitializedLocalVariable : public Cleanup {
293-
VarDecl *Var;
293+
SILValue Box;
294294
public:
295-
DeallocateUninitializedLocalVariable(VarDecl *var) : Var(var) {}
295+
DeallocateUninitializedLocalVariable(SILValue box) : Box(box) {}
296296

297297
void emit(SILGenFunction &SGF, CleanupLocation l,
298298
ForUnwind_t forUnwind) override {
299-
SGF.deallocateUninitializedLocalVariable(l, Var);
299+
SGF.B.createDeallocBox(l, Box);
300300
}
301301

302302
void dump(SILGenFunction &) const override {
@@ -315,7 +315,12 @@ namespace {
315315
class LocalVariableInitialization : public SingleBufferInitialization {
316316
/// The local variable decl being initialized.
317317
VarDecl *decl;
318-
SILGenFunction &SGF;
318+
319+
/// The alloc_box instruction.
320+
SILValue Box;
321+
322+
/// The projected address.
323+
SILValue Addr;
319324

320325
/// The cleanup we pushed to deallocate the local variable before it
321326
/// gets initialized.
@@ -332,7 +337,7 @@ class LocalVariableInitialization : public SingleBufferInitialization {
332337
LocalVariableInitialization(VarDecl *decl,
333338
Optional<MarkUninitializedInst::Kind> kind,
334339
uint16_t ArgNo, SILGenFunction &SGF)
335-
: decl(decl), SGF(SGF) {
340+
: decl(decl) {
336341
assert(decl->getDeclContext()->isLocalContext() &&
337342
"can't emit a local var for a non-local var decl");
338343
assert(decl->hasStorage() && "can't emit storage for a computed variable");
@@ -348,26 +353,24 @@ class LocalVariableInitialization : public SingleBufferInitialization {
348353
// The variable may have its lifetime extended by a closure, heap-allocate
349354
// it using a box.
350355
SILDebugVariable DbgVar(decl->isLet(), ArgNo);
351-
SILValue allocBox = SGF.B.createAllocBox(decl, boxType, DbgVar);
356+
Box = SGF.B.createAllocBox(decl, boxType, DbgVar);
352357

353358
// Mark the memory as uninitialized, so DI will track it for us.
354359
if (kind)
355-
allocBox = SGF.B.createMarkUninitialized(decl, allocBox, kind.getValue());
360+
Box = SGF.B.createMarkUninitialized(decl, Box, kind.getValue());
356361

357-
SILValue addr = SGF.B.createProjectBox(decl, allocBox, 0);
358-
359-
/// Remember that this is the memory location that we're emitting the
360-
/// decl to.
361-
SGF.VarLocs[decl] = SILGenFunction::VarLoc::get(addr, allocBox);
362+
Addr = SGF.B.createProjectBox(decl, Box, 0);
362363

363364
// Push a cleanup to destroy the local variable. This has to be
364365
// inactive until the variable is initialized.
365366
SGF.Cleanups.pushCleanupInState<DestroyLocalVariable>(CleanupState::Dormant,
366367
decl);
367368
ReleaseCleanup = SGF.Cleanups.getTopCleanup();
368369

369-
// Push a cleanup to deallocate the local variable.
370-
SGF.Cleanups.pushCleanup<DeallocateUninitializedLocalVariable>(decl);
370+
// Push a cleanup to deallocate the local variable. This references the
371+
// box directly since it might be activated before we update
372+
// SGF.VarLocs.
373+
SGF.Cleanups.pushCleanup<DeallocateUninitializedLocalVariable>(Box);
371374
DeallocCleanup = SGF.Cleanups.getTopCleanup();
372375
}
373376

@@ -376,8 +379,7 @@ class LocalVariableInitialization : public SingleBufferInitialization {
376379
}
377380

378381
SILValue getAddress() const {
379-
assert(SGF.VarLocs.count(decl) && "did not emit var?!");
380-
return SGF.VarLocs[decl].value;
382+
return Addr;
381383
}
382384

383385
SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
@@ -394,6 +396,11 @@ class LocalVariableInitialization : public SingleBufferInitialization {
394396
}
395397

396398
void finishInitialization(SILGenFunction &SGF) override {
399+
/// Remember that this is the memory location that we've emitted the
400+
/// decl to.
401+
assert(SGF.VarLocs.count(decl) == 0 && "Already emitted the local?");
402+
SGF.VarLocs[decl] = SILGenFunction::VarLoc::get(Addr, Box);
403+
397404
SingleBufferInitialization::finishInitialization(SGF);
398405
assert(!DidFinish &&
399406
"called LocalVariableInitialization::finishInitialization twice!");
@@ -1688,21 +1695,4 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
16881695
B.emitDestroyValueOperation(silLoc, Val);
16891696
else
16901697
B.createDestroyAddr(silLoc, Val);
1691-
}
1692-
1693-
void SILGenFunction::deallocateUninitializedLocalVariable(SILLocation silLoc,
1694-
VarDecl *vd) {
1695-
assert(vd->getDeclContext()->isLocalContext() &&
1696-
"can't emit a local var for a non-local var decl");
1697-
assert(vd->hasStorage() && "can't emit storage for a computed variable");
1698-
1699-
assert(VarLocs.count(vd) && "var decl wasn't emitted?!");
1700-
1701-
auto loc = VarLocs[vd];
1702-
1703-
// Ignore let values captured without a memory location.
1704-
if (!loc.value->getType().isAddress()) return;
1705-
1706-
assert(loc.box && "captured var should have been given a box");
1707-
B.createDeallocBox(silLoc, loc.box);
1708-
}
1698+
}

lib/SILGen/SILGenFunction.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,9 +2072,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
20722072

20732073
/// Destroy and deallocate an initialized local variable.
20742074
void destroyLocalVariable(SILLocation L, VarDecl *D);
2075-
2076-
/// Deallocate an uninitialized local variable.
2077-
void deallocateUninitializedLocalVariable(SILLocation L, VarDecl *D);
20782075

20792076
/// Enter a cleanup to deallocate a stack variable.
20802077
CleanupHandle enterDeallocStackCleanup(SILValue address);

test/SILGen/capture_order.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,3 +165,23 @@ class rdar40600800 {
165165
}
166166
}
167167
}
168+
169+
// Make sure we can't capture an uninitialized 'var' box, either.
170+
func SR14747() {
171+
func g() -> Int { // expected-error {{closure captures 'r' before it is declared}}
172+
_ = r // expected-note {{captured here}}
173+
return 5
174+
}
175+
var r = g() // expected-note {{captured value declared here}}
176+
// expected-warning@-1 {{variable 'r' was never mutated; consider changing to 'let' constant}}
177+
}
178+
179+
class class77933460 {}
180+
181+
func func77933460() {
182+
var obj: class77933460 = { obj }()
183+
// expected-error@-1 {{closure captures 'obj' before it is declared}}
184+
// expected-note@-2 {{captured here}}
185+
// expected-note@-3 {{captured value declared here}}
186+
// expected-warning@-4 {{variable 'obj' was never mutated; consider changing to 'let' constant}}
187+
}

0 commit comments

Comments
 (0)