25 #include "llvm/ADT/SmallString.h" 26 #include "llvm/Support/raw_ostream.h" 28 using namespace clang;
33 const CheckerBase *Checker;
38 bool sameDecl(
const Expr *A1,
const Expr *A2) {
41 return D1->
getDecl() == D2->getDecl();
46 bool isSizeof(
const Expr *E,
const Expr *WithArg) {
47 if (
const auto *UE = dyn_cast<UnaryExprOrTypeTraitExpr>(E))
48 if (UE->getKind() ==
UETT_SizeOf && !UE->isArgumentType())
49 return sameDecl(UE->getArgumentExpr(), WithArg);
54 bool isStrlen(
const Expr *E,
const Expr *WithArg) {
55 if (
const auto *CE = dyn_cast<CallExpr>(E)) {
60 sameDecl(CE->getArg(0), WithArg));
66 bool isOne(
const Expr *E) {
67 if (
const auto *IL = dyn_cast<IntegerLiteral>(E))
68 return (IL->getValue().isIntN(1));
72 StringRef getPrintableName(
const Expr *E) {
80 bool containsBadStrncatPattern(
const CallExpr *CE);
101 bool containsBadStrlcpyStrlcatPattern(
const CallExpr *CE);
105 : Checker(Checker), BR(BR), AC(AC) {}
108 void VisitChildren(
Stmt *S);
109 void VisitStmt(
Stmt *S) {
122 bool WalkAST::containsBadStrncatPattern(
const CallExpr *CE) {
130 if (
const auto *BE = dyn_cast<BinaryOperator>(LenArg->
IgnoreParenCasts())) {
132 if (BE->getOpcode() == BO_Sub) {
133 const Expr *L = BE->getLHS();
134 const Expr *R = BE->getRHS();
135 if (isSizeof(L, DstArg) && isStrlen(R, DstArg))
144 if (isSizeof(LenArg, DstArg))
148 if (isSizeof(LenArg, SrcArg))
153 bool WalkAST::containsBadStrlcpyStrlcatPattern(
const CallExpr *CE) {
162 if (isSizeof(LenArg, DstArg))
166 const auto *LenArgVal = dyn_cast<
VarDecl>(LenArgDecl->getDecl());
167 if (LenArgVal->getInit())
168 LenArg = LenArgVal->getInit();
175 uint64_t ILRawVal = IL->getValue().getZExtValue();
182 DstArgDecl = dyn_cast<
DeclRefExpr>(BE->getLHS()->IgnoreParenImpCasts());
183 if (BE->getOpcode() == BO_Add) {
184 if ((IL = dyn_cast<IntegerLiteral>(BE->getRHS()->IgnoreParenImpCasts()))) {
185 DstOff = IL->getValue().getZExtValue();
191 if (
const auto *Buffer = dyn_cast<ConstantArrayType>(DstArgDecl->getType())) {
194 auto RemainingBufferLen = BufferLen - DstOff;
195 if (RemainingBufferLen < ILRawVal)
204 void WalkAST::VisitCallExpr(
CallExpr *CE) {
210 if (containsBadStrncatPattern(CE)) {
213 PathDiagnosticLocation Loc =
216 StringRef DstName = getPrintableName(DstArg);
219 llvm::raw_svector_ostream os(S);
220 os <<
"Potential buffer overflow. ";
221 if (!DstName.empty()) {
222 os <<
"Replace with 'sizeof(" << DstName <<
") " 223 "- strlen(" << DstName <<
") - 1'";
227 os <<
"se a safer 'strlcat' API";
229 BR.EmitBasicReport(FD, Checker,
"Anti-pattern in the argument",
230 "C String API", os.str(), Loc,
235 if (containsBadStrlcpyStrlcatPattern(CE)) {
238 PathDiagnosticLocation Loc =
241 StringRef DstName = getPrintableName(DstArg);
244 llvm::raw_svector_ostream os(S);
245 os <<
"The third argument allows to potentially copy more bytes than it should. ";
246 os <<
"Replace with the value ";
247 if (!DstName.empty())
248 os <<
"sizeof(" << DstName <<
")";
250 os <<
"sizeof(<destination buffer>)";
253 BR.EmitBasicReport(FD, Checker,
"Anti-pattern in the argument",
254 "C String API", os.str(), Loc,
263 void WalkAST::VisitChildren(
Stmt *S) {
270 class CStringSyntaxChecker:
public Checker<check::ASTCodeBody> {
273 void checkASTCodeBody(
const Decl *D, AnalysisManager& Mgr,
274 BugReporter &BR)
const {
275 WalkAST walker(
this, BR, Mgr.getAnalysisDeclContext(D));
281 void ento::registerCStringSyntaxChecker(CheckerManager &mgr) {
282 mgr.registerChecker<CStringSyntaxChecker>();
285 bool ento::shouldRegisterCStringSyntaxChecker(
const LangOptions &LO) {
Represents a function declaration or definition.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Defines enumerations for the type traits support.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Stmt - This represents one statement.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Decl - This represents one declaration (or definition), e.g.
Represents a variable declaration or definition.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
AnalysisDeclContext contains the context data for the function or method under analysis.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
This represents one expression.
static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name=StringRef())
Returns true if the callee is an externally-visible function in the top-level namespace, such as malloc.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
const Decl * getDecl() const
Dataflow Directional Tag Classes.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Expr * IgnoreParenLValueCasts() LLVM_READONLY
Skip past any parentheses and lvalue casts which might surround this expression until reaching a fixe...
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Defines the clang::TargetInfo interface.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
A reference to a declared variable, function, enum, etc.