This is an archive of the discontinued LLVM Phabricator instance.

Recognize setjmp and friends as builtins even if jmp_buf is not declared yet.
ClosedPublic

Authored by rsmith on Sep 29 2020, 3:21 PM.

Details

Summary

This happens in glibc's headers. It's important that we recognize these
functions so that we can mark them as returns_twice.

Diff Detail

Event Timeline

rsmith created this revision.Sep 29 2020, 3:21 PM
Herald added a project: Restricted Project. · View Herald TranscriptSep 29 2020, 3:21 PM
rsmith requested review of this revision.Sep 29 2020, 3:21 PM
rjmccall accepted this revision.Sep 29 2020, 3:45 PM

LGTM. I like this better as a fix for PR40692 anyway.

This revision is now accepted and ready to land.Sep 29 2020, 3:45 PM

This broke use of setjmp for mingw on x86_64. IIRC, in MSVC environments, the _setjmp function is considered built-in, which is given an implicit second argument by the compiler. In mingw targets on the other hand, the compiler normally doesn't know of any such extra mechanisms, and it's hooked up e.g. like this:

#define setjmp(BUF) _setjmp((BUF), __builtin_frame_address (0))
int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmp(jmp_buf _Buf, void *_Ctx);

After this commit, in C++, this errors out with "error: too many arguments to function call, expected 1, have 2", while in C it merely produces a warning "warning: incompatible redeclaration of library function '_setjmp'" (and that warning is produced by the SDK headers, where those warnings normally are silenced).

A full repro case here follows:

typedef __attribute__ ((__aligned__ (16))) struct _SETJMP_FLOAT128 {
  __extension__ unsigned long long Part[2];
} SETJMP_FLOAT128;
#define _JBLEN 16
typedef SETJMP_FLOAT128 _JBTYPE;
typedef _JBTYPE jmp_buf[_JBLEN];

#ifdef __cplusplus
extern "C" {
#endif

#define setjmp(BUF) _setjmp((BUF), __builtin_frame_address (0))
int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmp(jmp_buf _Buf, void *_Ctx);

#ifdef __cplusplus
}
#endif

void other(void);
jmp_buf buf;
int func(void) {
    if (setjmp(buf)) {
        return 1;
    }
    other();
    return 0;
}
$ clang++ -x c++ -target x86_64-w64-mingw32 -c setjmp.c
setjmp.c:29:9: error: too many arguments to function call, expected 1, have 2
    if (setjmp(buf)) {
        ^~~~~~~~~~~
setjmp.c:12:36: note: expanded from macro 'setjmp'
#define setjmp(BUF) _setjmp((BUF), __builtin_frame_address (0))
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~

(The exact functions that is used for setjmp in mingw configuration is a bit of a jungle, with different CRT setups on different architectures: https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-headers/crt/setjmp.h#L213-L243)

rsmith added a comment.Oct 2 2020, 3:12 PM

This broke use of setjmp for mingw on x86_64.

Thanks, should be fixed in rG8fb2a235b0f22dedba72b8b559ba33171a8dcd09. Now that we properly recognize _setjmp even if it has a weird signature, the MSVC-specific check for exactly one argument was breaking the MinGW case. I've removed that check and instead we only apply the custom MSVC-specific codegen rule if the declaration happens to be of the right form (but we apply the returns_twice attribute regardless).

This broke use of setjmp for mingw on x86_64.

Thanks, should be fixed in rG8fb2a235b0f22dedba72b8b559ba33171a8dcd09.

Thanks for the quick fix!