Frame pointer omission does make debugging significantly harder. Local variables are harder to locate and stack traces are much harder to reconstruct without a frame pointer to help out. Also, accessing parameters can get more expensive since they are far away from the top of the stack and may require more expensive addressing modes.
The -fno-omit-frame-pointer
option direct the compiler to generate code that maintains and uses stack frame pointer for all functions so that a debugger can still produce a stack backtrace even with optimizations flags.
Irrespective if you use the flag, not every function needs a frame pointer in the first place, so you can't always expect a difference with the flag.
Also, whether the function has a frame pointer is an implementation detail. Compilers can differ in implementation details (and usually they do).
Intel(R) Xeon(R) CPU E5-2628L v3
UseAfterFree.cpp
int main(int argc, char **argv) {
int *array = new int[100];
delete [] array;
return array[argc]; // BOOM
}
$ clang --version
Ubuntu clang version 12.0.0-++20200928064922+37ef2255b64-1~exp1~20200928165602.178
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ diff -c <(clang -S UseAfterFree.cpp -Os -fno-omit-frame-pointer -o -) <(clang -S UseAfterFree.cpp -Os -o -)
***************
*** 7,31 ****
# %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
- .cfi_offset %rbp, -16
- movq %rsp, %rbp
- .cfi_def_cfa_register %rbp
- pushq %r14
pushq %rbx
! .cfi_offset %rbx, -32
! .cfi_offset %r14, -24
! movl %edi, %r14d
movl $400, %edi # imm = 0x190
callq _Znam
movq %rax, %rbx
movq %rax, %rdi
callq _ZdaPv
! movslq %r14d, %rax
movl (%rbx,%rax,4), %eax
popq %rbx
! popq %r14
popq %rbp
! .cfi_def_cfa %rsp, 8
retq
.Lfunc_end0:
.size main, .Lfunc_end0-main
--- 7,32 ----
# %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
pushq %rbx
! .cfi_def_cfa_offset 24
! pushq %rax
! .cfi_def_cfa_offset 32
! .cfi_offset %rbx, -24
! .cfi_offset %rbp, -16
! movl %edi, %ebp
movl $400, %edi # imm = 0x190
callq _Znam
movq %rax, %rbx
movq %rax, %rdi
callq _ZdaPv
! movslq %ebp, %rax
movl (%rbx,%rax,4), %eax
+ addq $8, %rsp
+ .cfi_def_cfa_offset 24
popq %rbx
! .cfi_def_cfa_offset 16
popq %rbp
! .cfi_def_cfa_offset 8
retq
.Lfunc_end0:
.size main, .Lfunc_end0-main
$ clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer UseAfterFree.cpp
$ ./a.out
=================================================================
==1374==ERROR: AddressSanitizer: heap-use-after-free on address 0x614000000044 at pc 0x0000004c990f bp 0x7ffd3adc4a70 sp 0x7ffd3adc4a68
READ of size 4 at 0x614000000044 thread T0
#0 0x4c990e in main /tmp/UseAfterFree.cpp:4:10
#1 0x7f4fd4eb00b2 in __libc_start_main /build/glibc-YYA7BZ/glibc-2.31/csu/../csu/libc-start.c:308:16
#2 0x41c2ad in _start (/tmp/a.out+0x41c2ad)
0x614000000044 is located 4 bytes inside of 400-byte region [0x614000000040,0x6140000001d0)
freed by thread T0 here:
#0 0x4c791d in operator delete[](void*) (/tmp/a.out+0x4c791d)
#1 0x4c98de in main /tmp/UseAfterFree.cpp:3:3
#2 0x7f4fd4eb00b2 in __libc_start_main /build/glibc-YYA7BZ/glibc-2.31/csu/../csu/libc-start.c:308:16
previously allocated by thread T0 here:
#0 0x4c70cd in operator new[](unsigned long) (/mnt/c/work/dpcode/c/frame-poiner/a.out+0x4c70cd)
#1 0x4c98d3 in main /tmp/UseAfterFree.cpp:2:16
#2 0x7f4fd4eb00b2 in __libc_start_main /build/glibc-YYA7BZ/glibc-2.31/csu/../csu/libc-start.c:308:16
SUMMARY: AddressSanitizer: heap-use-after-free /tmp/UseAfterFree.cpp:4:10 in main
Shadow bytes around the buggy address:
0x0c287fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c287fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c287fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c287fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c287fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c287fff8000: fa fa fa fa fa fa fa fa[fd]fd fd fd fd fd fd fd
0x0c287fff8010: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c287fff8020: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c287fff8030: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa
0x0c287fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c287fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==1374==ABORTING
$ gcc --version
gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ diff -c <(gcc -S UseAfterFree.cpp -Os -fno-omit-frame-pointer -o -) <(gcc -S UseAfterFree.cpp -Os -o -)
***************
*** 10,32 ****
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
- movq %rsp, %rbp
- .cfi_def_cfa_register 6
- pushq %r12
pushq %rbx
! .cfi_offset 12, -24
! .cfi_offset 3, -32
movslq %edi, %rbx
movl $400, %edi
call _Znam@PLT
! movq %rax, %r12
movq %rax, %rdi
call _ZdaPv@PLT
! movl (%r12,%rbx,4), %eax
popq %rbx
! popq %r12
popq %rbp
! .cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
--- 10,33 ----
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
pushq %rbx
! .cfi_def_cfa_offset 24
! .cfi_offset 3, -24
movslq %edi, %rbx
movl $400, %edi
+ pushq %rax
+ .cfi_def_cfa_offset 32
call _Znam@PLT
! movq %rax, %rbp
movq %rax, %rdi
call _ZdaPv@PLT
! movl 0(%rbp,%rbx,4), %eax
! popq %rdx
! .cfi_def_cfa_offset 24
popq %rbx
! .cfi_def_cfa_offset 16
popq %rbp
! .cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE0:
$ g++ -O1 -g -fsanitize=address -fno-omit-frame-pointer UseAfterFree.cpp
$ ./a.out
=================================================================
==1409==ERROR: AddressSanitizer: heap-use-after-free on address 0x614000000044 at pc 0x564c3b87921d bp 0x7fff1fef2490 sp 0x7fff1fef2480
READ of size 4 at 0x614000000044 thread T0
#0 0x564c3b87921c in main /tmp/UseAfterFree.cpp:4
#1 0x7f7c8b8840b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
#2 0x564c3b87910d in _start (/tmp/a.out+0x110d)
0x614000000044 is located 4 bytes inside of 400-byte region [0x614000000040,0x6140000001d0)
freed by thread T0 here:
#0 0x7f7c8bb5faaf in operator delete[](void*) (/lib/x86_64-linux-gnu/libasan.so.5+0x110aaf)
#1 0x564c3b8791ea in main /tmp/UseAfterFree.cpp:3
#2 0x7f7c8b8840b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
previously allocated by thread T0 here:
#0 0x7f7c8bb5eb47 in operator new[](unsigned long) (/lib/x86_64-linux-gnu/libasan.so.5+0x10fb47)
#1 0x564c3b8791df in main /tmp/UseAfterFree.cpp:2
#2 0x7f7c8b8840b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
SUMMARY: AddressSanitizer: heap-use-after-free /tmp/UseAfterFree.cpp:4 in main
Shadow bytes around the buggy address:
0x0c287fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c287fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c287fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c287fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c287fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c287fff8000: fa fa fa fa fa fa fa fa[fd]fd fd fd fd fd fd fd
0x0c287fff8010: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c287fff8020: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c287fff8030: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa
0x0c287fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c287fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==1409==ABORTING