about summary refs log tree commit diff
path: root/include
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2021-02-22 15:52:21 -0500
committerRich Felker <dalias@aerifal.cx>2021-02-22 15:52:21 -0500
commitb129cd8690da492b25b66061e29e52aae235f1e3 (patch)
treeecf69a6448c98f70251a19430d131445ceaf268d /include
parent3309e2d7a1aa82e52d7ac0facd64f9b5c28f923b (diff)
downloadmusl-b129cd8690da492b25b66061e29e52aae235f1e3.tar.gz
musl-b129cd8690da492b25b66061e29e52aae235f1e3.tar.xz
musl-b129cd8690da492b25b66061e29e52aae235f1e3.zip
guard against compilers failing to handle setjmp specially by default
since 4.1, gcc has had the __returns_twice__ attribute and has
required functions which return twice to carry it; however it's always
applied it automatically to known setjmp-like function names. clang
however does not do this reliably, at least not with -ffreestanding
and possibly under other conditions, resulting in silent emission of
wrong code.

since the symbol name setjmp is in no way special (setjmp is specified
as a macro that could expand to use any implementation-specific symbol
name or names), a compiler is justified not to do anything special
without further hints, and it's reasonable to do what we can to
provide such hints.

gcc 4.0.x and earlier do not recognize the attribute, so make use
conditional on __GNUC__ macros. clang and other gcc-like compilers
report (and have always reported) a later "GNUC" version so the
preprocessor conditional should function as desired for them as too.

undefine the internal macro after use so that nothing abuses it as a
public feature.
Diffstat (limited to 'include')
-rw-r--r--include/setjmp.h14
1 files changed, 11 insertions, 3 deletions
diff --git a/include/setjmp.h b/include/setjmp.h
index 2d43abf8..1976af23 100644
--- a/include/setjmp.h
+++ b/include/setjmp.h
@@ -15,25 +15,33 @@ typedef struct __jmp_buf_tag {
 	unsigned long __ss[128/sizeof(long)];
 } jmp_buf[1];
 
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
+#define __setjmp_attr __attribute__((__returns_twice__))
+#else
+#define __setjmp_attr
+#endif
+
 #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
  || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
  || defined(_BSD_SOURCE)
 typedef jmp_buf sigjmp_buf;
-int sigsetjmp (sigjmp_buf, int);
+int sigsetjmp (sigjmp_buf, int) __setjmp_attr;
 _Noreturn void siglongjmp (sigjmp_buf, int);
 #endif
 
 #if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
  || defined(_BSD_SOURCE)
-int _setjmp (jmp_buf);
+int _setjmp (jmp_buf) __setjmp_attr;
 _Noreturn void _longjmp (jmp_buf, int);
 #endif
 
-int setjmp (jmp_buf);
+int setjmp (jmp_buf) __setjmp_attr;
 _Noreturn void longjmp (jmp_buf, int);
 
 #define setjmp setjmp
 
+#undef __setjmp_attr
+
 #ifdef __cplusplus
 }
 #endif