https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119188
Bug ID: 119188 Summary: Incorrect -fcallgraph-info=su for leaf functions on x86-64 Product: gcc Version: 14.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: lukeshu at lukeshu dot com Target Milestone: --- With the given simple strnlen function, I'm seeing -fcallgraph-info report that the function uses 16 bytes of stack space, but by my count the disassembly shows it using 8+32=40 bytes. $ gcc --version gcc (GCC) 14.2.1 20250207 Copyright (C) 2024 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. $ cat f.c unsigned int _strnlen_s(const char *str, unsigned long long maxsize) { const char *s; for (s = str; *s && maxsize--; ++s); return (unsigned int) (s - str); } $ gcc -fcallgraph-info=su -c f.c $ cat f.ci graph: { title: "f.c" node: { title: "_strnlen_s" label: "_strnlen_s\nf.c:1:14\n16 bytes (static)" } } $ objdump --disassemble f.o f.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <_strnlen_s>: 0: 55 push %rbp # 8 bytes 1: 48 89 e5 mov %rsp,%rbp 4: 48 89 7d e8 mov %rdi,-0x18(%rbp) 8: 48 89 75 e0 mov %rsi,-0x20(%rbp) # clearly using another 32 bytes c: 48 8b 45 e8 mov -0x18(%rbp),%rax 10: 48 89 45 f8 mov %rax,-0x8(%rbp) 14: eb 05 jmp 1b <_strnlen_s+0x1b> 16: 48 83 45 f8 01 addq $0x1,-0x8(%rbp) 1b: 48 8b 45 f8 mov -0x8(%rbp),%rax 1f: 0f b6 00 movzbl (%rax),%eax 22: 84 c0 test %al,%al 24: 74 11 je 37 <_strnlen_s+0x37> 26: 48 8b 45 e0 mov -0x20(%rbp),%rax 2a: 48 8d 50 ff lea -0x1(%rax),%rdx 2e: 48 89 55 e0 mov %rdx,-0x20(%rbp) 32: 48 85 c0 test %rax,%rax 35: 75 df jne 16 <_strnlen_s+0x16> 37: 48 8b 45 f8 mov -0x8(%rbp),%rax 3b: 48 2b 45 e8 sub -0x18(%rbp),%rax 3f: 5d pop %rbp 40: c3 ret If I insert a "dummy" function call to force it to update %rsp before the call, I get the correct count (now 48 bytes, because of the extra 8 from `call`): void x(void); unsigned int _strnlen_s(const char *str, unsigned long long maxsize) { const char *s; for (s = str; *s && maxsize--; ++s); x(); return (unsigned int) (s - str); }