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) {
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())) {
203 auto RemainingBufferLen = BufferLen - DstOff;
204 if (RemainingBufferLen < ILRawVal)
213 void WalkAST::VisitCallExpr(
CallExpr *CE) {
219 if (containsBadStrncatPattern(CE)) {
222 PathDiagnosticLocation Loc =
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";
238 BR.EmitBasicReport(FD, Checker,
"Anti-pattern in the argument",
239 "C String API", os.str(), Loc,
244 if (containsBadStrlcpyStrlcatPattern(CE)) {
247 PathDiagnosticLocation Loc =
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>)";
262 BR.EmitBasicReport(FD, Checker,
"Anti-pattern in the argument",
263 "C String API", os.str(), Loc,
272 void WalkAST::VisitChildren(
Stmt *S) {
279 class CStringSyntaxChecker:
public Checker<check::ASTCodeBody> {
282 void checkASTCodeBody(
const Decl *D, AnalysisManager& Mgr,
283 BugReporter &BR)
const {
284 WalkAST walker(
this, BR, Mgr.getAnalysisDeclContext(D));
290 void ento::registerCStringSyntaxChecker(CheckerManager &mgr) {
291 mgr.registerChecker<CStringSyntaxChecker>();
294 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.