Demangle Function

The UnsafeMutableBufferPointer API is fundamentally flaw. You can't distinguish between invalid string, and buffer to small, unless you decide to return 0 for invalid string, nil for success, and anything else for buffer too small, which is very unintuitive and error prone.

All failable API that return an optional reserve nil to indicate failure.

I'm not even sure we need a buffer variant. A demangled symbol is an Unicode String. And knowing how hard it is to properly handle unicode string, I can't see any useful usage for this buffer but to create a String from it.

Do you have any use case in mind for the buffer API ?

1 Like

See https://forums.swift.org/t/crash-backtraces/25021/15: a crash handler might want to use a preallocated buffer since allocating memory after a crash can be unsafe.

5 Likes

I brought this up in my first reply, and this is the response I got.

In such case, you need to precise if there is any guarantee that the truncated version will be valid text, or if it may end in the middle of a grapheme cluster.

Thanks, I've updated the proposal. In the case of where swift_demangle will truncate, there is no guarantee that some of the resulting symbol will be readable. E.g.

// -module-name Test
// This requires 22 bytes to fully demangle
// Mangled name: $s4Test004tCIhSivp
// Demangled name: Test.😏 : Swift.Int
let 😏 = 16

// Intentionally break the emoji sequence
let buffer = UnsafeMutableBufferPointer<Int8>.allocate(
  capacity: 7
)
// ...
demangle("$s4Test004tCIhSivp", into: buffer)
print(String(cString: buffer.baseAddress!)) // Test.�

Similar APIs in C like snprintf return what the full length of the output string would have been if it weren't truncated. It might be nice for the buffered version to do the same. Should it also take the input as an UnsafeBufferPointer<CChar>, or at least a SubString, so it can also be formed without allocating?

2 Likes

We should do at least that. Ideally we’d define a better return type here so that the truncation effect is clear in code, instead of relying users to read the documentation. Can we use an enumeration here instead, with cases like .truncated?

3 Likes

Yeah I was thinking about something of the same vein as well. Just a rough sketch:

enum DemangleResult {
  case .success
  case .truncated(Int)
  case .invalidSymbol
}
4 Likes

I like the result type, makes it a lot easier to understand what's going on. In general a very nice proposal. I have also been looking into backtraces etc. for a while now and am collaborating with @IanPartridge on that, so if there's anything I can help with, let me know.

When does this happen? If dealing with backtraces is the primary concern here, could the backtrace tools incorporate a way to get the demangled name?

I think the way they’d get the mangled name is via the API proposed here.

This is certainly a somewhat niche feature, but there are other uses that I see like reading Swift metadata which contains mangled symbols.

Interpreting mangled type refs in Swift metadata would require a lower-level interface that exposes the AST of the mangling, like that used by the MetadataReader template in the runtime. This function should be used to turn symbol names into human-readable text for logging purposes, but its output probably shouldn't be considered parsable for further computation.

2 Likes

This is still useful when you want to print details about a Swift executable however.

Not really. Runtime mangled strings are allowed to contain embedded pointers that would be insecure for a symbol demangler like this to blindly dereference. This demangle interface will refuse to demangle them.

4 Likes

I think this is also a good idea. Would it make sense to provide both, or just the buffer input variant and callers with substrings can dig out the cstring buffer pointer?

1 Like

Update: I've made a PR to swift-evolution here: Add demangle function by Azoy · Pull Request #1061 · apple/swift-evolution · GitHub
I've updated the proposal to include the DemangleResult, a variant that takes a symbol from a buffer, and the trivial variant now returns an optional string. Please let me know what you think!

1 Like

For "alternatives considered", is libswiftDemangle available in the toolchains of all supported platforms?

The demangler is compiled into the runtime, separately from libswiftDemangle.

My apologises for entering a discussion without proper background
But is there currently a way to use:
SwiftDemangle.h or swift-demangle.cpp at run time? I guess if its in tools so probably not.
Is there an official way to have demangle api? or what would be a current work around for to get it?
according to 0262-demangle proposal

one could create a new Process from Foundation and set it up to launch a new process within the process to use swift-demangle

not sure if I want to go that way (and not so sure how to achieve it)