mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Runtime][IRGen] Trap C++ exceptions on *throw*, not catch.
The previous approach was effectively to catch the exception and then run a trap instruction. That has the unfortunate feature that we end up with a crash at the catch site, not at the throw site, which leaves us with very little information about which exception was thrown or where from. (Strictly we do have the exception pointer and could obtain exception information, but it still won't tell us what threw it.) Instead of that, set a personality function for Swift functions that call potentially throwing code, and have that personality function trap the exception during phase 1 (i.e. *before* the original stack has been unwound). rdar://120952971
This commit is contained in:
42
include/swift/Runtime/Exception.h
Normal file
42
include/swift/Runtime/Exception.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//===--- Exception.h - Exception support ------------------------*- C++ -*-===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2017 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 doesn't support exception handlers, but might call code that uses
|
||||
// exceptions, and when they leak out into Swift code, we want to trap them.
|
||||
//
|
||||
// To that end, we have our own exception personality routine, which we use
|
||||
// to trap exceptions and terminate.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef SWIFT_RUNTIME_EXCEPTION_H
|
||||
#define SWIFT_RUNTIME_EXCEPTION_H
|
||||
|
||||
#include "swift/Runtime/Config.h"
|
||||
|
||||
#if defined(__ELF__) || defined(__APPLE__)
|
||||
#include <unwind.h>
|
||||
|
||||
namespace swift {
|
||||
|
||||
SWIFT_RUNTIME_STDLIB_API _Unwind_Reason_Code
|
||||
swift_exceptionPersonality(int version,
|
||||
_Unwind_Action actions,
|
||||
uint64_t exceptionClass,
|
||||
struct _Unwind_Exception *exceptionObject,
|
||||
struct _Unwind_Context *context);
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
#endif // defined(__ELF__) || defined(__APPLE__)
|
||||
|
||||
#endif // SWIFT_RUNTIME_EXCEPTION_H
|
||||
@@ -2807,6 +2807,24 @@ FUNCTION(InitRawStructMetadata,
|
||||
EFFECT(MetaData),
|
||||
UNKNOWN_MEMEFFECTS)
|
||||
|
||||
// _Unwind_Reason_Code swift_exceptionPersonality(int version,
|
||||
// _Unwind_Action actions,
|
||||
// uint64 exceptionClass,
|
||||
// struct _Unwind_Exception *exceptionObject,
|
||||
// struct _Unwind_Context *context);
|
||||
FUNCTION(ExceptionPersonality,
|
||||
swift_exceptionPersonality,
|
||||
C_CC, AlwaysAvailable,
|
||||
RETURNS(Int32Ty),
|
||||
ARGS(Int32Ty,
|
||||
Int32Ty,
|
||||
Int64Ty,
|
||||
Int8PtrTy,
|
||||
Int8PtrTy),
|
||||
ATTRS(NoUnwind),
|
||||
EFFECT(NoEffect),
|
||||
UNKNOWN_MEMEFFECTS)
|
||||
|
||||
#undef RETURNS
|
||||
#undef ARGS
|
||||
#undef ATTRS
|
||||
|
||||
@@ -4994,7 +4994,22 @@ void IRGenFunction::emitEpilogue() {
|
||||
// The function should have an unwind table when catching exceptions.
|
||||
CurFn->addFnAttr(llvm::Attribute::getWithUWTableKind(
|
||||
*IGM.LLVMContext, llvm::UWTableKind::Default));
|
||||
CurFn->setPersonalityFn(IGM.getForeignExceptionHandlingPersonalityFunc());
|
||||
|
||||
auto deploymentAvailability =
|
||||
AvailabilityContext::forDeploymentTarget(IGM.Context);
|
||||
bool canUseSwiftPersonality = deploymentAvailability.isContainedIn(
|
||||
IGM.Context.getSwift511Availability());
|
||||
llvm::Constant *personality;
|
||||
|
||||
if (canUseSwiftPersonality) {
|
||||
// The function should use our personality routine
|
||||
auto swiftPersonality = IGM.getExceptionPersonalityFunctionPointer();
|
||||
personality = swiftPersonality.getDirectPointer();
|
||||
} else {
|
||||
personality = IGM.getForeignExceptionHandlingPersonalityFunc();
|
||||
}
|
||||
|
||||
CurFn->setPersonalityFn(personality);
|
||||
}
|
||||
for (auto *bb : ExceptionUnwindBlocks)
|
||||
CurFn->insert(CurFn->end(), bb);
|
||||
|
||||
@@ -47,6 +47,7 @@ set(swift_runtime_sources
|
||||
ErrorObjectNative.cpp
|
||||
Errors.cpp
|
||||
ErrorDefaultImpls.cpp
|
||||
Exception.cpp
|
||||
Exclusivity.cpp
|
||||
ExistentialContainer.cpp
|
||||
Float16Support.cpp
|
||||
|
||||
51
stdlib/public/runtime/Exception.cpp
Normal file
51
stdlib/public/runtime/Exception.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
//===--- Exception.cpp - Exception support --------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2017 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 doesn't support exception handlers, but might call code that uses
|
||||
// exceptions, and when they leak out into Swift code, we want to trap them.
|
||||
//
|
||||
// To that end, we have our own exception personality routine, which we use
|
||||
// to trap exceptions and terminate.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined(__ELF__) || defined(__APPLE__)
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <unwind.h>
|
||||
|
||||
#include "swift/Runtime/Exception.h"
|
||||
|
||||
using namespace swift;
|
||||
|
||||
extern "C" void __cxa_begin_catch(void *);
|
||||
|
||||
SWIFT_RUNTIME_STDLIB_API _Unwind_Reason_Code
|
||||
swift_exceptionPersonality(int version,
|
||||
_Unwind_Action actions,
|
||||
uint64_t exceptionClass,
|
||||
struct _Unwind_Exception *exceptionObject,
|
||||
struct _Unwind_Context *context)
|
||||
{
|
||||
// Handle exceptions by catching them and calling std::terminate().
|
||||
// This, in turn, will trigger the unhandled exception routine in the
|
||||
// C++ runtime.
|
||||
__cxa_begin_catch(exceptionObject);
|
||||
std::terminate();
|
||||
|
||||
return _URC_FATAL_PHASE1_ERROR;
|
||||
}
|
||||
|
||||
#endif /* defined(__ELF__) || defined(__APPLE__) */
|
||||
Reference in New Issue
Block a user