Skip to content

Commit 71efd95

Browse files
committed
[Demangler][Runtime] Give the demangler its own error handling.
The demangling library can't use the error handling from the main runtime because it isn't always linked with it. However, it's useful to have some error handling, and in particular to be able to get data into the crash logs. This is complicated because of the way the demangling library gets used, the upshot of which is that I've had to add a second object library just for libswiftCore's use, so that the demangler will use the runtime's error handling functions when present, and fall back on its own when they aren't. rdar://89139049
1 parent edbfce2 commit 71efd95

File tree

9 files changed

+373
-19
lines changed

9 files changed

+373
-19
lines changed

include/swift/Demangling/Demangle.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#ifndef SWIFT_DEMANGLING_DEMANGLE_H
2020
#define SWIFT_DEMANGLING_DEMANGLE_H
2121

22+
#include "swift/Demangling/Errors.h"
2223
#include "swift/Demangling/NamespaceMacros.h"
2324
#include "llvm/ADT/StringRef.h"
2425
#include "llvm/Support/Compiler.h"

include/swift/Demangling/Errors.h

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//===--- Errors.h - Demangling library error handling -----------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2022 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+
// This file exists because not every client links to libswiftCore (the
14+
// runtime), so calling swift::fatalError() or swift::warning() from within
15+
// the demangler is not an option.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#ifndef SWIFT_DEMANGLING_ERRORS_H
20+
#define SWIFT_DEMANGLING_ERRORS_H
21+
22+
#include "../../../stdlib/public/SwiftShims/Visibility.h"
23+
#include "swift/Demangling/NamespaceMacros.h"
24+
#include <inttypes.h>
25+
#include <stdarg.h>
26+
27+
#ifndef SWIFT_FORMAT
28+
// SWIFT_FORMAT(fmt,first) marks a function as taking a format string argument
29+
// at argument `fmt`, with the first argument for the format string as `first`.
30+
#if __has_attribute(format)
31+
#define SWIFT_FORMAT(fmt, first) __attribute__((format(printf, fmt, first)))
32+
#else
33+
#define SWIFT_FORMAT(fmt, first)
34+
#endif
35+
#endif
36+
37+
#ifndef SWIFT_VFORMAT
38+
// SWIFT_VFORMAT(fmt) marks a function as taking a format string argument at
39+
// argument `fmt`, with the arguments in a `va_list`.
40+
#if __has_attribute(format)
41+
#define SWIFT_VFORMAT(fmt) __attribute__((format(printf, fmt, 0)))
42+
#else
43+
#define SWIFT_VFORMAT(fmt)
44+
#endif
45+
#endif
46+
47+
#ifdef SWIFT_HAVE_CRASHREPORTERCLIENT
48+
49+
#define CRASHREPORTER_ANNOTATIONS_VERSION 5
50+
#define CRASHREPORTER_ANNOTATIONS_SECTION "__crash_info"
51+
52+
struct crashreporter_annotations_t {
53+
uint64_t version; // unsigned long
54+
uint64_t message; // char *
55+
uint64_t signature_string; // char *
56+
uint64_t backtrace; // char *
57+
uint64_t message2; // char *
58+
uint64_t thread; // uint64_t
59+
uint64_t dialog_mode; // unsigned int
60+
uint64_t abort_cause; // unsigned int
61+
};
62+
63+
extern "C" {
64+
SWIFT_RUNTIME_LIBRARY_VISIBILITY
65+
extern struct crashreporter_annotations_t gCRAnnotations;
66+
}
67+
68+
SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE
69+
static inline void CRSetCrashLogMessage(const char *message) {
70+
gCRAnnotations.message = reinterpret_cast<uint64_t>(message);
71+
}
72+
73+
SWIFT_RUNTIME_ATTRIBUTE_ALWAYS_INLINE
74+
static inline const char *CRGetCrashLogMessage() {
75+
return reinterpret_cast<const char *>(gCRAnnotations.message);
76+
}
77+
78+
#endif
79+
80+
namespace swift {
81+
namespace Demangle {
82+
SWIFT_BEGIN_INLINE_NAMESPACE
83+
84+
SWIFT_NORETURN SWIFT_FORMAT(2, 3) void fatal(uint32_t flags, const char *format,
85+
...);
86+
SWIFT_FORMAT(2, 3) void warn(uint32_t flags, const char *format, ...);
87+
88+
SWIFT_NORETURN SWIFT_VFORMAT(2) void fatalv(uint32_t flags, const char *format,
89+
va_list val);
90+
SWIFT_VFORMAT(2) void warnv(uint32_t flags, const char *format, va_list val);
91+
92+
SWIFT_END_INLINE_NAMESPACE
93+
} // end namespace Demangle
94+
} // end namespace swift
95+
96+
#endif // SWIFT_DEMANGLING_DEMANGLE_H

