[Runtime] Fix memory leak in -[__SwiftNativeNSError description] for large error values.

Balance the call to allocateBufferIn with a call to deallocateBufferIn. When an error value is small, the missing deallocateBufferIn doesn't do anything. But when the error value is a larger struct that doesn't fit inline, we need deallocateBufferIn to avoid leaking the allocation.

rdar://109933822
This commit is contained in:
Mike Ash
2023-06-01 12:54:19 -04:00
parent 25ef5d7016
commit 01300a6f86
2 changed files with 19 additions and 2 deletions

View File

@@ -103,13 +103,16 @@ using namespace swift::hashable_support;
- (id /* NSString */)description {
auto error = (const SwiftError *)self;
auto value = error->getValue();
auto type = error->type;
// Copy the value, since it will be consumed by getDescription.
ValueBuffer copyBuf;
auto copy = error->type->allocateBufferIn(&copyBuf);
auto copy = type->allocateBufferIn(&copyBuf);
error->type->vw_initializeWithCopy(copy, const_cast<OpaqueValue *>(value));
return getDescription(copy, error->type);
auto description = getDescription(copy, type);
type->deallocateBufferIn(&copyBuf);
return description;
}
- (NSInteger)code {

View File

@@ -863,6 +863,11 @@ struct SwiftError2: Error, CustomStringConvertible {
var description: String
}
struct SwiftErrorLarge: Error, CustomStringConvertible {
var description: String
var makeItLarge = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
}
ErrorBridgingTests.test("Swift Error description memory management") {
func checkDescription() {
// Generate a non-small, non-constant NSString bridged to String.
@@ -883,6 +888,15 @@ ErrorBridgingTests.test("Swift Error description memory management") {
expectEqual(str, bridgedError.description)
}
}
// Make sure large structs also work.
let largeError = SwiftErrorLarge(description: str)
let largeBridgedError = largeError as NSError
for _ in 0 ..< 10 {
autoreleasepool {
expectEqual(str, largeBridgedError.description)
}
}
}
if #available(SwiftStdlib 5.3, *) {