https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107618
Bug ID: 107618
Summary: Incorrect diagnostics when using -Og,
builtin_expect(), and function attribute "warning" or
"error"
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: other
Assignee: unassigned at gcc dot gnu.org
Reporter: yann at droneaud dot fr
Target Milestone: ---
Created attachment 53872
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=53872&action=edit
reproducer for -Og, __builtin_expect(), and function
__attribute__((warning("")))
The code below compiled with -Og triggers a warning message that is not
mandated:
$ gcc -Og warning.c
warning.c: In function ‘test_expect’:
warning.c:26:17: warning: call to ‘size_mismatch_expect’ declared with
attribute warning: size mismatch (builtin_expect) [-Wattribute-warning]
26 | size_mismatch_expect();
| ^~~~~~~~~~~~~~~~~~~~~~
$ cat warning.c
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
extern void size_mismatch_nonexpect(void)
__attribute__((__warning__("size mismatch")));
static bool
test_nonexpect(const void *addr, size_t len)
{
size_t sz = __builtin_object_size(addr, 0);
if (sz != (size_t)-1 && sz < len) {
size_mismatch_nonexpect();
return false;
}
return true;
}
extern void size_mismatch_expect(void)
__attribute__((__warning__("size mismatch (builtin_expect)")));
static bool
test_expect(const void *addr, size_t len)
{
size_t sz = __builtin_object_size(addr, 0);
if (__builtin_expect(sz != (size_t)-1 && sz < len, 0)) {
size_mismatch_expect();
return false;
}
return true;
}
int main(void)
{
int i = 0;
if (!test_nonexpect(&i, sizeof(i)))
return EXIT_FAILURE;
if (!test_expect(&i, sizeof(i)))
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
The warning at -Og level is not expected because there's no call to the
size_mismatch_expect() in the generated assembler (for x86-64):
$ head warning.s
.file "warning.c"
.text
.type test_nonexpect, @function
test_nonexpect:
movl $1, %eax
ret
.size test_nonexpect, .-test_nonexpect
.type test_expect, @function
test_expect:
movl $1, %eax
ret
.size test_expect, .-test_expect
.globl main
.type main, @function
main:
endbr64
subq $24, %rsp
movq %fs:40, %rax
movq %rax, 8(%rsp)
xorl %eax, %eax
movl $0, 4(%rsp)
leaq 4(%rsp), %rdi
movl $4, %esi
call test_nonexpect
testb %al, %al
jne .L11
movl $1, %eax
.L5:
movq 8(%rsp), %rdx
subq %fs:40, %rdx
jne .L12
addq $24, %rsp
ret
.L11:
leaq 4(%rsp), %rdi
movl $4, %esi
call test_expect
testb %al, %al
je .L9
movl $0, %eax
jmp .L5
.L9:
movl $1, %eax
jmp .L5
See also https://godbolt.org/z/KEsaavhvG
Compiling at optimization level s, z, 1, 2, or 3 doesn't produce that warning.
(but compiling with -O0 does produces two warnings, as expected, since calls to
the two functions are emitted).
Having the warning at debug optimization level makes using -Og in some complex
code base challenging for no good reason when __attribute__((error(""))) is
used (or -Werror=attribute-warning).
It should also be noted clang doesn't generate the warning for optimization
level above 0.