Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions stdlib/private/StdlibUnittest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ add_swift_target_library(swiftStdlibUnittest ${SWIFT_STDLIB_LIBRARY_BUILD_TYPES}
Statistics.swift
StdlibCoreExtras.swift
StringConvertible.swift
SymbolLookup.swift
TestHelpers.swift
TypeIndexed.swift

Expand Down
49 changes: 49 additions & 0 deletions stdlib/private/StdlibUnittest/SymbolLookup.swift
Original file line number Diff line number Diff line change
@@ -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
}
1 change: 1 addition & 0 deletions stdlib/public/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ set(swift_runtime_sources
CygwinPort.cpp
Demangle.cpp
Enum.cpp
ErrorObjectCommon.cpp
ErrorObjectConstants.cpp
ErrorObjectNative.cpp
Errors.cpp
Expand Down
7 changes: 0 additions & 7 deletions stdlib/public/runtime/ErrorObject.mm
Original file line number Diff line number Diff line change
Expand Up @@ -598,12 +598,5 @@ ProtocolDescriptorRef theErrorProtocol(&PROTOCOL_DESCR_SYM(s5Error),
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

38 changes: 38 additions & 0 deletions stdlib/public/runtime/ErrorObjectCommon.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
7 changes: 0 additions & 7 deletions stdlib/public/runtime/ErrorObjectNative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,4 @@ swift::swift_getErrorValue(const SwiftError *errorObject,
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
26 changes: 26 additions & 0 deletions stdlib/public/runtime/ErrorObjectTestSupport.h
Original file line number Diff line number Diff line change
@@ -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
23 changes: 23 additions & 0 deletions test/stdlib/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -191,5 +191,28 @@ ErrorTests.test("test dealloc empty error box") {
}
}

var errors: [Error] = []
ErrorTests.test("willThrow") {
// Error isn't allowed in a @convention(c) function when ObjC interop is
// not available, so pass it through an OpaquePointer.
typealias WillThrow = @convention(c) (OpaquePointer) -> Void
let willThrow = pointerToSwiftCoreSymbol(name: "_swift_willThrow")!
let callback: WillThrow = {
errors.append(unsafeBitCast($0, to: Error.self))
}
willThrow.storeBytes(of: callback, 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()

34 changes: 2 additions & 32 deletions test/stdlib/Runtime.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -592,39 +592,9 @@ Runtime.test("Struct layout with reference storage types") {
}

Runtime.test("SwiftError layout constants for LLDB") {
#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
_UnimplementedError()
#endif
#elseif os(Windows)
let hStdlibCore: HMODULE = GetModuleHandleA("swiftCore.dll")!
#else
_UnimplementedError()
#endif
let offsetof_SwiftError_typeMetadata = pointerToSwiftCoreSymbol(name: "_swift_lldb_offsetof_SwiftError_typeMetadata")!
let sizeof_SwiftError = pointerToSwiftCoreSymbol(name: "_swift_lldb_sizeof_SwiftError")!

#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 arch(i386) || arch(arm)
expectEqual(20, offsetof_SwiftError_typeMetadata.load(as: UInt.self))
Expand Down