12
12
#include " clang/AST/DeclCXX.h"
13
13
#include " clang/AST/Expr.h"
14
14
#include " clang/AST/ExprCXX.h"
15
+ #include " clang/AST/FormatString.h"
15
16
#include " clang/AST/RecursiveASTVisitor.h"
16
17
#include " clang/AST/Stmt.h"
17
18
#include " clang/AST/StmtVisitor.h"
@@ -611,6 +612,38 @@ static bool isNullTermPointer(const Expr *Ptr) {
611
612
return false ;
612
613
}
613
614
615
+ // Return true iff at least one of following cases holds:
616
+ // 1. Format string is a literal and there is an unsafe pointer argument
617
+ // corresponding to an `s` specifier;
618
+ // 2. Format string is not a literal and there is least an unsafe pointer
619
+ // argument (including the formatter argument).
620
+ static bool hasUnsafeFormatOrSArg (const Expr *Fmt, unsigned FmtArgIdx,
621
+ const CallExpr *Call, ASTContext &Ctx) {
622
+ if (auto *SL = dyn_cast<StringLiteral>(Fmt->IgnoreParenImpCasts ())) {
623
+ StringRef FmtStr = SL->getString ();
624
+ auto I = FmtStr.begin ();
625
+ auto E = FmtStr.end ();
626
+ unsigned ArgIdx = FmtArgIdx;
627
+
628
+ do {
629
+ ArgIdx = analyze_format_string::ParseFormatStringFirstSArgIndex (
630
+ I, E, ArgIdx, Ctx.getLangOpts (), Ctx.getTargetInfo ());
631
+ if (ArgIdx && Call->getNumArgs () > ArgIdx &&
632
+ !isNullTermPointer (Call->getArg (ArgIdx)))
633
+ return true ;
634
+ } while (ArgIdx);
635
+ return false ;
636
+ }
637
+ // If format is not a string literal, we cannot analyze the format string.
638
+ // In this case, this call is considered unsafe if at least one argument
639
+ // (including the format argument) is unsafe pointer.
640
+ return llvm::any_of (
641
+ llvm::make_range (Call->arg_begin () + FmtArgIdx, Call->arg_end ()),
642
+ [](const Expr *Arg) {
643
+ return Arg->getType ()->isPointerType () && !isNullTermPointer (Arg);
644
+ });
645
+ }
646
+
614
647
// Matches a call to one of the `-printf" functions (excluding the ones with
615
648
// va_list, or `-sprintf`s) that taking pointer-to-char-as-string arguments but
616
649
// fail to guarantee their null-termination. In other words, these calls are
@@ -626,19 +659,18 @@ AST_MATCHER_P(CallExpr, unsafeStringInPrintfs, StringRef, CoreName) {
626
659
if (Prefix.ends_with (" w" ))
627
660
Prefix = Prefix.drop_back (1 );
628
661
629
- auto AnyUnsafeStrPtr = [](const Expr *Arg) -> bool {
630
- return Arg->getType ()->isPointerType () && !isNullTermPointer (Arg);
631
- };
632
-
633
662
if (Prefix.empty () ||
634
663
Prefix == " k" ) // printf: all pointer args should be null-terminated
635
- return any_of (Node.arguments (), AnyUnsafeStrPtr);
636
- if (Prefix == " f" && Node.getNumArgs () > 1 )
637
- return any_of (llvm::make_range (Node.arg_begin () + 1 , Node.arg_end ()),
638
- AnyUnsafeStrPtr);
639
- if (Prefix == " sn" && Node.getNumArgs () > 2 ) {
640
- return any_of (llvm::make_range (Node.arg_begin () + 2 , Node.arg_end ()),
641
- AnyUnsafeStrPtr);
664
+ return hasUnsafeFormatOrSArg (Node.getArg (0 ), 0 , &Node,
665
+ Finder->getASTContext ());
666
+ if (Prefix == " f" )
667
+ return hasUnsafeFormatOrSArg (Node.getArg (1 ), 1 , &Node,
668
+ Finder->getASTContext ());
669
+ if (Prefix == " sn" ) {
670
+ // The first two arguments need to be in safe patterns, which is checked
671
+ // by `isSafeSizedby`:
672
+ return hasUnsafeFormatOrSArg (Node.getArg (2 ), 2 , &Node,
673
+ Finder->getASTContext ());
642
674
}
643
675
return false ; // A call to a "-printf" falls into another category.
644
676
}
@@ -775,7 +807,7 @@ AST_MATCHER_P(CallExpr, ignoreLibcPrefixAndSuffix,
775
807
776
808
StringRef CoreName =
777
809
TheLittleParser.matchName (II->getName (), FD->getBuiltinID ());
778
-
810
+
779
811
return InnerMatcher (CoreName).matches (Node, Finder, Builder);
780
812
}
781
813
} // namespace clang::ast_matchers
0 commit comments