Skip to content

Commit 143a473

Browse files
committed
[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
1 parent 2092240 commit 143a473

File tree

5 files changed

+128
-1
lines changed

5 files changed

+128
-1
lines changed

include/swift/Runtime/Exception.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===--- Exception.h - Exception support ------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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+
// Swift doesn't support exception handlers, but might call code that uses
14+
// exceptions, and when they leak out into Swift code, we want to trap them.
15+
//
16+
// To that end, we have our own exception personality routine, which we use
17+
// to trap exceptions and terminate.
18+
//
19+
//===----------------------------------------------------------------------===//
20+
21+
#ifndef SWIFT_RUNTIME_EXCEPTION_H
22+
#define SWIFT_RUNTIME_EXCEPTION_H
23+
24+
#include "swift/Runtime/Config.h"
25+
26+
#if defined(__ELF__) || defined(__APPLE__)
27+
#include <unwind.h>
28+
29+
namespace swift {
30+
31+
SWIFT_RUNTIME_STDLIB_API _Unwind_Reason_Code
32+
swift_exceptionPersonality(int version,
33+
_Unwind_Action actions,
34+
uint64_t exceptionClass,
35+
struct _Unwind_Exception *exceptionObject,
36+
struct _Unwind_Context *context);
37+
38+
} // end namespace swift
39+
40+
#endif // defined(__ELF__) || defined(__APPLE__)
41+
42+
#endif // SWIFT_RUNTIME_EXCEPTION_H

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2807,6 +2807,24 @@ FUNCTION(InitRawStructMetadata,
28072807
EFFECT(MetaData),
28082808
UNKNOWN_MEMEFFECTS)
28092809

2810+
// _Unwind_Reason_Code swift_exceptionPersonality(int version,
2811+
// _Unwind_Action actions,
2812+
// uint64 exceptionClass,
2813+
// struct _Unwind_Exception *exceptionObject,
2814+
// struct _Unwind_Context *context);
2815+
FUNCTION(ExceptionPersonality,
2816+
swift_exceptionPersonality,
2817+
C_CC, AlwaysAvailable,
2818+
RETURNS(Int32Ty),
2819+
ARGS(Int32Ty,
2820+
Int32Ty,
2821+
Int64Ty,
2822+
Int8PtrTy,
2823+
Int8PtrTy),
2824+
ATTRS(NoUnwind),
2825+
EFFECT(NoEffect),
2826+
UNKNOWN_MEMEFFECTS)
2827+
28102828
#undef RETURNS
28112829
#undef ARGS
28122830
#undef ATTRS

lib/IRGen/GenCall.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4994,7 +4994,22 @@ void IRGenFunction::emitEpilogue() {
49944994
// The function should have an unwind table when catching exceptions.
49954995
CurFn->addFnAttr(llvm::Attribute::getWithUWTableKind(
49964996
*IGM.LLVMContext, llvm::UWTableKind::Default));
4997-
CurFn->setPersonalityFn(IGM.getForeignExceptionHandlingPersonalityFunc());
4997+
4998+
auto deploymentAvailability =
4999+
AvailabilityContext::forDeploymentTarget(IGM.Context);
5000+
bool canUseSwiftPersonality = deploymentAvailability.isContainedIn(
5001+
IGM.Context.getSwift511Availability());
5002+
llvm::Constant *personality;
5003+
5004+
if (canUseSwiftPersonality) {
5005+
// The function should use our personality routine
5006+
auto swiftPersonality = IGM.getExceptionPersonalityFunctionPointer();
5007+
personality = swiftPersonality.getDirectPointer();
5008+
} else {
5009+
personality = IGM.getForeignExceptionHandlingPersonalityFunc();
5010+
}
5011+
5012+
CurFn->setPersonalityFn(personality);
49985013
}
49995014
for (auto *bb : ExceptionUnwindBlocks)
50005015
CurFn->insert(CurFn->end(), bb);

stdlib/public/runtime/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ set(swift_runtime_sources
4747
ErrorObjectNative.cpp
4848
Errors.cpp
4949
ErrorDefaultImpls.cpp
50+
Exception.cpp
5051
Exclusivity.cpp
5152
ExistentialContainer.cpp
5253
Float16Support.cpp

stdlib/public/runtime/Exception.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===--- Exception.cpp - Exception support --------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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+
// Swift doesn't support exception handlers, but might call code that uses
14+
// exceptions, and when they leak out into Swift code, we want to trap them.
15+
//
16+
// To that end, we have our own exception personality routine, which we use
17+
// to trap exceptions and terminate.
18+
//
19+
//===----------------------------------------------------------------------===//
20+
21+
#if defined(__ELF__) || defined(__APPLE__)
22+
23+
#include <exception>
24+
25+
#include <cstdio>
26+
27+
#include <unwind.h>
28+
29+
#include "swift/Runtime/Exception.h"
30+
31+
using namespace swift;
32+
33+
extern "C" void __cxa_begin_catch(void *);
34+
35+
SWIFT_RUNTIME_STDLIB_API _Unwind_Reason_Code
36+
swift_exceptionPersonality(int version,
37+
_Unwind_Action actions,
38+
uint64_t exceptionClass,
39+
struct _Unwind_Exception *exceptionObject,
40+
struct _Unwind_Context *context)
41+
{
42+
// Handle exceptions by catching them and calling std::terminate().
43+
// This, in turn, will trigger the unhandled exception routine in the
44+
// C++ runtime.
45+
__cxa_begin_catch(exceptionObject);
46+
std::terminate();
47+
48+
return _URC_FATAL_PHASE1_ERROR;
49+
}
50+
51+
#endif /* defined(__ELF__) || defined(__APPLE__) */

0 commit comments

Comments
 (0)