[Runtime] Add a function pointer for intercepting swift_willThrow calls.

rdar://problem/53400364
This commit is contained in:
Mike Ash
2019-10-22 15:50:14 -04:00
parent c55965519e
commit b8f5e841e2
9 changed files with 135 additions and 46 deletions

View File

@@ -27,6 +27,7 @@ add_swift_target_library(swiftStdlibUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES}
Statistics.swift Statistics.swift
StdlibCoreExtras.swift StdlibCoreExtras.swift
StringConvertible.swift StringConvertible.swift
SymbolLookup.swift
TestHelpers.swift TestHelpers.swift
TypeIndexed.swift TypeIndexed.swift

View File

@@ -0,0 +1,49 @@
//===--- SymbolLookup.swift -----------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
import Darwin
#elseif os(Linux) || os(FreeBSD) || os(PS4) || os(Android) || os(Cygwin) || os(Haiku)
import Glibc
#elseif os(Windows)
import MSVCRT
import WinSDK
#else
#error("Unsupported platform")
#endif
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
#elseif os(Linux)
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: 0)
#elseif os(Android)
#if arch(arm)
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: 0xffffffff as UInt)
#elseif arch(arm64)
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: 0)
#else
#error("Unsupported platform")
#endif
#elseif os(Windows)
let hStdlibCore: HMODULE = GetModuleHandleA("swiftCore.dll")!
#else
#error("Unsupported platform")
#endif
public func pointerToSwiftCoreSymbol(name: String) -> UnsafeMutableRawPointer? {
#if os(Windows)
return unsafeBitCast(GetProcAddress(hStdlibCore, name),
to: UnsafeMutableRawPointer?.self)
#else
return dlsym(RTLD_DEFAULT, name)
#endif
}

View File

@@ -37,6 +37,7 @@ set(swift_runtime_sources
CygwinPort.cpp CygwinPort.cpp
Demangle.cpp Demangle.cpp
Enum.cpp Enum.cpp
ErrorObjectCommon.cpp
ErrorObjectConstants.cpp ErrorObjectConstants.cpp
ErrorObjectNative.cpp ErrorObjectNative.cpp
Errors.cpp Errors.cpp

View File

@@ -598,12 +598,5 @@ swift::swift_errorRelease(SwiftError *error) {
return objc_release((id)error); return objc_release((id)error);
} }
/// Breakpoint hook for debuggers.
SWIFT_CC(swift) void
swift::swift_willThrow(SWIFT_CONTEXT void *unused,
SWIFT_ERROR_RESULT SwiftError **error) {
// empty
}
#endif #endif

View File

@@ -0,0 +1,38 @@
//===--- ErrorObjectCommon.cpp - Recoverable error object -----------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This implements the parts of the standard Error protocol type which are
// shared between the ObjC-interoperable implementation and the native
// implementation. The parts specific to each implementation can be found in
// ErrorObject.mm (for the ObjC-interoperable parts) and ErrorObjectNative.cpp.
//
//===----------------------------------------------------------------------===//
#include "swift/Runtime/Concurrent.h"
#include "swift/Runtime/Config.h"
#include "ErrorObject.h"
#include "ErrorObjectTestSupport.h"
using namespace swift;
void (*swift::_swift_willThrow)(SwiftError *error);
/// Breakpoint hook for debuggers, and calls _swift_willThrow if set.
SWIFT_CC(swift) void
swift::swift_willThrow(SWIFT_CONTEXT void *unused,
SWIFT_ERROR_RESULT SwiftError **error) {
// Cheap check to bail out early, since we expect there to be no callbacks
// the vast majority of the time.
if (SWIFT_LIKELY(!_swift_willThrow))
return;
_swift_willThrow(*error);
}

View File

@@ -106,11 +106,4 @@ swift::swift_getErrorValue(const SwiftError *errorObject,
out->errorConformance = errorObject->errorConformance; out->errorConformance = errorObject->errorConformance;
} }
/// Breakpoint hook for debuggers.
SWIFT_CC(swift) void
swift::swift_willThrow(SWIFT_CONTEXT void *unused,
SWIFT_ERROR_RESULT SwiftError **error) {
// do nothing
}
#endif #endif

View File

@@ -0,0 +1,26 @@
//===--- ErrorObjectTestSupport.h - Support for Instruments.app -*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Swift runtime support for tests involving errors.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_RUNTIME_ERROROBJECT_TEST_SUPPORT_H
#define SWIFT_RUNTIME_ERROROBJECT_TEST_SUPPORT_H
namespace swift {
SWIFT_RUNTIME_EXPORT void (*_swift_willThrow)(SwiftError *error);
}
#endif

View File

@@ -191,5 +191,23 @@ ErrorTests.test("test dealloc empty error box") {
} }
} }
var errors: [Error] = []
ErrorTests.test("willThrow") {
typealias WillThrow = @convention(c) (Error) -> Void
let willThrow = pointerToSwiftCoreSymbol(name: "_swift_willThrow")!
willThrow.storeBytes(of: { errors.append($0) }, as: WillThrow.self)
expectTrue(errors.isEmpty)
do {
throw UnsignedError.negativeOne
} catch {}
expectEqual(UnsignedError.self, type(of: errors.last!))
do {
throw SillyError.JazzHands
} catch {}
expectEqual(2, errors.count)
expectEqual(SillyError.self, type(of: errors.last!))
}
runAllTests() runAllTests()

View File

@@ -592,39 +592,9 @@ Runtime.test("Struct layout with reference storage types") {
} }
Runtime.test("SwiftError layout constants for LLDB") { Runtime.test("SwiftError layout constants for LLDB") {
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) let offsetof_SwiftError_typeMetadata = pointerToSwiftCoreSymbol(name: "_swift_lldb_offsetof_SwiftError_typeMetadata")!
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2) let sizeof_SwiftError = pointerToSwiftCoreSymbol(name: "_swift_lldb_sizeof_SwiftError")!
#elseif os(Linux)
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: 0)
#elseif os(Android)
#if arch(arm)
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: 0xffffffff as UInt)
#elseif arch(arm64)
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: 0)
#else
_UnimplementedError()
#endif
#elseif os(Windows)
let hStdlibCore: HMODULE = GetModuleHandleA("swiftCore.dll")!
#else
_UnimplementedError()
#endif
#if os(Windows)
let offsetof_SwiftError_typeMetadata: UnsafeRawPointer =
unsafeBitCast(GetProcAddress(hStdlibCore,
"_swift_lldb_offsetof_SwiftError_typeMetadata")!,
to: UnsafeRawPointer.self)
let sizeof_SwiftError: UnsafeRawPointer =
unsafeBitCast(GetProcAddress(hStdlibCore,
"_swift_lldb_sizeof_SwiftError")!,
to: UnsafeRawPointer.self)
#else
let offsetof_SwiftError_typeMetadata =
dlsym(RTLD_DEFAULT, "_swift_lldb_offsetof_SwiftError_typeMetadata")!
let sizeof_SwiftError =
dlsym(RTLD_DEFAULT, "_swift_lldb_sizeof_SwiftError")!
#endif
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
#if arch(i386) || arch(arm) #if arch(i386) || arch(arm)
expectEqual(20, offsetof_SwiftError_typeMetadata.load(as: UInt.self)) expectEqual(20, offsetof_SwiftError_typeMetadata.load(as: UInt.self))