From: Rafael Espindola Date: Wed, 12 Oct 2011 19:51:18 +0000 (+0000) Subject: Add returns_twice to functions that are known to return twice. This implements X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6700415542121e2cb7d867728046ffa21e402019;p=clang Add returns_twice to functions that are known to return twice. This implements the same behavior of gcc by keeping the attribute out of the function type. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141803 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 60bcde372a..d3a5eaf5f9 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -77,6 +77,7 @@ // in that it accepts its arguments as a va_list rather than // through an ellipsis // e -> const, but only when -fmath-errno=0 +// j -> returns_twice (like setjmp) // FIXME: gcc has nonnull #if defined(BUILTIN) && !defined(LIBBUILTIN) @@ -427,7 +428,7 @@ BUILTIN(__builtin_return_address, "v*IUi", "n") BUILTIN(__builtin_extract_return_addr, "v*v*", "n") BUILTIN(__builtin_frame_address, "v*IUi", "n") BUILTIN(__builtin_flt_rounds, "i", "nc") -BUILTIN(__builtin_setjmp, "iv**", "") +BUILTIN(__builtin_setjmp, "iv**", "j") BUILTIN(__builtin_longjmp, "vv**i", "r") BUILTIN(__builtin_unwind_init, "v", "") BUILTIN(__builtin_eh_return_data_regno, "iIi", "nc") @@ -672,6 +673,17 @@ LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_LANGUAGES) // POSIX unistd.h LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES) // POSIX setjmp.h + +LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(__sigsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(sigsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(vfork, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(getcontext, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) + LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES) LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_LANGUAGES) // non-standard but very common diff --git a/include/clang/Basic/Builtins.h b/include/clang/Basic/Builtins.h index fbf4ef417f..5afa020100 100644 --- a/include/clang/Basic/Builtins.h +++ b/include/clang/Basic/Builtins.h @@ -103,6 +103,11 @@ public: return strchr(GetRecord(ID).Attributes, 'r') != 0; } + /// isReturnsTwice - Return true if we know this builtin can return twice. + bool isReturnsTwice(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'j') != 0; + } + /// isLibFunction - Return true if this is a builtin for a libc/libm function, /// with a "__builtin_" prefix (e.g. __builtin_abs). bool isLibFunction(unsigned ID) const { diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 73f5cdb122..4f3e8ad2d5 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -468,6 +468,10 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (D->hasAttr()) Proto += " __attribute((noreturn))"; + + if (D->hasAttr()) + Proto += " __attribute((returns_twice))"; + if (CXXConstructorDecl *CDecl = dyn_cast(D)) { bool HasInitializerList = false; for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index f52abef330..6ae2d0c967 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -729,6 +729,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, // FIXME: handle sseregparm someday... if (TargetDecl) { + if (TargetDecl->hasAttr()) + FuncAttrs |= llvm::Attribute::ReturnsTwice; if (TargetDecl->hasAttr()) FuncAttrs |= llvm::Attribute::NoUnwind; else if (const FunctionDecl *Fn = dyn_cast(TargetDecl)) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d19023d045..8e2ff5ca88 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7263,6 +7263,9 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { FD->addAttr(::new (Context) ConstAttr(FD->getLocation(), Context)); } + if (Context.BuiltinInfo.isReturnsTwice(BuiltinID) && + !FD->getAttr()) + FD->addAttr(::new (Context) ReturnsTwiceAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->getAttr()) FD->addAttr(::new (Context) NoThrowAttr(FD->getLocation(), Context)); if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->getAttr()) diff --git a/test/Analysis/security-syntax-checks.m b/test/Analysis/security-syntax-checks.m index a04401b531..6fb5b3cf14 100644 --- a/test/Analysis/security-syntax-checks.m +++ b/test/Analysis/security-syntax-checks.m @@ -170,7 +170,7 @@ void test_strcat() { //===----------------------------------------------------------------------=== typedef int __int32_t; typedef __int32_t pid_t; -pid_t vfork(void); +pid_t vfork(void); //expected-warning{{declaration of built-in function 'vfork' requires inclusion of the header }} void test_vfork() { vfork(); //expected-warning{{Call to function 'vfork' is insecure as it can lead to denial of service situations in the parent process.}} diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c index fd98458c84..6cbf40ba22 100644 --- a/test/CodeGen/function-attributes.c +++ b/test/CodeGen/function-attributes.c @@ -100,3 +100,14 @@ __attribute__ ((returns_twice)) void f17(void); __attribute__ ((returns_twice)) void f18(void) { f17(); } + +// CHECK: define void @f19() +// CHECK: { +// CHECK: call i32 @setjmp(i32* null) +// CHECK: returns_twice +// CHECK: ret void +typedef int jmp_buf[((9 * 2) + 3 + 16)]; +int setjmp(jmp_buf); +void f19(void) { + setjmp(0); +} diff --git a/test/Sema/attr-returns-twice.c b/test/Sema/attr-returns-twice.c new file mode 100644 index 0000000000..13f53e36de --- /dev/null +++ b/test/Sema/attr-returns-twice.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 %s -verify -fsyntax-only + +int a __attribute__((returns_twice)); // expected-warning {{'returns_twice' attribute only applies to functions}} + +__attribute__((returns_twice)) void t0(void) { +} + +void t1() __attribute__((returns_twice)); + +void t2() __attribute__((returns_twice(2))); // expected-error {{attribute takes no arguments}} + +typedef void (*t3)(void) __attribute__((returns_twice)); // expected-warning {{'returns_twice' attribute only applies to functions}}