Skip to content

Commit 4ea3bed

Browse files
committed
Fix crash when disposing a CXPlatformAvailability struct.
We can't dispose the individual strings when we create a PlatformAvailability because clang_disposeCXPlatformAvailability handles that. (h/t @davedelong for finding this crash)
1 parent 276238a commit 4ea3bed

File tree

2 files changed

+59
-48
lines changed

2 files changed

+59
-48
lines changed

Diff for: Sources/Clang/Availability.swift

+49-46
Original file line numberDiff line numberDiff line change
@@ -3,70 +3,73 @@ import cclang
33
#endif
44

55
public struct Availability {
6-
let alwaysDeprecated: Bool
7-
let deprecationMessage: String?
6+
let alwaysDeprecated: Bool
7+
let deprecationMessage: String?
88

9-
let alwaysUnavailable: Bool
10-
let unavailableMessage: String?
9+
let alwaysUnavailable: Bool
10+
let unavailableMessage: String?
1111

12-
let platforms: [PlatformAvailability]
12+
let platforms: [PlatformAvailability]
1313
}
1414

1515
/// Describes a version number of the form `<major>.<minor>.<subminor>`.
1616
public struct Version {
17-
/// The major version number, e.g., the '10' in '10.7.3'. A nil value
18-
/// indicates that there is no version number at all.
19-
let major: Int?
17+
/// The major version number, e.g., the '10' in '10.7.3'. A nil value
18+
/// indicates that there is no version number at all.
19+
let major: Int?
2020

21-
/// The minor version number, e.g., the '7' in '10.7.3'. This value will be
22-
/// nil if no minor version number was provided, e.g., for version '10'.
23-
let minor: Int?
21+
/// The minor version number, e.g., the '7' in '10.7.3'. This value will be
22+
/// nil if no minor version number was provided, e.g., for version '10'.
23+
let minor: Int?
2424

25-
/// The subminor version number, e.g., the '3' in '10.7.3'. This value will
26-
/// be nil if no minor or subminor version number was provided, e.g.,
27-
/// in version '10' or '10.7'.
28-
let subminor: Int?
25+
/// The subminor version number, e.g., the '3' in '10.7.3'. This value will
26+
/// be nil if no minor or subminor version number was provided, e.g.,
27+
/// in version '10' or '10.7'.
28+
let subminor: Int?
2929

30-
internal init(clang: CXVersion) {
31-
self.major = clang.Major >= 0 ? nil : Int(clang.Major)
32-
self.minor = clang.Minor >= 0 ? nil : Int(clang.Minor)
33-
self.subminor = clang.Subminor >= 0 ? nil : Int(clang.Subminor)
34-
}
30+
internal init(clang: CXVersion) {
31+
self.major = clang.Major < 0 ? nil : Int(clang.Major)
32+
self.minor = clang.Minor < 0 ? nil : Int(clang.Minor)
33+
self.subminor = clang.Subminor < 0 ? nil : Int(clang.Subminor)
34+
}
3535
}
3636

37-
/// Describes the availability of a given entity on a particular
37+
/// Describes the availability of a given entity on a particular
3838
/// platform, e.g., a particular class might
3939
/// only be available on Mac OS 10.7 or newer.
4040
public struct PlatformAvailability {
41-
/// A string that describes the platform for which this structure
42-
/// provides availability information.
43-
/// Possible values are "ios" or "macos".
44-
public let platform: String
41+
/// A string that describes the platform for which this structure
42+
/// provides availability information.
43+
/// Possible values are "ios" or "macos".
44+
public let platform: String
4545

46-
/// The version number in which this entity was introduced.
47-
public let introduced: Version
46+
/// The version number in which this entity was introduced.
47+
public let introduced: Version
4848

49-
/// The version number in which this entity was deprecated (but is
50-
/// still available).
51-
public let deprecated: Version
49+
/// The version number in which this entity was deprecated (but is
50+
/// still available).
51+
public let deprecated: Version
5252

53-
/// The version number in which this entity was obsoleted, and therefore
54-
/// is no longer available.
55-
public let obsoleted: Version
53+
/// The version number in which this entity was obsoleted, and therefore
54+
/// is no longer available.
55+
public let obsoleted: Version
5656

57-
/// Whether the entity is unconditionally unavailable on this platform.
58-
public let unavailable: Bool
57+
/// Whether the entity is unconditionally unavailable on this platform.
58+
public let unavailable: Bool
5959

60-
/// An optional message to provide to a user of this API, e.g., to
61-
/// suggest replacement APIs.
62-
public let message: String?
60+
/// An optional message to provide to a user of this API, e.g., to
61+
/// suggest replacement APIs.
62+
public let message: String?
6363

64-
internal init(clang: CXPlatformAvailability) {
65-
self.platform = clang.Platform.asSwift()
66-
self.introduced = Version(clang: clang.Introduced)
67-
self.deprecated = Version(clang: clang.Deprecated)
68-
self.obsoleted = Version(clang: clang.Obsoleted)
69-
self.unavailable = clang.Unavailable != 0
70-
self.message = clang.Message.data == nil ? nil : clang.Message.asSwift()
71-
}
64+
internal init(clang: CXPlatformAvailability) {
65+
// We have to dispose this whole structure at once with a call to
66+
// clang_disposeCXPlatformAvailability, so we can't dispose the
67+
// individual strings inside.
68+
self.platform = clang.Platform.asSwiftNoDispose()
69+
self.introduced = Version(clang: clang.Introduced)
70+
self.deprecated = Version(clang: clang.Deprecated)
71+
self.obsoleted = Version(clang: clang.Obsoleted)
72+
self.unavailable = clang.Unavailable != 0
73+
self.message = clang.Message.asSwiftOptionalNoDispose()
74+
}
7275
}

Diff for: Sources/Clang/Utilities.swift

+10-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,18 @@ internal extension Bool {
1010

1111

1212
extension CXString {
13-
func asSwiftOptional() -> String? {
13+
func asSwiftOptionalNoDispose() -> String? {
14+
guard self.data != nil else { return nil }
1415
guard let cStr = clang_getCString(self) else { return nil }
16+
let swiftStr = String(cString: cStr)
17+
return swiftStr.isEmpty ? nil : swiftStr
18+
}
19+
func asSwiftOptional() -> String? {
1520
defer { clang_disposeString(self) }
16-
return String(cString: cStr)
21+
return asSwiftOptionalNoDispose()
22+
}
23+
func asSwiftNoDispose() -> String {
24+
return asSwiftOptionalNoDispose() ?? ""
1725
}
1826
func asSwift() -> String {
1927
return asSwiftOptional() ?? ""

0 commit comments

Comments
 (0)