Skip to content

Commit fe775ce

Browse files
committed
Fix use-after-free on substituting function type involving conditional ~Escapable with Escapable type
1 parent 294e4cf commit fe775ce

File tree

3 files changed

+130
-4
lines changed

3 files changed

+130
-4
lines changed

include/swift/AST/TypeTransform.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -357,8 +357,9 @@ case TypeKind::Id:
357357
return transInterfaceParams[targetIndex].getInterfaceType();
358358
}
359359
});
360-
if (didRemoveLifetimeDependencies) {
361-
extInfo = extInfo.withLifetimeDependencies(substDependenceInfos);
360+
if (didRemoveLifetimeDependencies && !substDependenceInfos.empty()) {
361+
extInfo = extInfo.withLifetimeDependencies(
362+
ctx.AllocateCopy(substDependenceInfos));
362363
}
363364
}
364365

@@ -938,8 +939,9 @@ case TypeKind::Id:
938939
return params[targetIndex].getParameterType();
939940
});
940941

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

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)