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:
Aaron Ballman 2015-10-08 19:54:43 +00:00
parent 1cbf51a41b
commit e4b1765a0f
7 changed files with 157 additions and 0 deletions

View File

@ -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

View File

@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS support)
add_clang_library(clangTidyCERTModule
CERTTidyModule.cpp
SetLongJmpCheck.cpp
VariadicFunctionDefCheck.cpp
LINK_LIBS

View File

@ -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

View File

@ -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

View File

@ -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>`_.

View File

@ -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

View File

@ -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
}