Skip to content

Commit 41c313b

Browse files
committed
Merge pull request #1886 from Reflejo/optional-try-leak
[Swift 2.2.1] [SILGen] Fix for 'try?' leaking the error value
2 parents 6f7deae + 4349b89 commit 41c313b

File tree

6 files changed

+137
-121
lines changed

6 files changed

+137
-121
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,11 @@ RValue RValueEmitter::visitOptionalTryExpr(OptionalTryExpr *E, SGFContext C) {
988988
// If control branched to the failure block, inject .None into the
989989
// result type.
990990
SGF.B.emitBlock(catchBB);
991-
(void)catchBB->createBBArg(SILType::getExceptionType(SGF.getASTContext()));
991+
FullExpr catchCleanups(SGF.Cleanups, E);
992+
auto *errorArg = catchBB->createBBArg(
993+
SILType::getExceptionType(SGF.getASTContext()));
994+
(void) SGF.emitManagedRValueWithCleanup(errorArg);
995+
catchCleanups.pop();
992996

993997
if (isByAddress) {
994998
SGF.emitInjectOptionalNothingInto(E, optInit->getAddress(), optTL);

test/Interpreter/errors.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %target-run-simple-swift
2+
// REQUIRES: executable_test
3+
4+
//
5+
// Tests for error handling.
6+
//
7+
8+
import StdlibUnittest
9+
10+
// Also import modules which are used by StdlibUnittest internally. This
11+
// workaround is needed to link all required libraries in case we compile
12+
// StdlibUnittest with -sil-serialize-all.
13+
import SwiftPrivate
14+
#if _runtime(_ObjC)
15+
import ObjectiveC
16+
#endif
17+
18+
enum Excuse : ErrorType { case CatAteHomework(LifetimeTracked) }
19+
20+
var ErrorHandlingTests = TestSuite("ErrorHandling")
21+
22+
func furball(b: Bool) throws -> LifetimeTracked {
23+
if b {
24+
throw Excuse.CatAteHomework(LifetimeTracked(0))
25+
} else {
26+
return LifetimeTracked(1)
27+
}
28+
}
29+
30+
ErrorHandlingTests.test("tryCatch") {
31+
do {
32+
try expectEqual(furball(false), LifetimeTracked(1))
33+
} catch {
34+
expectUnreachable()
35+
}
36+
37+
do {
38+
try furball(true)
39+
expectUnreachable()
40+
} catch let e {
41+
if case Excuse.CatAteHomework(let c) = e {
42+
expectEqual(c, LifetimeTracked(0))
43+
} else {
44+
expectUnreachable()
45+
}
46+
}
47+
}
48+
49+
ErrorHandlingTests.test("tryOptional") {
50+
expectEqual(LifetimeTracked(1), try? furball(false))
51+
expectEqual(Optional<LifetimeTracked>.None, try? furball(true))
52+
}
53+
54+
runAllTests()

test/Interpreter/failable_initializers.swift

Lines changed: 33 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,23 @@ import ObjectiveC
1313

1414
var FailableInitTestSuite = TestSuite("FailableInit")
1515

16-
class Canary {
17-
static var count: Int = 0
18-
19-
init() {
20-
Canary.count += 1
21-
}
22-
23-
deinit {
24-
Canary.count -= 1
25-
}
26-
}
27-
2816
class Bear {
29-
let x: Canary
17+
let x: LifetimeTracked
3018

3119
/* Designated */
3220
init(n: Int) {
33-
x = Canary()
21+
x = LifetimeTracked(0)
3422
}
3523

3624
init?(n: Int, before: Bool) {
3725
if before {
3826
return nil
3927
}
40-
self.x = Canary()
28+
self.x = LifetimeTracked(0)
4129
}
4230

4331
init?(n: Int, after: Bool) {
44-
self.x = Canary()
32+
self.x = LifetimeTracked(0)
4533
if after {
4634
return nil
4735
}
@@ -51,7 +39,7 @@ class Bear {
5139
if before {
5240
return nil
5341
}
54-
self.x = Canary()
42+
self.x = LifetimeTracked(0)
5543
if after {
5644
return nil
5745
}
@@ -121,45 +109,45 @@ class Bear {
121109
}
122110

123111
class PolarBear : Bear {
124-
let y: Canary
112+
let y: LifetimeTracked
125113

126114
/* Designated */
127115
override init(n: Int) {
128-
self.y = Canary()
116+
self.y = LifetimeTracked(0)
129117
super.init(n: n)
130118
}
131119

132120
override init?(n: Int, before: Bool) {
133121
if before {
134122
return nil
135123
}
136-
self.y = Canary()
124+
self.y = LifetimeTracked(0)
137125
super.init(n: n)
138126
}
139127

140128
init?(n: Int, during: Bool) {
141-
self.y = Canary()
129+
self.y = LifetimeTracked(0)
142130
super.init(n: n, before: during)
143131
}
144132

145133
init?(n: Int, before: Bool, during: Bool) {
146-
self.y = Canary()
134+
self.y = LifetimeTracked(0)
147135
if before {
148136
return nil
149137
}
150138
super.init(n: n, before: during)
151139
}
152140

153141
override init?(n: Int, after: Bool) {
154-
self.y = Canary()
142+
self.y = LifetimeTracked(0)
155143
super.init(n: n)
156144
if after {
157145
return nil
158146
}
159147
}
160148

161149
init?(n: Int, during: Bool, after: Bool) {
162-
self.y = Canary()
150+
self.y = LifetimeTracked(0)
163151
super.init(n: n, before: during)
164152
if after {
165153
return nil
@@ -170,7 +158,7 @@ class PolarBear : Bear {
170158
if before {
171159
return nil
172160
}
173-
self.y = Canary()
161+
self.y = LifetimeTracked(0)
174162
super.init(n: n)
175163
if after {
176164
return nil
@@ -181,7 +169,7 @@ class PolarBear : Bear {
181169
if before {
182170
return nil
183171
}
184-
self.y = Canary()
172+
self.y = LifetimeTracked(0)
185173
super.init(n: n, before: during)
186174
if after {
187175
return nil
@@ -190,50 +178,50 @@ class PolarBear : Bear {
190178
}
191179

192180
class GuineaPig<T> : Bear {
193-
let y: Canary
181+
let y: LifetimeTracked
194182
let t: T
195183

196184
init?(t: T, during: Bool) {
197-
self.y = Canary()
185+
self.y = LifetimeTracked(0)
198186
self.t = t
199187
super.init(n: 0, before: during)
200188
}
201189
}
202190

203191
struct Chimera {
204-
let x: Canary
205-
let y: Canary
192+
let x: LifetimeTracked
193+
let y: LifetimeTracked
206194

207195
init?(before: Bool) {
208196
if before {
209197
return nil
210198
}
211-
x = Canary()
212-
y = Canary()
199+
x = LifetimeTracked(0)
200+
y = LifetimeTracked(0)
213201
}
214202

215203
init?(during: Bool) {
216-
x = Canary()
204+
x = LifetimeTracked(0)
217205
if during {
218206
return nil
219207
}
220-
y = Canary()
208+
y = LifetimeTracked(0)
221209
}
222210

223211
init?(before: Bool, during: Bool) {
224212
if before {
225213
return nil
226214
}
227-
x = Canary()
215+
x = LifetimeTracked(0)
228216
if during {
229217
return nil
230218
}
231-
y = Canary()
219+
y = LifetimeTracked(0)
232220
}
233221

234222
init?(after: Bool) {
235-
x = Canary()
236-
y = Canary()
223+
x = LifetimeTracked(0)
224+
y = LifetimeTracked(0)
237225
if after {
238226
return nil
239227
}
@@ -243,19 +231,19 @@ struct Chimera {
243231
if before {
244232
return nil
245233
}
246-
x = Canary()
247-
y = Canary()
234+
x = LifetimeTracked(0)
235+
y = LifetimeTracked(0)
248236
if after {
249237
return nil
250238
}
251239
}
252240

253241
init?(during: Bool, after: Bool) {
254-
x = Canary()
242+
x = LifetimeTracked(0)
255243
if during {
256244
return nil
257245
}
258-
y = Canary()
246+
y = LifetimeTracked(0)
259247
if after {
260248
return nil
261249
}
@@ -265,11 +253,11 @@ struct Chimera {
265253
if before {
266254
return nil
267255
}
268-
x = Canary()
256+
x = LifetimeTracked(0)
269257
if during {
270258
return nil
271259
}
272-
y = Canary()
260+
y = LifetimeTracked(0)
273261
if after {
274262
return nil
275263
}
@@ -287,8 +275,6 @@ FailableInitTestSuite.test("FailableInitFailure_Root") {
287275
mustFail { Bear(n: 0, after: true) }
288276
mustFail { Bear(n: 0, before: true, after: false) }
289277
mustFail { Bear(n: 0, before: false, after: true) }
290-
291-
expectEqual(0, Canary.count)
292278
}
293279

294280
FailableInitTestSuite.test("FailableInitFailure_Derived") {
@@ -304,14 +290,10 @@ FailableInitTestSuite.test("FailableInitFailure_Derived") {
304290
mustFail { PolarBear(n: 0, before: true, during: false, after: false) }
305291
mustFail { PolarBear(n: 0, before: false, during: true, after: false) }
306292
mustFail { PolarBear(n: 0, before: false, during: false, after: true) }
307-
308-
expectEqual(0, Canary.count)
309293
}
310294

311295
FailableInitTestSuite.test("DesignatedInitFailure_DerivedGeneric") {
312-
mustFail { GuineaPig<Canary>(t: Canary(), during: true) }
313-
314-
expectEqual(0, Canary.count)
296+
mustFail { GuineaPig<LifetimeTracked>(t: LifetimeTracked(0), during: true) }
315297
}
316298

317299
FailableInitTestSuite.test("ConvenienceInitFailure_Root") {
@@ -330,8 +312,6 @@ FailableInitTestSuite.test("ConvenienceInitFailure_Root") {
330312

331313
_ = Bear(IUO: false)
332314
_ = Bear(force: false)
333-
334-
expectEqual(0, Canary.count)
335315
}
336316

337317
FailableInitTestSuite.test("ConvenienceInitFailure_Derived") {
@@ -347,8 +327,6 @@ FailableInitTestSuite.test("ConvenienceInitFailure_Derived") {
347327
mustFail { PolarBear(before: true, during: false, after: false) }
348328
mustFail { PolarBear(before: false, during: true, after: false) }
349329
mustFail { PolarBear(before: false, during: false, after: true) }
350-
351-
expectEqual(0, Canary.count)
352330
}
353331

354332
FailableInitTestSuite.test("InitFailure_Struct") {
@@ -364,8 +342,6 @@ FailableInitTestSuite.test("InitFailure_Struct") {
364342
mustFail { Chimera(before: true, during: false, after: false) }
365343
mustFail { Chimera(before: false, during: true, after: false) }
366344
mustFail { Chimera(before: false, during: false, after: true) }
367-
368-
expectEqual(0, Canary.count)
369345
}
370346

371347
runAllTests()

0 commit comments

Comments
 (0)