include/swift/Runtime/Debug.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,13 @@ static inline void crash(const char *message) {
8282
swift_unreachable("Expected compiler to crash.");
8383
}
8484

85-
// swift::fatalError() halts with a crash log message,
85+
// swift::fatalErrorv() halts with a crash log message,
86+
// but makes no attempt to preserve register state.
87+
SWIFT_RUNTIME_ATTRIBUTE_NORETURN
88+
SWIFT_VFORMAT(2)
89+
extern void fatalErrorv(uint32_t flags, const char *format, va_list args);
90+
91+
// swift::fatalError() halts with a crash log message,
8692
// but makes no attempt to preserve register state.
8793
SWIFT_RUNTIME_ATTRIBUTE_NORETURN
8894
SWIFT_FORMAT(2, 3)

lib/Demangling/CMakeLists.txt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
set(swift_demangling_compile_flags
2+
LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING=1
3+
SWIFT_SUPPORT_OLD_MANGLING=1
4+
SWIFT_STDLIB_HAS_TYPE_PRINTING=1)
5+
6+
if(SWIFT_RUNTIME_CRASH_REPORTER_CLIENT)
7+
list(APPEND swift_demangling_compile_flags
8+
"-DSWIFT_HAVE_CRASHREPORTERCLIENT=1")
9+
endif()
10+
111
add_swift_host_library(swiftDemangling STATIC
212
Demangler.cpp
313
Context.cpp
@@ -7,11 +17,10 @@ add_swift_host_library(swiftDemangling STATIC
717
OldDemangler.cpp
818
OldRemangler.cpp
919
Punycode.cpp
10-
Remangler.cpp)
20+
Remangler.cpp
21+
Errors.cpp)
1122
target_compile_definitions(swiftDemangling PRIVATE
12-
LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING=1
13-
SWIFT_SUPPORT_OLD_MANGLING=1
14-
SWIFT_STDLIB_HAS_TYPE_PRINTING=1)
23+
${swift_demangling_compile_flags})
1524

1625
# NOTE: Runtime libraries that depend on swiftDemangling should define
1726
# SWIFT_INLINE_NAMESPACE to specify the identifier that will be used for an

lib/Demangling/Demangler.cpp

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,10 @@ void swift::Demangle::failAssert(const char *file, unsigned line,
9595
NodePointer node, const char *expr) {
9696
std::string treeStr = getNodeTreeAsString(node);
9797

98-
fprintf(stderr,
99-
"%s:%u: assertion failed for Node %p: %s\n"
100-
"%s:%u: Node %p is:\n%s\n",
101-
file, line, node, expr,
102-
file, line, node, treeStr.c_str());
103-
abort();
98+
fatal(0,
99+
"%s:%u: assertion failed for Node %p: %s\n"
100+
"%s:%u: Node %p is:\n%s\n",
101+
file, line, node, expr, file, line, node, treeStr.c_str());
104102
}
105103

