Index: clang-tidy/cert/CERTTidyModule.cpp =================================================================== --- clang-tidy/cert/CERTTidyModule.cpp +++ clang-tidy/cert/CERTTidyModule.cpp @@ -15,6 +15,7 @@ #include "../misc/NewDeleteOverloadsCheck.h" #include "../misc/NonCopyableObjects.h" #include "../misc/StaticAssertCheck.h" +#include "SetLongJmpCheck.h" #include "VariadicFunctionDefCheck.h" namespace clang { @@ -35,6 +36,9 @@ // OOP CheckFactories.registerCheck( "cert-oop11-cpp"); + // ERR + CheckFactories.registerCheck( + "cert-err52-cpp"); // C checkers // DCL Index: clang-tidy/cert/CMakeLists.txt =================================================================== --- clang-tidy/cert/CMakeLists.txt +++ clang-tidy/cert/CMakeLists.txt @@ -2,6 +2,7 @@ add_clang_library(clangTidyCERTModule CERTTidyModule.cpp + SetLongJmpCheck.cpp VariadicFunctionDefCheck.cpp LINK_LIBS Index: clang-tidy/cert/SetLongJmpCheck.h =================================================================== --- clang-tidy/cert/SetLongJmpCheck.h +++ clang-tidy/cert/SetLongJmpCheck.h @@ -0,0 +1,37 @@ +//===--- SetLongJmpCheck.h - clang-tidy--------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SETLONGJMPCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SETLONGJMPCHECK_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { + +/// Guards against use of setjmp/longjmp in C++ code +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cert-setlongjmp.html +class SetLongJmpCheck : public ClangTidyCheck { +public: + SetLongJmpCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void registerPPCallbacks(CompilerInstance &Compiler) override; + + static const char DiagWording[]; +}; + +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_SETLONGJMPCHECK_H + Index: clang-tidy/cert/SetLongJmpCheck.cpp =================================================================== --- clang-tidy/cert/SetLongJmpCheck.cpp +++ clang-tidy/cert/SetLongJmpCheck.cpp @@ -0,0 +1,77 @@ +//===--- SetLongJmpCheck.cpp - clang-tidy----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "SetLongJmpCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { + +const char SetLongJmpCheck::DiagWording[] = + "do not call %0; consider using exception handling instead"; + +namespace { +class SetJmpMacroCallbacks : public PPCallbacks { + SetLongJmpCheck &Check; + +public: + explicit SetJmpMacroCallbacks(SetLongJmpCheck &Check) : Check(Check) {} + + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, + SourceRange Range, const MacroArgs *Args) override { + const auto *II = MacroNameTok.getIdentifierInfo(); + if (!II) + return; + + if (II->getName() == "setjmp") + Check.diag(Range.getBegin(), Check.DiagWording) << II; + } +}; +} // namespace + +void SetLongJmpCheck::registerPPCallbacks(CompilerInstance &Compiler) { + // This checker only applies to C++, where exception handling is a superior + // solution to setjmp/longjmp calls. + if (!getLangOpts().CPlusPlus) + return; + + // Per [headers]p5, setjmp must be exposed as a macro instead of a function, + // despite the allowance in C for setjmp to also be an extern function. + Compiler.getPreprocessor().addPPCallbacks( + llvm::make_unique(*this)); +} + +void SetLongJmpCheck::registerMatchers(MatchFinder *Finder) { + // This checker only applies to C++, where exception handling is a superior + // solution to setjmp/longjmp calls. + if (!getLangOpts().CPlusPlus) + return; + + // In case there is an implementation that happens to define setjmp as a + // function instead of a macro, this will also catch use of it. However, we + // are primarily searching for uses of longjmp. + Finder->addMatcher(callExpr(callee(functionDecl(anyOf(hasName("setjmp"), + hasName("longjmp"))))) + .bind("expr"), + this); +} + +void SetLongJmpCheck::check(const MatchFinder::MatchResult &Result) { + const auto *E = Result.Nodes.getNodeAs("expr"); + diag(E->getExprLoc(), DiagWording) << cast(E->getCalleeDecl()); +} + +} // namespace tidy +} // namespace clang Index: docs/clang-tidy/checks/cert-setlongjmp.rst =================================================================== --- docs/clang-tidy/checks/cert-setlongjmp.rst +++ docs/clang-tidy/checks/cert-setlongjmp.rst @@ -0,0 +1,11 @@ +cert-err52-cpp +============== + +The C standard library facilities setjmp() and longjmp() can be used to +simulate throwing and catching exceptions. However, these facilities bypass +automatic resource management and can result in undefined behavior, commonly +including resource leaks, and denial-of-service attacks. + +This check corresponds to the CERT C++ Coding Standard rule +`ERR52-CPP. Do not use setjmp() or longjmp() +`_. Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -2,6 +2,7 @@ ========================= .. toctree:: + cert-setlongjmp cert-variadic-function-def cppcoreguidelines-pro-type-const-cast cppcoreguidelines-pro-type-reinterpret-cast Index: test/clang-tidy/cert-setlongjmp.cpp =================================================================== --- test/clang-tidy/cert-setlongjmp.cpp +++ test/clang-tidy/cert-setlongjmp.cpp @@ -0,0 +1,26 @@ +// RUN: %python %S/check_clang_tidy.py %s cert-err52-cpp %t -- -std=c++11 + +typedef void *jmp_buf; +extern int __setjmpimpl(jmp_buf); +#define setjmp(x) __setjmpimpl(x) +[[noreturn]] extern void longjmp(jmp_buf, int); + +namespace std { +using ::jmp_buf; +using ::longjmp; +} + +static jmp_buf env; +void g() { + std::longjmp(env, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call 'longjmp'; consider using exception handling instead [cert-err52-cpp] + ::longjmp(env, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call 'longjmp'; consider using exception handling instead + longjmp(env, 1); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not call 'longjmp'; consider using exception handling instead +} + +void f() { + (void)setjmp(env); + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: do not call 'setjmp'; consider using exception handling instead +}