Skip to content

Commit e75ee3f

Browse files
authored
Merge pull request #80507 from jckarter/builtin-emplace-double-free
SILGen: Correct ownership forwarding of `Builtin.emplace`.
2 parents b4fb529 + 66780ee commit e75ee3f

File tree

2 files changed

+102
-4
lines changed

2 files changed

+102
-4
lines changed

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2130,6 +2130,7 @@ static ManagedValue emitBuiltinEmplace(SILGenFunction &SGF,
21302130
resultASTTy);
21312131
bool didEmitInto;
21322132
Initialization *dest;
2133+
TemporaryInitialization *destTemporary = nullptr;
21332134
std::unique_ptr<Initialization> destOwner;
21342135

21352136
// Use the context destination if available.
@@ -2139,8 +2140,9 @@ static ManagedValue emitBuiltinEmplace(SILGenFunction &SGF,
21392140
dest = C.getEmitInto();
21402141
} else {
21412142
didEmitInto = false;
2142-
destOwner = SGF.emitTemporary(loc, loweredBufferTy);
2143-
dest = destOwner.get();
2143+
auto destTempOwner = SGF.emitTemporary(loc, loweredBufferTy);
2144+
dest = destTemporary = destTempOwner.get();
2145+
destOwner = std::move(destTempOwner);
21442146
}
21452147

21462148
auto buffer = dest->getAddressForInPlaceInitialization(SGF, loc);
@@ -2187,16 +2189,19 @@ static ManagedValue emitBuiltinEmplace(SILGenFunction &SGF,
21872189
return ManagedValue::forInContext();
21882190
}
21892191

2192+
assert(destTemporary
2193+
&& "didn't emit into context but also didn't emit into temporary?");
2194+
auto result = destTemporary->getManagedAddress();
21902195
auto resultTy = SGF.getLoweredType(subs.getReplacementTypes()[0]);
21912196

21922197
// If the result is naturally address-only, then we can adopt the stack slot
21932198
// as the value directly.
21942199
if (resultTy == loweredBufferTy.getLoweredType().getAddressType()) {
2195-
return SGF.emitManagedRValueWithCleanup(buffer);
2200+
return result;
21962201
}
21972202

21982203
// If the result is loadable, load it.
2199-
return SGF.B.createLoadTake(loc, ManagedValue::forLValue(buffer));
2204+
return SGF.B.createLoadTake(loc, result);
22002205
}
22012206

22022207
std::optional<SpecializedEmitter>

