Skip to content

Commit 55fc2b0

Browse files
authored
Merge pull request #16677 from mikeash/fix-static-stripped-error-bridging
[Runtime] Look up Error bridging symbols indirectly through special symbols that won't be stripped in static builds.
2 parents 193b3ee + 177f34c commit 55fc2b0

File tree

6 files changed

+75
-10
lines changed

6 files changed

+75
-10
lines changed

stdlib/public/SDK/Foundation/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ add_swift_library(swiftFoundation ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SD
2626
NSCoder.swift
2727
NSDate.swift
2828
NSDictionary.swift
29+
NSError.c
2930
NSError.swift
3031
NSExpression.swift
3132
NSFastEnumeration.swift
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "swift/Runtime/Config.h"
14+
15+
#if SWIFT_OBJC_INTEROP
16+
#include "swift/Demangling/ManglingMacros.h"
17+
18+
// Declare dynamic lookup points for ErrorObject.mm. It uses dlsym to
19+
// find these symbols to locate NS/CFError Error conformance tables and
20+
// related items. The .desc asm directive ensures that they are
21+
// preserved even when statically linked into an executable and
22+
// stripped, so that the dlsym lookup still works.
23+
#define ERROROBJECT_DYNAMIC_LOOKUP_POINT(symbol) \
24+
extern void *MANGLE_SYM(symbol); \
25+
void **MANGLING_CONCAT2(ErrorObjectLookup_, MANGLE_SYM(symbol)) = &MANGLE_SYM(symbol); \
26+
asm(".desc _ErrorObjectLookup_" MANGLE_AS_STRING(MANGLE_SYM(symbol)) ", 0x10");
27+
28+
ERROROBJECT_DYNAMIC_LOOKUP_POINT(So10CFErrorRefas5Error10FoundationWa)
29+
ERROROBJECT_DYNAMIC_LOOKUP_POINT(So8NSObjectCs8Hashable10ObjectiveCWa)
30+
ERROROBJECT_DYNAMIC_LOOKUP_POINT(10Foundation24_getErrorDefaultUserInfoyyXlSgxs0C0RzlF)
31+
ERROROBJECT_DYNAMIC_LOOKUP_POINT(10Foundation21_bridgeNSErrorToError_3outSbSo0C0C_SpyxGtAA021_ObjectiveCBridgeableE0RzlF)
32+
ERROROBJECT_DYNAMIC_LOOKUP_POINT(10Foundation26_ObjectiveCBridgeableErrorMp)
33+
34+
#endif

stdlib/public/runtime/ErrorObject.mm

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,21 @@ static Class getSwiftNativeNSErrorClass() {
220220
object_dispose((id)error);
221221
}
222222

223+
/// Look up a symbol that points to something else. Treats the symbol as
224+
/// a void** and dereferences it if it's non-NULL. Returns NULL if the
225+
/// symbol can't be found or if the value is NULL.
226+
static void *dynamicLookupSymbol(const char *name) {
227+
void **ptr = reinterpret_cast<void **>(dlsym(RTLD_DEFAULT, name));
228+
if (!ptr) return nullptr;
229+
return *ptr;
230+
}
231+
232+
/// Look up an indirect pointer to a mangled Swift symbol, automatically
233+
/// prepending the ErrorObjectLookup_ prefix. Used to find the various
234+
/// Foundation overlay symbols for Error bridging.
235+
#define DYNAMIC_LOOKUP_SYMBOL(symbol) \
236+
dynamicLookupSymbol("ErrorObjectLookup_" MANGLE_AS_STRING(MANGLE_SYM(symbol)))
237+
223238
static const WitnessTable *getNSErrorConformanceToError() {
224239
// CFError and NSError are toll-free-bridged, so we can use either type's
225240
// witness table interchangeably. CFError's is potentially slightly more
@@ -228,8 +243,7 @@ static Class getSwiftNativeNSErrorClass() {
228243
// to assume that that's been linked in if a user is using NSError in their
229244
// Swift source.
230245

231-
auto TheWitnessTable = SWIFT_LAZY_CONSTANT(dlsym(RTLD_DEFAULT,
232-
MANGLE_AS_STRING(MANGLE_SYM(So10CFErrorRefas5Error10FoundationWa))));
246+
auto TheWitnessTable = SWIFT_LAZY_CONSTANT(DYNAMIC_LOOKUP_SYMBOL(So10CFErrorRefas5Error10FoundationWa));
233247
assert(TheWitnessTable &&
234248
"Foundation overlay not loaded, or 'CFError : Error' conformance "
235249
"not available");
@@ -238,8 +252,7 @@ static Class getSwiftNativeNSErrorClass() {
238252
}
239253

240254
static const HashableWitnessTable *getNSErrorConformanceToHashable() {
241-
auto TheWitnessTable = SWIFT_LAZY_CONSTANT(dlsym(RTLD_DEFAULT,
242-
MANGLE_AS_STRING(MANGLE_SYM(So8NSObjectCs8Hashable10ObjectiveCWa))));
255+
auto TheWitnessTable = SWIFT_LAZY_CONSTANT(DYNAMIC_LOOKUP_SYMBOL(So8NSObjectCs8Hashable10ObjectiveCWa));
243256
assert(TheWitnessTable &&
244257
"ObjectiveC overlay not loaded, or 'NSObject : Hashable' conformance "
245258
"not available");
@@ -379,8 +392,7 @@ typedef SWIFT_CC(swift)
379392
// public func Foundation._getErrorDefaultUserInfo<T: Error>(_ error: T)
380393
// -> AnyObject?
381394
auto foundationGetDefaultUserInfo = SWIFT_LAZY_CONSTANT(
382-
reinterpret_cast<GetDefaultFn*> (dlsym(RTLD_DEFAULT,
383-
MANGLE_AS_STRING(MANGLE_SYM(10Foundation24_getErrorDefaultUserInfoyyXlSgxs0C0RzlF)))));
395+
reinterpret_cast<GetDefaultFn*> (DYNAMIC_LOOKUP_SYMBOL(10Foundation24_getErrorDefaultUserInfoyyXlSgxs0C0RzlF)));
384396
if (!foundationGetDefaultUserInfo) {
385397
SWIFT_CC_PLUSONE_GUARD(T->vw_destroy(error));
386398
return nullptr;
@@ -520,12 +532,10 @@ typedef SWIFT_CC(swift)
520532
bool BridgeFn(NSError *, OpaqueValue*, const Metadata *,
521533
const WitnessTable *);
522534
auto bridgeNSErrorToError = SWIFT_LAZY_CONSTANT(
523-
reinterpret_cast<BridgeFn*>(dlsym(RTLD_DEFAULT,
524-
MANGLE_AS_STRING(MANGLE_SYM(10Foundation21_bridgeNSErrorToError_3outSbSo0C0C_SpyxGtAA021_ObjectiveCBridgeableE0RzlF)))));
535+
reinterpret_cast<BridgeFn*>(DYNAMIC_LOOKUP_SYMBOL(10Foundation21_bridgeNSErrorToError_3outSbSo0C0C_SpyxGtAA021_ObjectiveCBridgeableE0RzlF)));
525536
// protocol _ObjectiveCBridgeableError
526537
auto TheObjectiveCBridgeableError = SWIFT_LAZY_CONSTANT(
527-
reinterpret_cast<const ProtocolDescriptor *>(dlsym(RTLD_DEFAULT,
528-
MANGLE_AS_STRING(MANGLE_SYM(10Foundation26_ObjectiveCBridgeableErrorMp)))));
538+
reinterpret_cast<const ProtocolDescriptor *>(DYNAMIC_LOOKUP_SYMBOL(10Foundation26_ObjectiveCBridgeableErrorMp)));
529539

530540
// If the Foundation overlay isn't loaded, then arbitrary NSErrors can't be
531541
// bridged.

test/stdlib/ErrorBridgedStatic.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ class Bar: Foo {
1414
override func foo(_ x: Int32) throws {
1515
try super.foo(5)
1616
}
17+
18+
override func foothrows(_ x: Int32) throws {
19+
try super.foothrows(5)
20+
}
1721
}
1822

1923
var ErrorBridgingStaticTests = TestSuite("ErrorBridging with static libs")
@@ -24,4 +28,14 @@ ErrorBridgingStaticTests.test("round-trip Swift override of ObjC method") {
2428
} catch { }
2529
}
2630

31+
ErrorBridgingStaticTests.test("round-trip Swift override of throwing ObjC method") {
32+
do {
33+
try (Bar() as Foo).foothrows(5)
34+
} catch {
35+
print(error)
36+
expectEqual(error._domain, "abcd")
37+
expectEqual(error._code, 1234)
38+
}
39+
}
40+
2741
runAllTests()

test/stdlib/Inputs/ErrorBridgedStaticImpl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
@interface Foo: NSObject
44

55
- (BOOL)foo:(int)x error:(NSError**)error;
6+
- (BOOL)foothrows:(int)x error:(NSError**)error;
67

78
@end

test/stdlib/Inputs/ErrorBridgedStaticImpl.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,10 @@ - (BOOL)foo:(int)x error:(NSError**)error {
77
return NO;
88
}
99

10+
- (BOOL)foothrows:(int)x error:(NSError**)error {
11+
*error = [NSError errorWithDomain: @"abcd" code: 1234 userInfo: nil];
12+
return NO;
13+
}
14+
1015
@end
1116

0 commit comments

Comments
 (0)