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

Reply via email to