Skip to content

Commit f257b3b

Browse files
committed
[Runtime] Fix _swift_refCountBytesForMetatype for reference types
_swift_addRefCountStringForMetatype and _swift_refCountBytesForMetatype diverged in the code that determines whether a type is a reference, causing the size number of ref count bytes to differ from the actually used bytes. This can cause early termination of the runtime interpreter functions, which in turn causes unbalanced reference counts. rdar://112474091
1 parent c415744 commit f257b3b

File tree

5 files changed

+78
-2
lines changed

5 files changed

+78
-2
lines changed

stdlib/public/runtime/Metadata.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2785,15 +2785,26 @@ size_t swift::_swift_refCountBytesForMetatype(const Metadata *type) {
27852785
size_t offset = sizeof(uint64_t);
27862786
return LayoutStringReader{type->getLayoutString(), offset}
27872787
.readBytes<size_t>();
2788-
} else if (type->isClassObject() || type->isAnyExistentialType()) {
2789-
return sizeof(uint64_t);
27902788
} else if (auto *tuple = dyn_cast<TupleTypeMetadata>(type)) {
27912789
size_t res = 0;
27922790
for (InProcess::StoredSize i = 0; i < tuple->NumElements; i++) {
27932791
res += _swift_refCountBytesForMetatype(tuple->getElement(i).Type);
27942792
}
27952793
return res;
2794+
} else if (auto *cls = type->getClassObject()) {
2795+
if (cls->isTypeMetadata()) {
2796+
auto *vwt = cls->getValueWitnesses();
2797+
if (vwt != &VALUE_WITNESS_SYM(Bo) &&
2798+
vwt != &VALUE_WITNESS_SYM(BO) &&
2799+
vwt != &VALUE_WITNESS_SYM(Bb)) {
2800+
goto metadata;
2801+
}
2802+
}
2803+
return sizeof(uint64_t);
2804+
} else if (type->isAnyExistentialType()) {
2805+
return sizeof(uint64_t);
27962806
} else {
2807+
metadata:
27972808
return sizeof(uint64_t) + sizeof(uintptr_t);
27982809
}
27992810
}

test/Interpreter/Inputs/ObjCClasses/ObjCClasses.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ __attribute__((swift_name("OuterType.InnerType")))
118118
@property NSArray<OuterType *> *things;
119119
@end
120120

121+
@interface ObjCPrintOnDealloc : NSObject
122+
@end
123+
121124
NS_ASSUME_NONNULL_END
122125

123126
#endif

test/Interpreter/Inputs/ObjCClasses/ObjCClasses.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,9 @@ - (id)init {
191191
}
192192

193193
@end
194+
195+
@implementation ObjCPrintOnDealloc
196+
- (void)dealloc {
197+
printf("ObjCPrintOnDealloc deinitialized!\n");
198+
}
199+
@end

test/Interpreter/Inputs/layout_string_witnesses_types.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,16 @@ public struct Wrapper<T> {
276276
}
277277
}
278278

279+
public struct NestedWrapper<T> {
280+
public let x: Wrapper<T>
281+
public let y: Wrapper<T>
282+
283+
public init(x: Wrapper<T>, y: Wrapper<T>) {
284+
self.x = x
285+
self.y = y
286+
}
287+
}
288+
279289
struct InternalGeneric<T> {
280290
let x: T
281291
let y: Int
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// RUN: %empty-directory(%t)
2+
//
3+
// RUN: %target-clang -fobjc-arc %S/Inputs/ObjCClasses/ObjCClasses.m -c -o %t/ObjCClasses.o
4+
// RUN: %target-swift-frontend -prespecialize-generic-metadata -enable-experimental-feature LayoutStringValueWitnesses -enable-experimental-feature LayoutStringValueWitnessesInstantiation -enable-layout-string-value-witnesses -enable-layout-string-value-witnesses-instantiation -enable-type-layout -enable-autolinking-runtime-compatibility-bytecode-layouts -parse-stdlib -emit-module -emit-module-path=%t/layout_string_witnesses_types.swiftmodule %S/Inputs/layout_string_witnesses_types.swift
5+
// RUN: %target-build-swift-dylib(%t/%target-library-name(layout_string_witnesses_types)) -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnessesInstantiation -Xfrontend -enable-layout-string-value-witnesses -Xfrontend -enable-layout-string-value-witnesses-instantiation -Xfrontend -enable-type-layout -Xfrontend -parse-stdlib -parse-as-library %S/Inputs/layout_string_witnesses_types.swift
6+
// RUN: %target-build-swift -g -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnesses -Xfrontend -enable-experimental-feature -Xfrontend LayoutStringValueWitnessesInstantiation -Xfrontend -enable-layout-string-value-witnesses -Xfrontend -enable-layout-string-value-witnesses-instantiation -Xfrontend -enable-type-layout -parse-stdlib -module-name layout_string_witnesses_dynamic -llayout_string_witnesses_types -L%t -I %S/Inputs/ObjCClasses/ %t/ObjCClasses.o -I %t -o %t/main %s %target-rpath(%t)
7+
// RUN: %target-codesign %t/main
8+
// RUN: %target-run %t/main %t/%target-library-name(layout_string_witnesses_types) | %FileCheck %s --check-prefix=CHECK -check-prefix=CHECK-%target-os
9+
10+
// REQUIRES: executable_test
11+
// REQUIRES: objc_interop
12+
13+
import Swift
14+
import layout_string_witnesses_types
15+
import ObjCClasses
16+
import Foundation
17+
18+
func testNestedResilientObjc() {
19+
let ptr = allocateInternalGenericPtr(of: NestedWrapper<ObjCPrintOnDealloc>.self)
20+
21+
do {
22+
let x = NestedWrapper<ObjCPrintOnDealloc>(x: .init(x: ObjCPrintOnDealloc()), y: .init(x: ObjCPrintOnDealloc()))
23+
testGenericInit(ptr, to: x)
24+
}
25+
26+
do {
27+
let y = NestedWrapper<ObjCPrintOnDealloc>(x: .init(x: ObjCPrintOnDealloc()), y: .init(x: ObjCPrintOnDealloc()))
28+
// CHECK-macosx: Before deinit
29+
print("Before deinit")
30+
31+
// CHECK-macosx-NEXT: ObjCPrintOnDealloc deinitialized!
32+
// CHECK-macosx-NEXT: ObjCPrintOnDealloc deinitialized!
33+
testGenericAssign(ptr, from: y)
34+
}
35+
36+
// CHECK-macosx-NEXT: Before deinit
37+
print("Before deinit")
38+
39+
// CHECK-macosx-NEXT: ObjCPrintOnDealloc deinitialized!
40+
// CHECK-macosx-NEXT: ObjCPrintOnDealloc deinitialized!
41+
testGenericDestroy(ptr, of: NestedWrapper<ObjCPrintOnDealloc>.self)
42+
43+
ptr.deallocate()
44+
}
45+
46+
testNestedResilientObjc()

0 commit comments

Comments
 (0)