Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Panic: unwind vs abort

When a Rust program panics, it can handle the failure in two ways: unwind or abort. Unwind mode cleans up resources as the panic travels up the call stack, while abort mode immediately terminates the program. The chosen mode affects the generated code.

Source

Initialize a new workspace with cargo init.

The source code of chapter Vec is reused here.

Build

$ cargo rustc --release

By default the option panic=unwind is used.

Ghidra

Load the binary into Ghidra and auto-analyze it.

rust_lab::main

While scrolling through the listing, we can see that Ghidra adds try-catch comments to the following parts, and we notice XREFs from addresses that are far away.

                             try { // try from 00401958 to 00401967 has its CatchHandler @
                             LAB_00401958                                    XREF[1]:     00453a88(*)  
        00401958 61 03 00 90     adrp       x1,0x46d000
                             arg1: source location for debugging
        0040195c 21 80 21 91     add        x1=>PTR_s_src/main.rs_0046d860,x1,#0x860         = 0044aea0
                             arg0: address of vec
        00401960 e0 23 00 91     add        x0,sp,#0x8
                             increase cap from 3 to 8
        00401964 fd 0d 01 94     bl         alloc::raw_vec::RawVec<T,A>::grow_one            undefined grow_one()
                             } // end try from 00401958 to 00401967
                             catch() { ... } // from try @ 00401958 with catch @ 004019ac
                             LAB_004019ac                                    XREF[1]:     00453a8a(*)  
        004019ac e1 07 40 f9     ldr        x1,[sp, #0x8]
        004019b0 f3 03 00 aa     mov        x19,x0
        004019b4 81 00 00 b4     cbz        x1,LAB_004019c4
        004019b8 e0 0b 40 f9     ldr        x0,[sp, #0x10]
        004019bc 22 00 80 52     mov        w2,#0x1
        004019c0 14 00 00 94     bl         __rustc::__rust_dealloc                          void __rust_dealloc(u8 * ptr, us
                             LAB_004019c4                                    XREF[1]:     004019b4(j)  
        004019c4 e0 03 13 aa     mov        x0,x19
        004019c8 30 c7 00 94     bl         _Unwind_Resume                                   undefined _Unwind_Resume()
                             -- Flow Override: CALL_RETURN (CALL_TERMINATOR)

If we follow the XREFs, we can see they are under the LSDA (Language-Specific Data Area) located in section .gcc_except_table.

                             //
                             // .gcc_except_table 
                             // SHT_PROGBITS  [0x453a84 - 0x454c67]
                             // ram:00453a84-ram:00454c67
                             //
                             **************************************************************
                             * Language-Specific Data Area                                *
                             **************************************************************
...
        00453a88 44              uleb128    LAB_00401958                                     (LSDA Call Site) IP Offset
        00453a89 10              uleb128    10h                                              (LSDA Call Site) IP Range Length
        00453a8a 98 01           uleb128    LAB_004019ac                                     (LSDA Call Site) Landing Pad Add
        00453a8c 00              uleb128    0h                                               (LSDA Call Site) Action Table Of
...

This means, if a panic occurs while the execution is between 0x00401958 and 0x00401958 + 0x10 = 0x00401968, during unwinding, the code located at 0x004019ac will be executed. In this case, if necessary (the vector capacity is not null) it deallocates the allocated block and continues the unwinding process.