106104
bool swift::Demangle::isContext(Node::Kind kind) {
@@ -751,7 +749,7 @@ NodePointer Demangler::demangleSymbolicReference(unsigned char rawKind) {
751749
NodePointer resolved = nullptr;
752750
if (SymbolicReferenceResolver)
753751
resolved = SymbolicReferenceResolver(kind, direct, value, at);
754-
752+
755753
// With no resolver, or a resolver that failed, refuse to demangle further.
756754
if (!resolved)
757755
return nullptr;

lib/Demangling/Errors.cpp

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
//===--- Errors.cpp - Demangling library error handling ---------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2022 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+
// This file is the public API of the demangler library.
14+
// Tools which use the demangler library (like lldb) must include this - and
15+
// only this - header file.
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#include "swift/Demangling/Errors.h"
20+
#include <inttypes.h>
21+
#include <stdarg.h>
22+
#include <stdio.h>
23+
#include <stdlib.h>
24+
#include <string.h>
25+
26+
#if defined(_WIN32)
27+
#include <io.h>
28+
#endif
29+
30+
#if SWIFT_STDLIB_HAS_ASL
31+
#include <asl.h>
32+
#elif defined(__ANDROID__)
33+
#include <android/log.h>
34+
#endif
35+
36+
#if SWIFT_DEMANGLE_USE_RUNTIME_ERRORS
37+
#include "swift/Runtime/Debug.h"
38+
#endif
39+
40+
#if !SWIFT_DEMANGLE_USE_RUNTIME_ERRORS
41+
42+
// -- Declarations -----------------------------------------------------------
43+
44+
static SWIFT_NORETURN void demangleFatal(uint32_t flags, const char *format,
45+
va_list val);
46+
static void demangleWarn(uint32_t flags, const char *format, va_list val);
47+
48+
// -- Crash reporter integration ---------------------------------------------
49+
50+
#if SWIFT_HAVE_CRASHREPORTERCLIENT
51+
#include <malloc/malloc.h>
52+
#include <pthread.h>
53+
54+
// Instead of linking to CrashReporterClient.a (because it complicates the
55+
// build system), define the only symbol from that static archive ourselves.
56+
//
57+
// The layout of this struct is CrashReporter ABI, so there are no ABI concerns
58+
// here.
59+
extern "C" {
60+
SWIFT_LIBRARY_VISIBILITY
61+
struct crashreporter_annotations_t gCRAnnotations __attribute__((
62+
__section__("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {
63+
CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0, 0};
64+
}
65+
66+
// Report a message to any forthcoming crash log.
67+
static void reportOnCrash(uint32_t flags, const char *message) {
68+
// We must use an "unsafe" mutex in this pathway since the normal "safe"
69+
// mutex calls fatal when an error is detected and fatal ends up
70+
// calling us. In other words we could get infinite recursion if the
71+
// mutex errors.
72+
static pthread_mutex_t crashlogLock = PTHREAD_MUTEX_INITIALIZER;
73+
74+
pthread_mutex_lock(&crashlogLock);
75+
76+
char *oldMessage = (char *)CRGetCrashLogMessage();
77+
char *newMessage;
78+
if (oldMessage) {
79+
swift_asprintf(&newMessage, "%s%s", oldMessage, message);
80+
if (malloc_size(oldMessage))
81+
free(oldMessage);
82+
} else {
83+
newMessage = strdup(message);
84+
}
85+
86+
CRSetCrashLogMessage(newMessage);
87+
88+
pthread_mutex_unlock(&crashlogLock);
89+
}
90+
91+
#else
92+
static void
93+
94+
reportOnCrash(uint32_t flags, const char *message) {
95+
// empty
96+
}
97+
98+
#endif // SWIFT_HAVE_CRASHREPORTERCLIENT
99+
100+
// -- Utility functions ------------------------------------------------------
101+
102+
// Report a message to system console and stderr.
103+
static void reportNow(uint32_t flags, const char *message) {
104+
#if defined(_WIN32)
105+
#define STDERR_FILENO 2
106+
_write(STDERR_FILENO, message, strlen(message));
107+
#else
108+
fputs(message, stderr);
109+
fflush(stderr);
110+
#endif
111+
#if SWIFT_STDLIB_HAS_ASL
112+
asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", message);
113+
#elif defined(__ANDROID__)
114+
__android_log_print(ANDROID_LOG_FATAL, "SwiftDemangle", "%s", message);
115+
#endif
116+
}
117+
118+
/// Report a fatal error to system console, stderr, and crash logs.
119+
/// Does not crash by itself.
120+
static void reportError(uint32_t flags, const char *message) {
121+
reportNow(flags, message);
122+
reportOnCrash(flags, message);
123+
}
124+
125+
/// Not everything has vasprintf()
126+
SWIFT_VFORMAT(2)
127+
static int demangle_vasprintf(char **strp, const char *format, va_list args) {
128+
va_list args_for_len;
129+
130+
va_copy(args_for_len, args);
131+
int len = vsnprintf(nullptr, 0, format, args_for_len);
132+
va_end(args_for_len);
133+
134+
*strp = nullptr;
135+
136+
if (len < 0)
137+
return -1;
138+
139+
size_t bufsiz = len + 1;
140+
char *buffer = reinterpret_cast<char *>(malloc(bufsiz));
141+
if (!buffer)
142+
return -1;
143+
144+
int result = vsnprintf(buffer, bufsiz, format, args);
145+
if (result < 0) {
146+
free(buffer);
147+
return -1;
148+
}
149+
150+
*strp = buffer;
151+
return result;
152+
}
153+
154+
// -- Implementation ---------------------------------------------------------
155+
156+
static SWIFT_NORETURN void demangleFatal(uint32_t flags, const char *format,
157+
va_list val) {
158+
char *message;
159+
160+
if (demangle_vasprintf(&message, format, val) < 0) {
161+
reportError(flags, "unable to format fatal error message");
162+
abort();
163+
}
164+
165+
reportError(flags, message);
166+
abort();
167+
}
168+
169+
static void demangleWarn(uint32_t flags, const char *format, va_list val) {
170+
char *message;
171+
172+
if (demangle_vasprintf(&message, format, val) < 0) {
173+
reportNow(flags, "unable to format warning message");
174+
return;
175+
}
176+
177+
reportNow(flags, message);
178+
free(message);
179+
}
180+
181+
#endif // !SWIFT_DEMANGLE_USE_RUNTIME_ERRORS
182+
183+
// -- Public API -------------------------------------------------------------
184+
185+
namespace swift {
186+
namespace Demangle {
187+
SWIFT_BEGIN_INLINE_NAMESPACE
188+
189+
SWIFT_NORETURN void fatal(uint32_t flags, const char *format, ...) {
190+
va_list val;
191+
192+
va_start(val, format);
193+
fatalv(flags, format, val);
194+
}
195+
196+
void warn(uint32_t flags, const char *format, ...) {
197+
va_list val;
198+
199+
va_start(val, format);
200+
warnv(flags, format, val);
201+
va_end(val);
202+
}
203+
204+
SWIFT_NORETURN void fatalv(uint32_t flags, const char *format, va_list val) {
205+
#if SWIFT_DEMANGLE_USE_RUNTIME_ERRORS
206+
swift::fatalErrorv(flags, format, val);
207+
#else
208+
demangleFatal(flags, format, val);
209+
#endif
210+
}
211+
212+
void warnv(uint32_t flags, const char *format, va_list val) {
213+
#if SWIFT_DEMANGLE_USE_RUNTIME_ERRORS
214+
swift::warningv(flags, format, val);
215+
#else
216+
demangleWarn(flags, format, val);
217+
#endif
218+
}
219+
220+
SWIFT_END_INLINE_NAMESPACE
221+
} // end namespace Demangle
222+
} // end namespace swift

0 commit comments

Comments
 (0)