Skip to content

Commit 2763e13

Browse files
committed
[Stdlib] Fix an overrelease in -[__SwiftNativeNSError description].
getDescription takes its argument at +1, but the implementation was passing the value directly. This caused the contained error value to be destroyed. rdar://problem/59512630
1 parent abc84e7 commit 2763e13

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

stdlib/public/runtime/ErrorObject.mm

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,14 @@ - (void)dealloc {
102102

103103
- (id /* NSString */)description {
104104
auto error = (const SwiftError *)self;
105-
return getDescription(const_cast<OpaqueValue *>(error->getValue()),
106-
error->type);
105+
auto value = error->getValue();
106+
107+
// Copy the value, since it will be consumed by getDescription.
108+
ValueBuffer copyBuf;
109+
auto copy = error->type->allocateBufferIn(&copyBuf);
110+
error->type->vw_initializeWithCopy(copy, const_cast<OpaqueValue *>(value));
111+
112+
return getDescription(copy, error->type);
107113
}
108114

109115
- (NSInteger)code {

test/stdlib/ErrorBridged.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,4 +854,35 @@ ErrorBridgingTests.test("Swift Error bridged to NSError description") {
854854
}
855855
}
856856

857+
struct SwiftError2: Error, CustomStringConvertible {
858+
var description: String
859+
}
860+
861+
ErrorBridgingTests.test("Swift Error description memory management") {
862+
func checkDescription() {
863+
// Generate a non-small, non-constant NSString bridged to String.
864+
let str = (["""
865+
There once was a gigantic genie
866+
Who turned out to be a real meanie
867+
I wished for flight
868+
And with all his might
869+
He gave me a propellor beanie
870+
"""] as NSArray).description
871+
let error = SwiftError2(description: str)
872+
let bridgedError = error as NSError
873+
874+
// Ensure that the bridged NSError description method doesn't overrelease
875+
// the error value.
876+
for _ in 0 ..< 10 {
877+
autoreleasepool {
878+
expectEqual(str, bridgedError.description)
879+
}
880+
}
881+
}
882+
883+
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
884+
checkDescription()
885+
}
886+
}
887+
857888
runAllTests()

0 commit comments

Comments
 (0)