Issue |
122840
|
Summary |
Clang incorrectly adds tailcalls after `setjmp(...)` with `-fno-builtin`
|
Labels |
clang:codegen
|
Assignees |
|
Reporter |
alanzhao1
|
Originally reported by Chromium at https://g-issues.chromium.org/issues/380508212
Example:
```c
#include <setjmp.h>
struct JpegCommon {
jmp_buf jmpbuf;
int cinfo;
};
int jpeg_start_decompress(int *);
int jpeg_common_start_decompress(struct JpegCommon* jpeg_common) {
if (setjmp(jpeg_common->jmpbuf) == -1) {
return 0;
}
return jpeg_start_decompress(&jpeg_common->cinfo);
}
```
If this file is compiled with `-fno-builtin`, then Clang will optimize the call to `jpeg_start_decompress(...)` as a tailcall:
```asm
jpeg_common_start_decompress:
push rbx
mov rbx, rdi
call _setjmp@PLT
cmp eax, -1
je .LBB0_1
add rbx, 200
mov rdi, rbx
pop rbx
jmp jpeg_start_decompress@PLT
.LBB0_1:
xor eax, eax
pop rbx
ret
```
This is incorrect. Control flow may resume at `setjmp(...)` from another function. Because of this, the contents of the execution stack must be preserved. The tail call optimization shown above is incorrect because `jpeg_start_decompress(...)` may mess up the stack for when we later enter `jpeg_common_start_decompress(...)` at `setjmp(...)` via a `longjmp(..)` call.
This incorrect codegen only occurs with `-fno-builtin` - if we don't pass `-fno-builtin`, Clang correctly emits a call instruction (thereby preserving the stack).
godbolt: https://godbolt.org/z/1anGj6e3s
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs