25#include "llvm/ADT/SmallString.h"
26#include "llvm/Support/raw_ostream.h"
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) {
74 return D->getDecl()->getName();
80 bool containsBadStrncatPattern(
const CallExpr *CE);
101 bool containsBadStrlcpyStrlcatPattern(
const CallExpr *CE);
108 void VisitChildren(
Stmt *S);
109 void VisitStmt(
Stmt *S) {
122bool 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))
153bool WalkAST::containsBadStrlcpyStrlcatPattern(
const CallExpr *CE) {
160 const auto *LenArgDRE =
163 if (isSizeof(LenArg, DstArg))
168 const auto *LenArgVal = dyn_cast<VarDecl>(LenArgDRE->getDecl());
171 assert(isa<EnumConstantDecl>(LenArgDRE->getDecl()));
174 if (LenArgVal->getInit())
175 LenArg = LenArgVal->getInit();
182 uint64_t ILRawVal = IL->getValue().getZExtValue();
190 DstArgDRE = dyn_cast<DeclRefExpr>(BE->getLHS()->IgnoreParenImpCasts());
191 if (BE->getOpcode() == BO_Add) {
192 if ((IL = dyn_cast<IntegerLiteral>(BE->getRHS()->IgnoreParenImpCasts()))) {
193 DstOff = IL->getValue().getZExtValue();
199 if (
const auto *Buffer =
200 dyn_cast<ConstantArrayType>(DstArgDRE->getType())) {
202 uint64_t BufferLen =
C.getTypeSize(Buffer) / 8;
203 auto RemainingBufferLen = BufferLen - DstOff;
204 if (RemainingBufferLen < ILRawVal)
213void WalkAST::VisitCallExpr(
CallExpr *CE) {
219 if (containsBadStrncatPattern(CE)) {
225 StringRef DstName = getPrintableName(DstArg);
228 llvm::raw_svector_ostream os(S);
229 os <<
"Potential buffer overflow. ";
230 if (!DstName.empty()) {
231 os <<
"Replace with 'sizeof(" << DstName <<
") "
232 "- strlen(" << DstName <<
") - 1'";
236 os <<
"se a safer 'strlcat' API";
239 "C String API", os.str(),
Loc,
244 if (containsBadStrlcpyStrlcatPattern(CE)) {
250 StringRef DstName = getPrintableName(DstArg);
253 llvm::raw_svector_ostream os(S);
254 os <<
"The third argument allows to potentially copy more bytes than it should. ";
255 os <<
"Replace with the value ";
256 if (!DstName.empty())
257 os <<
"sizeof(" << DstName <<
")";
259 os <<
"sizeof(<destination buffer>)";
263 "C String API", os.str(),
Loc,
272void WalkAST::VisitChildren(
Stmt *S) {
273 for (
Stmt *Child : S->children())
279class CStringSyntaxChecker:
public Checker<check::ASTCodeBody> {
294bool ento::shouldRegisterCStringSyntaxChecker(
const CheckerManager &mgr) {
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Defines enumerations for the type traits support.
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, method or block under analysis.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Decl - This represents one declaration (or definition), e.g.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreParenLValueCasts() LLVM_READONLY
Skip past any parentheses and lvalue casts which might surround this expression until reaching a fixe...
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Represents a function declaration or definition.
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
BugReporter is a utility class for generating PathDiagnostics for analysis.
const SourceManager & getSourceManager()
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=std::nullopt, ArrayRef< FixItHint > Fixits=std::nullopt)
ASTContext & getContext()
static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name=StringRef())
Returns true if the given function is an externally-visible function in the top-level namespace,...
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
Defines the clang::TargetInfo interface.
The JSON file list parser is used to communicate input to InstallAPI.