# EH3 split epilog does not match valid stack restores

**URL:** <https://community.hex-rays.com/t/eh3-split-epilog-does-not-match-valid-stack-restores/811>\
**Category:** IDA General\
**Created:** [September 27, 2026, 8:22pm UTC](https://community.hex-rays.com/t/eh3-split-epilog-does-not-match-valid-stack-restores/811 "2026-09-27T20:22:58Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![QuietMaple10](https://avatars.discourse-cdn.com/v4/letter/q/50afbb/32.png) [@QuietMaple10](https://community.hex-rays.com/u/QuietMaple10)\
**Post date:** [September 27, 2026, 8:22pm UTC](https://community.hex-rays.com/t/eh3-split-epilog-does-not-match-valid-stack-restores/811/1 "2026-09-27T20:22:58Z")

</div>

In the example below `epilog_repro` using displacement free `[rsp]` (`o_phrase`) warns:

```auto
[WARN] flowchart(140001000): EH3[140001000]: get_epilog_split_eas(14000101E): Bad instruction for SAVE_NONVOL

```

While `epilog_control` with an explicitly encoded `[rsp+disp8=0]` (`o_displ`) does not.

```x86asm
; ml64 /nologo /c /Foeh3_repro.obj eh3_repro.asm
; lld-link /nodefaultlib /entry:epilog_repro /subsystem:console /export:epilog_repro /export:epilog_control /out:eh3_repro.exe eh3_repro.obj vcruntime.lib

option casemap:none
option prologue:none
option epilogue:none

extern __CxxFrameHandler3:proc

.code

public epilog_repro
public epilog_control

epilog_repro proc
    push r13
    sub rsp, 20h
    vmovaps xmmword ptr [rsp], xmm6

epilog_repro_body::
    test cl, 1
    jz short result_path_0

result_path_1:
    mov r13, rcx
    jmp short epilog_restore

result_path_0:
    lea r13, [rcx]
    jmp short epilog_restore

epilog_restore:
    mov rax, r13
    nop
    movaps xmm6, xmmword ptr [rsp] ; 0F 28 34 24, source is o_phrase
    add rsp, 20h
    pop r13
    ret
epilog_repro_end::
epilog_repro endp

ALIGN 16
epilog_control proc
    push r13
    sub rsp, 20h
    vmovaps xmmword ptr [rsp], xmm6

epilog_control_body::
    test cl, 1
    jz short control_path_0

control_path_1:
    mov r13, rcx
    jmp short control_restore

control_path_0:
    lea r13, [rcx]
    jmp short control_restore

control_restore:
    mov rax, r13
    db 0Fh, 28h, 74h, 24h, 00h ; movaps xmm6, [rsp+disp8=0], source is o_displ
    add rsp, 20h
    pop r13
    ret
epilog_control_end::
epilog_control endp

epilog_repro_cleanup proc
    ret
epilog_repro_cleanup endp

_xdata SEGMENT READONLY ALIAS(".xdata")
ALIGN 4

epilog_repro_unwind label byte
    ; Version=1, Flags=EHANDLER|UHANDLER, Prolog=0Bh, 4 unwind code slots
    db 19h, 0Bh, 4, 0
    db 0Bh, 68h ; UWOP_SAVE_XMM128 xmm6, [rsp]
    dw 0
    db 06h, 32h ; UWOP_ALLOC_SMALL 20h
    db 02h, 0D0h ; UWOP_PUSH_NONVOL r13

ALIGN 4
    dd imagerel __CxxFrameHandler3
    dd imagerel epilog_repro_funcinfo

; One cleanup, no catches
epilog_repro_funcinfo label dword
    dd 19930522h
    dd 1
    dd imagerel epilog_repro_unwind_map
    dd 0
    dd 0
    dd 2
    dd imagerel epilog_repro_ip_to_state
    dd 0
    dd 0
    dd 1

epilog_repro_unwind_map label dword
    dd -1
    dd imagerel epilog_repro_cleanup

epilog_repro_ip_to_state label dword
    dd imagerel epilog_repro
    dd -1
    dd imagerel epilog_repro_body
    dd 0

ALIGN 4
epilog_control_unwind label byte
    ; Identical prolog description, only a different FuncInfo RVA
    db 19h, 0Bh, 4, 0
    db 0Bh, 68h ; UWOP_SAVE_XMM128 xmm6, [rsp]
    dw 0
    db 06h, 32h ; UWOP_ALLOC_SMALL 20h
    db 02h, 0D0h ; UWOP_PUSH_NONVOL r13

ALIGN 4
    dd imagerel __CxxFrameHandler3
    dd imagerel epilog_control_funcinfo

epilog_control_funcinfo label dword
    dd 19930522h
    dd 1
    dd imagerel epilog_repro_unwind_map
    dd 0
    dd 0
    dd 2
    dd imagerel epilog_control_ip_to_state
    dd 0
    dd 0
    dd 1

epilog_control_ip_to_state label dword
    dd imagerel epilog_control
    dd -1
    dd imagerel epilog_control_body
    dd 0

_xdata ENDS

_pdata SEGMENT READONLY ALIAS(".pdata")
ALIGN 4
    dd imagerel epilog_repro
    dd imagerel epilog_repro_end
    dd imagerel epilog_repro_unwind
    dd imagerel epilog_control
    dd imagerel epilog_control_end
    dd imagerel epilog_control_unwind
_pdata ENDS

end

```

Both restore the same register from the same stack address. The functions have matching unwind operations and EH3 metadata, the return value move precedes the restore in both.

Discovered this in a production Rust binary.

---

<div class="post-metadata">

**Author:** ![ilfak](https://sea2.discourse-cdn.com/flex002/user_avatar/community.hex-rays.com/ilfak/32/49_2.png) [@ilfak](https://community.hex-rays.com/u/ilfak)\
**Post date:** [September 28, 2026, 4:54pm UTC](https://community.hex-rays.com/t/eh3-split-epilog-does-not-match-valid-stack-restores/811/2 "2026-09-28T16:54:18Z")

</div>

Thank you for the detailed report! I confirm the problem, we will fix it.
