Skip to content

Commit 6b502f9

Browse files
committed
Fix use-after-free on substituting function type involving conditional ~Escapable with Escapable type
1 parent 5583f93 commit 6b502f9

File tree

7 files changed

+164
-25
lines changed

7 files changed

+164
-25
lines changed

include/swift/AST/ExtInfo.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,10 @@ class ASTExtInfoBuilder {
746746
lifetimeDependencies);
747747
}
748748

749+
[[nodiscard]] ASTExtInfoBuilder withLifetimeDependencies(
750+
SmallVectorImpl<LifetimeDependenceInfo> lifetimeDependencies) const =
751+
delete;
752+
749753
[[nodiscard]]
750754
ASTExtInfoBuilder withIsolation(FunctionTypeIsolation isolation) const {
751755
return ASTExtInfoBuilder(
@@ -925,6 +929,10 @@ class ASTExtInfo {
925929
return builder.withLifetimeDependencies(lifetimeDependencies).build();
926930
}
927931

932+
[[nodiscard]] ASTExtInfo withLifetimeDependencies(
933+
SmallVectorImpl<LifetimeDependenceInfo> lifetimeDependencies) const =
934+
delete;
935+
928936
void Profile(llvm::FoldingSetNodeID &ID) const { builder.Profile(ID); }
929937

930938
bool isEqualTo(ASTExtInfo other, bool useClangTypes) const {
@@ -1232,6 +1240,10 @@ class SILExtInfoBuilder {
12321240
return SILExtInfoBuilder(bits, clangTypeInfo, lifetimeDependenceInfo);
12331241
}
12341242

1243+
[[nodiscard]] ASTExtInfoBuilder withLifetimeDependencies(
1244+
SmallVectorImpl<LifetimeDependenceInfo> lifetimeDependencies) const =
1245+
delete;
1246+
12351247
void Profile(llvm::FoldingSetNodeID &ID) const {
12361248
ID.AddInteger(bits);
12371249
ID.AddPointer(clangTypeInfo.getType());
@@ -1373,6 +1385,9 @@ class SILExtInfo {
13731385
return builder.withLifetimeDependencies(lifetimeDependencies);
13741386
}
13751387

1388+
SILExtInfo withLifetimeDependencies(SmallVectorImpl<LifetimeDependenceInfo>
1389+
lifetimeDependencies) const = delete;
1390+
13761391
void Profile(llvm::FoldingSetNodeID &ID) const { builder.Profile(ID); }
13771392

13781393
bool isEqualTo(SILExtInfo other, bool useClangTypes) const {

include/swift/AST/TypeTransform.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,8 @@ case TypeKind::Id:
358358
}
359359
});
360360
if (didRemoveLifetimeDependencies) {
361-
extInfo = extInfo.withLifetimeDependencies(substDependenceInfos);
361+
extInfo = extInfo.withLifetimeDependencies(
362+
ctx.AllocateCopy(substDependenceInfos));
362363
}
363364
}
364365

@@ -939,7 +940,8 @@ case TypeKind::Id:
939940
});
940941

941942
if (didRemoveLifetimeDependencies) {
942-
extInfo = extInfo->withLifetimeDependencies(substDependenceInfos);
943+
extInfo = extInfo->withLifetimeDependencies(
944+
ctx.AllocateCopy(substDependenceInfos));
943945
}
944946
}
945947

include/swift/AST/Types.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5210,12 +5210,12 @@ class SILFunctionType final
52105210
/// Given an existing ExtInfo, and a set of interface parameters and results
52115211
/// destined for a new SILFunctionType, return a new ExtInfo with only the
52125212
/// lifetime dependencies relevant after substitution.
5213-
static ExtInfo
5214-
getSubstLifetimeDependencies(GenericSignature genericSig,
5215-
ExtInfo origExtInfo,
5216-
ArrayRef<SILParameterInfo> params,
5217-
ArrayRef<SILYieldInfo> yields,
5218-
ArrayRef<SILResultInfo> results);
5213+
static ExtInfo getSubstLifetimeDependencies(GenericSignature genericSig,
5214+
ExtInfo origExtInfo,
5215+
ASTContext &context,
5216+
ArrayRef<SILParameterInfo> params,
5217+
ArrayRef<SILYieldInfo> yields,
5218+
ArrayRef<SILResultInfo> results);
52195219

