It is by chance. You are invoking undefined behavior for dereferencing a pointer pointing at an object whose lifetime is ended.
When I entered your code to Compiler Explorer, I got this:
fun:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    $43, -12(%rbp)
        leaq    -12(%rbp), %rax
        movq    %rax, -8(%rbp)
        movq    -8(%rbp), %rax
        popq    %rbp
        ret
.LC0:
        .string "%d"
main:
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $16, %rsp
        movl    $0, %eax
        call    fun
        movq    %rax, -8(%rbp)
        movq    -8(%rbp), %rax
        movl    (%rax), %eax
        movl    %eax, %esi
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf
        movl    $0, %eax
        leave
        ret
In this illustration, let me assume that %rsp = 0x10000000 just before executing call fun.
call pushes the return address on the stack, so it will subtract 8 from the stack pointer. push also subtract 8 from the stack pointer. Therefore, when movl    $43, -12(%rbp) is executed, %rbp is 0x0ffffff0 and the layout on the stack is:
     -12(%rbp) -> 0x0fffffe4  43
                  0x0fffffe8  (the address to return will be written here)
                  0x0fffffec  (the address to return will be written here)
        (%rbp) -> 0x0ffffff0  old base pointer %rbp
                  0x0ffffff4  old base pointer %rbp
                  0x0ffffff8  address to return from fun
                  0x0ffffffc  address to return from fun
                  0x10000000
                  0x10000004
                  0x10000008  (returned address will be stored here in main())
                  0x1000000c  (returned address will be stored here in main())
%rbp in main() -> 0x10000010
After returning from fun(), there are no memory write that destroys the 43 written before reading the value by movl    (%rax), %eax. Therefore the value happened to be preserved.
Note again that you are invoking undefined behavior, so the result may differ.
For example, when -O2 optimization option is added, Compiler Explorer gave me this:
fun:
        xorl    %eax, %eax
        ret
.LC0:
        .string "%d"
main:
        subq    $8, %rsp
        xorl    %esi, %esi
        movl    $.LC0, %edi
        xorl    %eax, %eax
        call    printf
        xorl    %eax, %eax
        addq    $8, %rsp
        ret
Now the buggy function fun() is replaced with empty process and the result is changed.