LLDB Swift Casting Raw Address into Usable Type
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
When you have a raw memory address in an LLDB session and want to inspect it as a Swift value, the task is really about building the right pointer type and then dereferencing it safely. LLDB can evaluate Swift expressions, so you can cast the address to UnsafePointer or UnsafeMutablePointer of the type you expect and inspect the pointee. The difficult part is not the syntax. It is making sure the address is valid and the target type actually matches the bytes in memory.
Start with the Address and the Expected Type
A raw address by itself has no meaning beyond “some bytes live here.” To turn it into something useful, you must know what type is stored there.
For example, if you believe the address points to an Int, you can ask LLDB to evaluate a Swift expression:
That command does three things:
- converts the numeric address into a pointer-sized integer
- reinterprets it as
UnsafePointer<Int> - reads the value through
.pointee
If the address and type are both correct, LLDB prints the Int stored there.
Use UnsafeRawPointer for a Two-Step Cast
Sometimes it is clearer to cast through UnsafeRawPointer first and then bind memory to the concrete type you want. That makes the conversion easier to read in a debugging session.
This style is useful when you want to inspect the pointer in stages instead of writing everything in one line.
The same idea works for structs as long as the bytes at that address really are laid out as that struct.
Inspect Structs and Class Instances Carefully
If the address points to a Swift struct stored in memory, you can cast to the appropriate pointer type:
For class instances, be more careful. The address may refer to an object reference, object header, or bridged runtime representation rather than directly to the instance fields you expect. In practice, if you already have an object variable in scope, inspecting that variable directly is usually safer than reconstructing it from an address.
Read Memory Before You Cast
When you are not yet sure what lives at an address, use LLDB's memory tools first. That lets you inspect raw bytes without committing to a type interpretation too early.
This is especially useful when:
- alignment looks suspicious
- the address may be stale
- you are not sure whether the pointer is typed correctly
- the value may come from C interop or manually managed memory
Raw inspection helps you verify whether the bytes look plausible before you dereference them as a Swift type.
Prefer Existing Variables Over Raw Address Casting
If the program already has a symbol, variable, or pointer in scope, use that instead of reconstructing the value from a hard-coded address. For example, if ptr exists in the current frame, this is better:
Hard-coded addresses are fragile because they depend on the current process state, stack layout, and optimizer behavior. They are useful for emergency debugging, but they should not be your first tool when normal symbolic inspection is available.
Know the Limits of Swift Expression Evaluation
LLDB's Swift expression support is powerful but not perfect. Generic types, optimized builds, and some bridged runtime objects can make inspection harder than the same task in C.
If a Swift expression fails, you can sometimes simplify the problem by:
- casting to a simpler pointer type first
- using
memory readto inspect bytes directly - switching to a debug build with optimizations reduced
- inspecting nearby symbolic variables instead of only the raw address
This is often faster than forcing one complicated expression to work.
Common Pitfalls
The most common mistake is dereferencing an address without confirming that it is still valid. A stale pointer or stack address can crash the debugged process or print meaningless data.
Another mistake is assuming the target type from guesswork. If the bytes do not match the type, the cast may succeed syntactically but produce garbage.
Developers also forget alignment and object-layout details. Swift structs, bridged objects, and class instances are not all represented the same way in memory.
Summary
- In LLDB, cast a raw address by turning it into the correct Swift pointer type and reading
.pointee. - '
UnsafeRawPointerplusassumingMemoryBoundis often easier to read than a one-line cast.' - Use
memory readfirst when you are not certain what lives at the address. - Prefer inspecting existing variables and pointers over hard-coded addresses when possible.
- The cast syntax is easy; the hard part is making sure the address and the expected type are actually correct.