test/SILGen/emplace.swift

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// RUN: %target-swift-frontend -enable-experimental-feature BuiltinModule -emit-silgen %s | %FileCheck %s
2+
3+
// REQUIRES: swift_feature_BuiltinModule
4+
5+
import Builtin
6+
7+
@_silgen_name("do_emplace")
8+
func do_emplace(_: Builtin.RawPointer)
9+
10+
struct AO {
11+
var x: Any
12+
}
13+
14+
struct Loadable {
15+
var x: AnyObject
16+
}
17+
18+
// CHECK-LABEL: sil {{.*}} @$s{{.*}}_in_place_loadable
19+
func emplace_in_place_loadable() -> Loadable {
20+
// CHECK: [[TMP:%.*]] = alloc_stack $Loadable
21+
// CHECK-NEXT: builtin "zeroInitializer"([[TMP]])
22+
// CHECK-NEXT: [[PTR:%.*]] = address_to_pointer {{.*}} [[TMP]]
23+
// CHECK-NEXT: apply {{.*}}([[PTR]])
24+
// CHECK-NEXT: load [take] [[TMP]]
25+
// CHECK-NEXT: dealloc_stack [[TMP]]
26+
return Builtin.emplace(do_emplace)
27+
}
28+
29+
// CHECK-LABEL: sil {{.*}} @$s{{.*}}_in_place_ao
30+
// CHECK: bb0([[OUT:%.*]] : $*AO):
31+
func emplace_in_place_ao() -> AO {
32+
// CHECK: builtin "zeroInitializer"([[OUT]])
33+
// CHECK-NEXT: [[PTR:%.*]] = address_to_pointer {{.*}} [[OUT]]
34+
// CHECK-NEXT: apply [[FN:%.*]]([[PTR]])
35+
// CHECK-NEXT: destroy_value [[FN]]
36+
// CHECK-NEXT: tuple ()
37+
// CHECK-NEXT: return
38+
return Builtin.emplace(do_emplace)
39+
}
40+
41+
// CHECK-LABEL: sil {{.*}} @$s{{.*}}_assign_loadable
42+
// CHECK: bb0([[INOUT:%.*]] : $*Loadable):
43+
func emplace_assign_loadable(_ x: inout Loadable) {
44+
// CHECK: [[TMP:%.*]] = alloc_stack $Loadable
45+
// CHECK-NEXT: builtin "zeroInitializer"([[TMP]])
46+
// CHECK-NEXT: [[PTR:%.*]] = address_to_pointer {{.*}} [[TMP]]
47+
// CHECK-NEXT: apply {{.*}}([[PTR]])
48+
// CHECK-NEXT: [[RESULT:%.*]] = load [take] [[TMP]]
49+
// CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] [[INOUT]]
50+
// CHECK-NEXT: assign [[RESULT]] to [[WRITE]]
51+
// CHECK-NEXT: end_access [[WRITE]]
52+
// CHECK-NEXT: dealloc_stack [[TMP]]
53+
x = Builtin.emplace(do_emplace)
54+
}
55+
56+
// CHECK-LABEL: sil {{.*}} @$s{{.*}}_assign_ao
57+
// CHECK: bb0([[INOUT:%.*]] : $*AO):
58+
func emplace_assign_ao(_ x: inout AO) {
59+
// CHECK: [[TMP:%.*]] = alloc_stack $AO
60+
// CHECK-NEXT: builtin "zeroInitializer"([[TMP]])
61+
// CHECK-NEXT: [[PTR:%.*]] = address_to_pointer {{.*}} [[TMP]]
62+
// CHECK-NEXT: apply {{.*}}([[PTR]])
63+
// CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] [[INOUT]]
64+
// CHECK-NEXT: copy_addr [take] [[TMP]] to [[WRITE]]
65+
// CHECK-NEXT: end_access [[WRITE]]
66+
// CHECK-NEXT: dealloc_stack [[TMP]]
67+
x = Builtin.emplace(do_emplace)
68+
}
69+
70+
// CHECK-LABEL: sil {{.*}} @$s{{.*}}_ignore_loadable
71+
func emplace_ignore_loadable() {
72+
// CHECK: [[TMP:%.*]] = alloc_stack $Loadable
73+
// CHECK-NEXT: builtin "zeroInitializer"([[TMP]])
74+
// CHECK-NEXT: [[PTR:%.*]] = address_to_pointer {{.*}} [[TMP]]
75+
// CHECK-NEXT: apply {{.*}}([[PTR]])
76+
// CHECK-NEXT: [[RESULT:%.*]] = load [take] [[TMP]]
77+
// CHECK-NEXT: ignored_use [[RESULT]]
78+
// CHECK-NEXT: destroy_value [[RESULT]]
79+
// CHECK-NEXT: dealloc_stack [[TMP]]
80+
let _: Loadable = Builtin.emplace(do_emplace)
81+
}
82+
83+
// CHECK-LABEL: sil {{.*}} @$s{{.*}}_ignore_ao
84+
func emplace_ignore_ao() {
85+
// CHECK: [[TMP:%.*]] = alloc_stack $AO
86+
// CHECK-NEXT: builtin "zeroInitializer"([[TMP]])
87+
// CHECK-NEXT: [[PTR:%.*]] = address_to_pointer {{.*}} [[TMP]]
88+
// CHECK-NEXT: apply {{.*}}([[PTR]])
89+
// CHECK-NEXT: ignored_use [[TMP]]
90+
// CHECK-NEXT: destroy_addr [[TMP]]
91+
// CHECK-NEXT: dealloc_stack [[TMP]]
92+
let _: AO = Builtin.emplace(do_emplace)
93+
}

0 commit comments

Comments
 (0)