forked from OSchip/llvm-project
Adding a checker (cert-err52-cpp) that detects use of setjmp or longjmp in C++ code. Corresponds to the CERT C++ secure coding rule: https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=1834
llvm-svn: 249727
This commit is contained in:
parent
1cbf51a41b
commit
e4b1765a0f
|
@ -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 @@ public:
|
|||
// OOP
|
||||
CheckFactories.registerCheck<MoveConstructorInitCheck>(
|
||||
"cert-oop11-cpp");
|
||||
// ERR
|
||||
CheckFactories.registerCheck<SetLongJmpCheck>(
|
||||
"cert-err52-cpp");
|
||||
|
||||
// C checkers
|
||||
// DCL
|
||||
|
|
|
@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support)
|
|||
|
||||
add_clang_library(clangTidyCERTModule
|
||||
CERTTidyModule.cpp
|
||||
SetLongJmpCheck.cpp
|
||||
VariadicFunctionDefCheck.cpp
|
||||
|
||||
LINK_LIBS
|
||||
|
|
|
@ -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<SetJmpMacroCallbacks>(*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<CallExpr>("expr");
|
||||
diag(E->getExprLoc(), DiagWording) << cast<NamedDecl>(E->getCalleeDecl());
|
||||
}
|
||||
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
<https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=1834>`_.
|
|
@ -2,6 +2,7 @@ List of clang-tidy Checks
|
|||
=========================
|
||||
|
||||
.. toctree::
|
||||
cert-setlongjmp
|
||||
cert-variadic-function-def
|
||||
cppcoreguidelines-pro-type-const-cast
|
||||
cppcoreguidelines-pro-type-reinterpret-cast
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue