Skip to content

Commit 4ba7e41

Browse files
committed
[runtime] Fortify the swift_demangle API.
Remove the reference to String, which leaks internal implementation details, check for invalid inputs, and make the API more flexible. Remove the similar Swift API, since it provides no additional value.
1 parent 7dc6855 commit 4ba7e41

File tree

3 files changed

+83
-29
lines changed

3 files changed

+83
-29
lines changed

stdlib/public/core/Misc.swift

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -121,30 +121,6 @@ func _typeByName(_ name: String) -> Any.Type? {
121121
return type
122122
}
123123
}
124-
125-
@warn_unused_result
126-
@_silgen_name("swift_stdlib_demangleName")
127-
func _stdlib_demangleNameImpl(
128-
_ mangledName: UnsafePointer<UInt8>,
129-
_ mangledNameLength: UInt,
130-
_ demangledName: UnsafeMutablePointer<String>)
131-
132-
// NB: This function is not used directly in the Swift codebase, but is
133-
// exported for Xcode support. Please coordinate before changing.
134-
@warn_unused_result
135-
public // @testable
136-
func _stdlib_demangleName(_ mangledName: String) -> String {
137-
let mangledNameUTF8 = Array(mangledName.utf8)
138-
return mangledNameUTF8.withUnsafeBufferPointer {
139-
(mangledNameUTF8) in
140-
let (_, demangledName) = _withUninitializedString {
141-
_stdlib_demangleNameImpl(
142-
mangledNameUTF8.baseAddress!, UInt(mangledNameUTF8.endIndex),
143-
$0)
144-
}
145-
return demangledName
146-
}
147-
}
148124

149125
/// Returns `floor(log(x))`. This equals to the position of the most
150126
/// significant non-zero bit, or 63 - number-of-zeros before it.

stdlib/public/runtime/Reflection.mm

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,16 +1190,63 @@ static Mirror ObjC_getMirrorForSuperclass(Class sup,
11901190
}
11911191

11921192
// NB: This function is not used directly in the Swift codebase, but is
1193-
// exported for Xcode support. Please coordinate before changing.
1193+
// exported for Xcode support and is used by the sanitizers. Please coordinate
1194+
// before changing.
1195+
//
1196+
/// Demangles a Swift symbol name.
1197+
///
1198+
/// \param mangledName is the symbol name that needs to be demangled.
1199+
/// \param mangledNameLength is the length of the string that should be
1200+
/// demangled.
1201+
/// \param outputBuffer is the user provided buffer where the demangled name
1202+
/// will be placed. If nullptr, a new buffer will be malloced. In that case,
1203+
/// the user of this API is responsible for freeing the returned buffer.
1204+
/// \param outputBufferSize is the size of the output buffer. If the demangled
1205+
/// name does not fit into the outputBuffer, the output will be truncated and
1206+
/// the size will be updated, indicating how large the buffer should be.
1207+
/// \param flags can be used to select the demangling style. TODO: We should
1208+
//// define what these will be.
1209+
/// \returns the demangled name. Returns nullptr if the input String is not a
1210+
/// Swift mangled name.
11941211
SWIFT_RUNTIME_EXPORT
1195-
extern "C" void swift_stdlib_demangleName(const char *mangledName,
1196-
size_t mangledNameLength,
1197-
String *demangledName) {
1212+
extern "C" char *swift_demangle(const char *mangledName,
1213+
size_t mangledNameLength,
1214+
char *outputBuffer,
1215+
size_t *outputBufferSize,
1216+
uint32_t flags) {
1217+
if (flags != 0) {
1218+
swift::fatalError(0, "Only 'flags' value of '0' is currently supported.");
1219+
}
1220+
if (outputBuffer != nullptr && outputBufferSize == nullptr) {
1221+
swift::fatalError(0, "'outputBuffer' is passed but the size is 'nullptr'.");
1222+
}
1223+
1224+
// Check if we are dealing with Swift mangled name, otherwise, don't try
1225+
// to demangle and send indication to the user.
1226+
if (mangledName[0] != '_' || mangledName[1] != 'T') {
1227+
return nullptr;
1228+
}
1229+
1230+
// Demangle the name.
11981231
auto options = Demangle::DemangleOptions();
11991232
options.DisplayDebuggerGeneratedModule = false;
12001233
auto result =
12011234
Demangle::demangleSymbolAsString(mangledName,
12021235
mangledNameLength,
12031236
options);
1204-
new (demangledName) String(result.data(), result.size());
1237+
1238+
// If the output buffer is not provided, malloc memory ourselves.
1239+
if (outputBuffer == nullptr || *outputBufferSize == 0) {
1240+
return strdup(result.c_str());
1241+
}
1242+
1243+
// Indicate a failure if the result does not fit and will be truncated
1244+
// and set the required outputBufferSize.
1245+
if (*outputBufferSize < result.length() + 1) {
1246+
*outputBufferSize = result.length() + 1;
1247+
}
1248+
1249+
// Copy into the provided buffer.
1250+
strlcpy(outputBuffer, result.c_str(), *outputBufferSize);
1251+
return outputBuffer;
12051252
}

test/1_stdlib/Runtime.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,37 @@ import StdlibUnittest
99
import SwiftShims
1010

1111

12+
@warn_unused_result
13+
@_silgen_name("swift_demangle")
14+
public
15+
func _stdlib_demangleImpl(
16+
mangledName: UnsafePointer<UInt8>?,
17+
mangledNameLength: UInt,
18+
outputBuffer: UnsafeMutablePointer<UInt8>?,
19+
outputBufferSize: UnsafeMutablePointer<UInt>?,
20+
flags: UInt32
21+
) -> UnsafeMutablePointer<CChar>?
22+
23+
@warn_unused_result
24+
func _stdlib_demangleName(_ mangledName: String) -> String {
25+
return mangledName.nulTerminatedUTF8.withUnsafeBufferPointer {
26+
(mangledNameUTF8) in
27+
28+
let demangledNamePtr = _stdlib_demangleImpl(
29+
mangledName: mangledNameUTF8.baseAddress,
30+
mangledNameLength: UInt(mangledNameUTF8.count - 1),
31+
outputBuffer: nil,
32+
outputBufferSize: nil,
33+
flags: 0)
34+
35+
if let demangledNamePtr = demangledNamePtr {
36+
let demangledName = String(cString: demangledNamePtr)
37+
_swift_stdlib_free(demangledNamePtr)
38+
return demangledName
39+
}
40+
return mangledName
41+
}
42+
}
1243

1344
var swiftObjectCanaryCount = 0
1445
class SwiftObjectCanary {

0 commit comments

Comments
 (0)