Skip to content

Commit e8d474a

Browse files
author
Harlan Haskins
authored
Merge pull request #23343 from harlanhaskins/mangled-lassi
[Demangle] Check for old-style mangling in getObjCClassByMangledName
2 parents 086a985 + 09bdaa3 commit e8d474a

File tree

5 files changed

+207
-12
lines changed

5 files changed

+207
-12
lines changed

stdlib/private/StdlibUnittest/StdlibUnittest.swift

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ func _childProcess() {
839839
var stderr = _Stderr()
840840
print("\(_stdlibUnittestStreamPrefix);end", to: &stderr)
841841

842-
if !testSuite._testByName(testName).canReuseChildProcessAfterTest {
842+
if testSuite._shouldShutDownChildProcess(forTestNamed: testName) {
843843
return
844844
}
845845
}
@@ -1107,7 +1107,7 @@ class _ParentProcess {
11071107
// Check if the child has sent us "end" markers for the current test.
11081108
if stdoutEnd && stderrEnd {
11091109
var status: ProcessTerminationStatus?
1110-
if !testSuite._testByName(testName).canReuseChildProcessAfterTest {
1110+
if testSuite._shouldShutDownChildProcess(forTestNamed: testName) {
11111111
status = _waitForChild()
11121112
switch status! {
11131113
case .exit(0):
@@ -1147,7 +1147,11 @@ class _ParentProcess {
11471147
return (failed: false, ())
11481148
}
11491149
#endif
1150-
print("\(_stdlibUnittestStreamPrefix);shutdown", to: &_childStdin)
1150+
// If the child process expects an EOF, its stdin fd has already been closed and
1151+
// it will shut itself down automatically.
1152+
if !_childStdin.isClosed {
1153+
print("\(_stdlibUnittestStreamPrefix);shutdown", to: &_childStdin)
1154+
}
11511155

11521156
var childCrashed = false
11531157

@@ -1209,6 +1213,9 @@ class _ParentProcess {
12091213
if t.stdinText != nil {
12101214
print("The test \(fullTestName) requires stdin input and can't be run in-process, marking as failed")
12111215
_anyExpectFailed = true
1216+
} else if t.requiresOwnProcess {
1217+
print("The test \(fullTestName) requires running in a child process and can't be run in-process, marking as failed.")
1218+
_anyExpectFailed = true
12121219
} else {
12131220
_anyExpectFailed = false
12141221
testSuite._runTest(name: t.name, parameter: testParameter)
@@ -1550,6 +1557,17 @@ public final class TestSuite {
15501557
return _tests[_testNameToIndex[testName]!]
15511558
}
15521559

1560+
/// Determines if we should shut down the current test process, i.e. if this
1561+
/// test or the next test requires executing in its own process.
1562+
func _shouldShutDownChildProcess(forTestNamed testName: String) -> Bool {
1563+
let index = _testNameToIndex[testName]!
1564+
if index == _tests.count - 1 { return false }
1565+
let currentTest = _tests[index]
1566+
let nextTest = _tests[index + 1]
1567+
if !currentTest.canReuseChildProcessAfterTest { return true }
1568+
return currentTest.requiresOwnProcess || nextTest.requiresOwnProcess
1569+
}
1570+
15531571
internal enum _TestCode {
15541572
case single(code: () -> Void)
15551573
case parameterized(code: (Int) -> Void, count: Int)
@@ -1564,6 +1582,7 @@ public final class TestSuite {
15641582
let stdinEndsWithEOF: Bool
15651583
let crashOutputMatches: [String]
15661584
let code: _TestCode
1585+
let requiresOwnProcess: Bool
15671586

15681587
/// Whether the test harness should stop reusing the child process after
15691588
/// running this test.
@@ -1601,6 +1620,7 @@ public final class TestSuite {
16011620
var _stdinEndsWithEOF: Bool = false
16021621
var _crashOutputMatches: [String] = []
16031622
var _testLoc: SourceLoc?
1623+
var _requiresOwnProcess: Bool = false
16041624
}
16051625

16061626
init(testSuite: TestSuite, name: String, loc: SourceLoc) {
@@ -1630,6 +1650,11 @@ public final class TestSuite {
16301650
return self
16311651
}
16321652

1653+
public func requireOwnProcess() -> _TestBuilder {
1654+
_data._requiresOwnProcess = true
1655+
return self
1656+
}
1657+
16331658
internal func _build(_ testCode: _TestCode) {
16341659
_testSuite._tests.append(
16351660
_Test(
@@ -1638,7 +1663,8 @@ public final class TestSuite {
16381663
stdinText: _data._stdinText,
16391664
stdinEndsWithEOF: _data._stdinEndsWithEOF,
16401665
crashOutputMatches: _data._crashOutputMatches,
1641-
code: testCode))
1666+
code: testCode,
1667+
requiresOwnProcess: _data._requiresOwnProcess))
16421668
_testSuite._testNameToIndex[_name] = _testSuite._tests.count - 1
16431669
}
16441670

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,9 +1422,28 @@ static objc_hook_getClass OldGetClassHook;
14221422
static BOOL
14231423
getObjCClassByMangledName(const char * _Nonnull typeName,
14241424
Class _Nullable * _Nonnull outClass) {
1425-
auto metadata = swift_getTypeByMangledNameInEnvironment(typeName, strlen(typeName),
1426-
/* no substitutions */
1427-
nullptr, nullptr);
1425+
// Demangle old-style class and protocol names, which are still used in the
1426+
// ObjC metadata.
1427+
StringRef typeStr(typeName);
1428+
const Metadata *metadata = nullptr;
1429+
if (typeStr.startswith("_Tt")) {
1430+
Demangler demangler;
1431+
auto node = demangler.demangleSymbol(typeName);
1432+
if (!node)
1433+
return NO;
1434+
metadata = swift_getTypeByMangledNode(
1435+
MetadataState::Complete, demangler, node,
1436+
/* no substitutions */
1437+
[&](unsigned depth, unsigned index) {
1438+
return nullptr;
1439+
},
1440+
[&](const Metadata *type, unsigned index) {
1441+
return nullptr;
1442+
}).getMetadata();
1443+
} else {
1444+
metadata = swift_getTypeByMangledNameInEnvironment(
1445+
typeStr.data(), typeStr.size(), /* no substitutions */ nullptr, nullptr);
1446+
}
14281447
if (metadata) {
14291448
auto objcClass =
14301449
reinterpret_cast<Class>(
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
import resilient_struct
3+
import Foundation
4+
5+
6+
// Resilient base class
7+
8+
open class ResilientNSObjectOutsideParent: NSObject {
9+
open var property: String = "ResilientNSObjectOutsideParent.property"
10+
public final var finalProperty: String = "ResilientNSObjectOutsideParent.finalProperty"
11+
12+
open class var classProperty: String {
13+
return "ResilientNSObjectOutsideParent.classProperty"
14+
}
15+
16+
override public init() {
17+
print("ResilientNSObjectOutsideParent.init()")
18+
}
19+
20+
open func method() {
21+
print("ResilientNSObjectOutsideParent.method()")
22+
}
23+
24+
open class func classMethod() {
25+
print("ResilientNSObjectOutsideParent.classMethod()")
26+
}
27+
28+
open func getValue() -> Int {
29+
return 0
30+
}
31+
}
32+
33+
// Resilient generic base class
34+
35+
open class ResilientGenericNSObjectOutsideParent<A>: NSObject {
36+
open var property: A
37+
public init(property: A) {
38+
self.property = property
39+
print("ResilientGenericNSObjectOutsideParent.init()")
40+
}
41+
42+
open func method() {
43+
print("ResilientGenericNSObjectOutsideParent.method()")
44+
}
45+
46+
open class func classMethod() {
47+
print("ResilientGenericNSObjectOutsideParent.classMethod()")
48+
}
49+
}
50+
51+
// Resilient subclass of generic class
52+
53+
open class ResilientConcreteNSObjectOutsideChild : ResilientGenericNSObjectOutsideParent<String> {
54+
public override init(property: String) {
55+
print("ResilientConcreteNSObjectOutsideChild.init(property: String)")
56+
super.init(property: property)
57+
}
58+
59+
open override func method() {
60+
print("ResilientConcreteNSObjectOutsideChild.method()")
61+
super.method()
62+
}
63+
64+
open override class func classMethod() {
65+
print("ResilientConcreteNSObjectOutsideChild.classMethod()")
66+
super.classMethod()
67+
}
68+
}

test/Interpreter/SDK/objc_getClass.swift

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
// RUN: %target-build-swift-dylib(%t/%target-library-name(resilient_class)) -enable-library-evolution %S/../../Inputs/resilient_class.swift -emit-module -emit-module-path %t/resilient_class.swiftmodule -module-name resilient_class -I%t -L%t -lresilient_struct
77
// RUN: %target-codesign %t/%target-library-name(resilient_class)
88

9-
// RUN: %target-build-swift %s -L %t -I %t -lresilient_struct -lresilient_class -o %t/main %target-rpath(%t)
9+
// RUN: %target-build-swift-dylib(%t/%target-library-name(resilient_objc_class)) -Xfrontend -enable-resilience %S/../../Inputs/resilient_objc_class.swift -emit-module -emit-module-path %t/resilient_objc_class.swiftmodule -module-name resilient_objc_class -I%t -L%t -lresilient_struct
10+
// RUN: %target-codesign %t/%target-library-name(resilient_objc_class)
11+
12+
// RUN: %target-build-swift %s -L %t -I %t -lresilient_struct -lresilient_class -lresilient_objc_class -o %t/main %target-rpath(%t)
1013
// RUN: %target-codesign %t/main
1114

12-
// RUN: %target-run %t/main %t/%target-library-name(resilient_struct) %t/libresilient_class%{target-shared-library-suffix}
15+
// RUN: %target-run %t/main %t/%target-library-name(resilient_struct) %t/libresilient_class%{target-shared-library-suffix} %t/libresilient_objc_class%{target-shared-library-suffix}
1316

1417

1518
// REQUIRES: executable_test
@@ -22,6 +25,7 @@ import ObjectiveC
2225
import Foundation
2326
import resilient_struct
2427
import resilient_class
28+
import resilient_objc_class
2529

2630
// Old OS versions do not have this hook.
2731
let getClassHookMissing = {
@@ -110,6 +114,19 @@ class ResilientFieldSubclassObjC : ResilientFieldSuperclassObjC {
110114
var subvalue = ResilientInt(i: 4)
111115
}
112116

117+
class ResilientSubclassOfNSObject : ResilientNSObjectOutsideParent {
118+
var subvalue = ResilientInt(i: 5)
119+
}
120+
121+
class ResilientSubclassOfGenericNSObject : ResilientGenericNSObjectOutsideParent<Int> {
122+
var subvalue = ResilientInt(i: 6)
123+
init() { super.init(property: 0) }
124+
}
125+
126+
class ResilientSubclassOfConcreteNSObject : ResilientConcreteNSObjectOutsideChild {
127+
var subvalue = ResilientInt(i: 7)
128+
init() { super.init(property: "") }
129+
}
113130

114131
func requireClass(named name: String, demangledName: String) {
115132
for _ in 1...2 {
@@ -124,14 +141,18 @@ func requireClass(named name: String) {
124141
return requireClass(named: name, demangledName: name)
125142
}
126143

127-
testSuite.test("Basic") {
144+
testSuite.test("Basic")
145+
.requireOwnProcess()
146+
.code {
128147
requireClass(named: "main.SwiftSubclass")
129148
requireClass(named: "main.SwiftSuperclass")
130149
requireClass(named: "main.ObjCSubclass")
131150
requireClass(named: "main.ObjCSuperclass")
132151
}
133152

134-
testSuite.test("BasicMangled") {
153+
testSuite.test("BasicMangled")
154+
.requireOwnProcess()
155+
.code {
135156
requireClass(named: "_TtC4main20MangledSwiftSubclass",
136157
demangledName: "main.MangledSwiftSubclass")
137158
requireClass(named: "_TtC4main22MangledSwiftSuperclass",
@@ -145,6 +166,7 @@ testSuite.test("BasicMangled") {
145166
testSuite.test("Generic")
146167
.skip(.custom({ getClassHookMissing },
147168
reason: "objc_getClass hook not present"))
169+
.requireOwnProcess()
148170
.code {
149171
requireClass(named: "main.ConstrainedSwiftSubclass")
150172
requireClass(named: "main.ConstrainedSwiftSuperclass")
@@ -155,6 +177,7 @@ testSuite.test("Generic")
155177
testSuite.test("GenericMangled")
156178
.skip(.custom({ getClassHookMissing },
157179
reason: "objc_getClass hook not present"))
180+
.requireOwnProcess()
158181
.code {
159182
requireClass(named: "_TtC4main24ConstrainedSwiftSubclass",
160183
demangledName: "main.ConstrainedSwiftSubclass")
@@ -169,6 +192,7 @@ testSuite.test("GenericMangled")
169192
testSuite.test("ResilientSubclass")
170193
.skip(.custom({ getClassHookMissing },
171194
reason: "objc_getClass hook not present"))
195+
.requireOwnProcess()
172196
.code {
173197
requireClass(named: "main.ResilientSubclass")
174198
requireClass(named: "main.ResilientSuperclass")
@@ -181,6 +205,7 @@ testSuite.test("ResilientSubclass")
181205
testSuite.test("ResilientField")
182206
.skip(.custom({ getClassHookMissing },
183207
reason: "objc_getClass hook not present"))
208+
.requireOwnProcess()
184209
.code {
185210
requireClass(named: "main.ResilientFieldSubclassSwift")
186211
requireClass(named: "main.ResilientFieldSuperclassSwift")
@@ -195,6 +220,23 @@ testSuite.test("ResilientField")
195220
expectEqual(ResilientFieldSubclassObjC().subvalue.i, 4)
196221
}
197222

223+
testSuite.test("ResilientNSObject")
224+
.skip(.custom({ getClassHookMissing },
225+
reason: "objc_getClass hook not present"))
226+
.requireOwnProcess()
227+
.code {
228+
requireClass(named: "_TtC4main27ResilientSubclassOfNSObject",
229+
demangledName: "main.ResilientSubclassOfNSObject")
230+
requireClass(named: "_TtC4main34ResilientSubclassOfGenericNSObject",
231+
demangledName: "main.ResilientSubclassOfGenericNSObject")
232+
requireClass(named: "_TtC4main35ResilientSubclassOfConcreteNSObject",
233+
demangledName: "main.ResilientSubclassOfConcreteNSObject")
234+
235+
expectEqual(ResilientSubclassOfNSObject().subvalue.i, 5)
236+
expectEqual(ResilientSubclassOfGenericNSObject().subvalue.i, 6)
237+
expectEqual(ResilientSubclassOfConcreteNSObject().subvalue.i, 7)
238+
}
239+
198240
testSuite.test("NotPresent") {
199241
// This class does not exist.
200242
expectNil(NSClassFromString("main.ThisClassDoesNotExist"));
@@ -207,4 +249,3 @@ testSuite.test("NotPresent") {
207249
}
208250

209251
runAllTests()
210-
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// RUN: %target-run-simple-swift
2+
// REQUIRES: executable_test
3+
4+
import StdlibUnittest
5+
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
6+
import Darwin
7+
#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku)
8+
import Glibc
9+
#elseif os(Windows)
10+
import MSVCRT
11+
#else
12+
#error("Unsupported platform")
13+
#endif
14+
15+
//
16+
// Test that a test runs in its own child process if asked.
17+
//
18+
19+
enum Globals {
20+
static var modifiedByChildProcess = false
21+
}
22+
23+
var TestSuiteRequireNewProcess = TestSuite("TestSuiteRequireNewProcess")
24+
25+
TestSuiteRequireNewProcess.test("RequireOwnProcessBefore")
26+
.code {
27+
Globals.modifiedByChildProcess = true
28+
}
29+
30+
TestSuiteRequireNewProcess.test("RequireOwnProcess")
31+
.requireOwnProcess()
32+
.code {
33+
expectEqual(false, Globals.modifiedByChildProcess)
34+
Globals.modifiedByChildProcess = true
35+
}
36+
37+
TestSuiteRequireNewProcess.test("ShouldNotReusePreviousProcess") {
38+
expectEqual(false, Globals.modifiedByChildProcess)
39+
}
40+
41+
runAllTests()

0 commit comments

Comments
 (0)