Skip to content

Commit a8e0d74

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 549ad3f commit a8e0d74

File tree

5 files changed

+77
-1
lines changed

5 files changed

+77
-1
lines changed

stdlib/public/runtime/Metadata.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2734,7 +2734,18 @@ void swift::swift_initStructMetadataWithLayoutString(
27342734
} else if (fieldType->hasLayoutString()) {
27352735
refCountBytes += *(const size_t *)(fieldType->getLayoutString() +
27362736
sizeof(uint64_t));
2737-
} else if (fieldType->isClassObject() || fieldType->isAnyExistentialType()) {
2737+
} else if (auto *cls = type->getClassObject()) {
2738+
if (cls->isTypeMetadata()) {
2739+
auto *vwt = cls->getValueWitnesses();
2740+
if (vwt != &VALUE_WITNESS_SYM(Bo) &&
2741+
vwt != &VALUE_WITNESS_SYM(BO) &&
2742+
vwt != &VALUE_WITNESS_SYM(Bb)) {
2743+
refCountBytes += sizeof(uint64_t) + sizeof(uintptr_t);
2744+
continue;
2745+
}
2746+
}
2747+
refCountBytes += sizeof(uint64_t);
2748+
} else if (type->isAnyExistentialType()) {
27382749
refCountBytes += sizeof(uint64_t);
27392750
} else {
27402751
refCountBytes += sizeof(uint64_t) + sizeof(uintptr_t);

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
@@ -271,6 +271,16 @@ public struct Wrapper<T> {
271271
}
272272
}
273273

274+
public struct NestedWrapper<T> {
275+
public let x: Wrapper<T>
276+
public let y: Wrapper<T>
277+
278+
public init(x: Wrapper<T>, y: Wrapper<T>) {
279+
self.x = x
280+
self.y = y
281+
}
282+
}
283+
274284
struct InternalGeneric<T> {
275285
let x: T
276286
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)