52205220
/// Return a structurally-identical function type with a slightly tweaked
52215221
/// ExtInfo.

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,10 @@ SILType SILFunctionType::substInterfaceType(SILModule &M,
5959
return interfaceType;
6060
}
6161

62-
SILFunctionType::ExtInfo
63-
SILFunctionType::getSubstLifetimeDependencies(GenericSignature genericSig,
64-
ExtInfo origExtInfo,
65-
ArrayRef<SILParameterInfo> params,
66-
ArrayRef<SILYieldInfo> yields,
67-
ArrayRef<SILResultInfo> results) {
62+
SILFunctionType::ExtInfo SILFunctionType::getSubstLifetimeDependencies(
63+
GenericSignature genericSig, ExtInfo origExtInfo, ASTContext &context,
64+
ArrayRef<SILParameterInfo> params, ArrayRef<SILYieldInfo> yields,
65+
ArrayRef<SILResultInfo> results) {
6866
if (origExtInfo.getLifetimeDependencies().empty()) {
6967
return origExtInfo;
7068
}
@@ -87,7 +85,8 @@ SILFunctionType::getSubstLifetimeDependencies(GenericSignature genericSig,
8785
}
8886
});
8987
if (didRemoveLifetimeDependencies) {
90-
return origExtInfo.withLifetimeDependencies(substLifetimeDependencies);
88+
return origExtInfo.withLifetimeDependencies(
89+
context.AllocateCopy(substLifetimeDependencies));
9190
}
9291
return origExtInfo;
9392
}
@@ -131,10 +130,10 @@ CanSILFunctionType SILFunctionType::getUnsubstitutedType(SILModule &M) const {
131130

132131
auto signature = isPolymorphic() ? getInvocationGenericSignature()
133132
: CanGenericSignature();
134-
135-
auto extInfo = getSubstLifetimeDependencies(signature, getExtInfo(),
136-
params, yields, results);
137-
133+
134+
auto extInfo = getSubstLifetimeDependencies(
135+
signature, getExtInfo(), getASTContext(), params, yields, results);
136+
138137
return SILFunctionType::get(signature,
139138
extInfo,
140139
getCoroutineKind(),
@@ -2855,7 +2854,7 @@ static CanSILFunctionType getSILFunctionType(
28552854
.withSendable(isSendable)
28562855
.withAsync(isAsync)
28572856
.withUnimplementable(unimplementable)
2858-
.withLifetimeDependencies(loweredLifetimes)
2857+
.withLifetimeDependencies(TC.Context.AllocateCopy(loweredLifetimes))
28592858
.build();
28602859

28612860
return SILFunctionType::get(genericSig, silExtInfo, coroutineKind,

lib/SIL/IR/SILTypeSubstitution.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,10 @@ class SILTypeSubstituter :
240240
auto genericSig = IFS.shouldSubstituteOpaqueArchetypes()
241241
? origType->getInvocationGenericSignature()
242242
: nullptr;
243-
244-
extInfo = SILFunctionType::getSubstLifetimeDependencies(genericSig, extInfo,
245-
substParams,
246-
substYields,
247-
substResults);
243+
244+
extInfo = SILFunctionType::getSubstLifetimeDependencies(
245+
genericSig, extInfo, TC.Context, substParams, substYields,
246+
substResults);
248247

249248
return SILFunctionType::get(genericSig, extInfo,
250249
origType->getCoroutineKind(),
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
@_addressableForDependencies
2+
public struct Something {
3+
public struct View<T: BitwiseCopyable> : ~Copyable, ~Escapable {
4+
var ptr: UnsafeBufferPointer<T>
5+
6+
@lifetime(borrow ptr)
7+
public init(ptr: borrowing UnsafeBufferPointer<T>) {
8+
self.ptr = copy ptr
9+
}
10+
11+
public var span: Span<T> {
12+
@lifetime(borrow self)
13+
borrowing get {
14+
Span(_unsafeElements: ptr)
15+
}
16+
}
17+
}
18+
19+
public struct MutableView<T: BitwiseCopyable> : ~Copyable, ~Escapable {
20+
var ptr: UnsafeMutableBufferPointer<T>
21+
22+
@lifetime(borrow ptr)
23+
public init(ptr: borrowing UnsafeMutableBufferPointer<T>) {
24+
self.ptr = copy ptr
25+
}
26+
27+
public var mutableSpan: MutableSpan<T> {
28+
@lifetime(&self)
29+
mutating get {
30+
MutableSpan(_unsafeElements: ptr)
31+
}
32+
}
33+
}
34+
35+
var ptr: UnsafeMutableRawBufferPointer
36+
public init(ptr: UnsafeMutableRawBufferPointer) {
37+
self.ptr = ptr
38+
}
39+
40+
@lifetime(borrow self)
41+
public func view<T>(of type: T.Type = T.self) -> View<T> {
42+
let tp = ptr.assumingMemoryBound(to: T.self)
43+
return __overrideLifetime(View(ptr: .init(tp)), borrowing: self)
44+
}
45+
46+
@lifetime(&self)
47+
public mutating func mutableView<T>(of type: T.Type = T.self) -> MutableView<T> {
48+
let tp = ptr.assumingMemoryBound(to: T.self)
49+
return __overrideLifetime(MutableView(ptr: tp), mutating: &self)
50+
}
51+
}
52+
53+
@unsafe
54+
@_unsafeNonescapableResult
55+
@_alwaysEmitIntoClient
56+
@_transparent
57+
@lifetime(borrow source)
58+
public func __overrideLifetime<
59+
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
60+
>(
61+
_ dependent: consuming T, borrowing source: borrowing U
62+
) -> T {
63+
dependent
64+
}
65+
66+
/// Unsafely discard any lifetime dependency on the `dependent` argument. Return
67+
/// a value identical to `dependent` that inherits all lifetime dependencies from
68+
/// the `source` argument.
69+
@unsafe
70+
@_unsafeNonescapableResult
71+
@_alwaysEmitIntoClient
72+
@_transparent
73+
@lifetime(copy source)
74+
public func __overrideLifetime<
75+
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
76+
>(
77+
_ dependent: consuming T, copying source: borrowing U
78+
) -> T {
79+
dependent
80+
}
81+
82+
/// Unsafely discard any lifetime dependency on the `dependent` argument.
83+
/// Return a value identical to `dependent` with a lifetime dependency
84+
/// on the caller's exclusive borrow scope of the `source` argument.
85+
@unsafe
86+
@_unsafeNonescapableResult
87+
@_alwaysEmitIntoClient
88+
@_transparent
89+
@lifetime(&source)
90+
public func __overrideLifetime<
91+
T: ~Copyable & ~Escapable, U: ~Copyable & ~Escapable
92+
>(
93+
_ dependent: consuming T,
94+
mutating source: inout U
95+
) -> T {
96+
dependent
97+
}
98+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module -o %t %S/Inputs/ne_types.swift \
3+
// RUN: -enable-experimental-feature LifetimeDependence \
4+
// RUN: -enable-experimental-feature AddressableTypes \
5+
// RUN: -enable-library-evolution \
6+
// RUN: -emit-module-path %t/ne_types.swiftmodule
7+
8+
// RUN: %target-swift-frontend -emit-silgen -I %t %s \
9+
// RUN: -enable-experimental-feature LifetimeDependence
10+
11+
// REQUIRES: swift_feature_LifetimeDependence
12+
// REQUIRES: swift_feature_AddressableTypes
13+
14+
import ne_types
15+
16+
// Ensure no memory crashes during SILGen
17+
18+
struct NonEscapableFrameworkThingTests {
19+
func example() async throws {
20+
let ptr = UnsafeMutableRawBufferPointer.allocate(byteCount: 40, alignment: 1)
21+
defer { ptr.deallocate() }
22+
var something = Something(ptr: ptr)
23+
var mutableView = something.mutableView(of: Float32.self)
24+
var mutableSpan = mutableView.mutableSpan
25+
}
26+
}

0 commit comments

Comments
 (0)