14
14
#include " clang/AST/RecursiveASTVisitor.h"
15
15
#include " clang/AST/Stmt.h"
16
16
#include " clang/AST/StmtVisitor.h"
17
+ #include " clang/AST/Type.h"
17
18
#include " clang/ASTMatchers/ASTMatchFinder.h"
18
19
#include " clang/ASTMatchers/ASTMatchers.h"
19
20
#include " clang/Basic/SourceLocation.h"
@@ -763,32 +764,27 @@ AST_MATCHER(FunctionDecl, isNormalPrintfFunc) {
763
764
AST_MATCHER_P (CallExpr, hasUnsafePrintfStringArg,
764
765
clang::ast_matchers::internal::Matcher<Expr>,
765
766
UnsafeStringArgMatcher) {
766
- // Determine what printf it is:
767
- const Expr *FirstArg = Node.getArg (0 );
768
- ASTContext &Ctx = Finder->getASTContext ();
767
+ // Determine what printf it is by examining formal parameters:
768
+ const FunctionDecl *FD = Node.getDirectCallee ();
769
769
770
- if (isa<StringLiteral>(FirstArg->IgnoreParenImpCasts ())) {
771
- // It is a printf/kprintf. And, the format is a string literal:
772
- bool isKprintf = false ;
773
- const Expr *UnsafeArg;
770
+ assert (FD && " It should have been checked that FD is non-null." );
774
771
775
- if (auto *Callee = Node.getDirectCallee ())
776
- if (auto *II = Callee->getIdentifier ())
777
- isKprintf = II->getName () == " kprintf" ;
778
- if (hasUnsafeFormatOrSArg (&Node, UnsafeArg, 0 , Ctx, isKprintf))
779
- return UnsafeStringArgMatcher.matches (*UnsafeArg, Finder, Builder);
780
- return false ;
781
- }
772
+ unsigned NumParms = FD->getNumParams ();
773
+
774
+ if (NumParms < 1 )
775
+ return false ; // possibly some user-defined printf function
782
776
783
- QualType PtrTy = FirstArg->getType ();
777
+ ASTContext &Ctx = Finder->getASTContext ();
778
+ QualType FristParmTy = FD->getParamDecl (0 )->getType ();
784
779
785
- assert (PtrTy->isPointerType ());
780
+ if (!FristParmTy->isPointerType ())
781
+ return false ; // possibly some user-defined printf function
786
782
787
- QualType PteTy = (cast<PointerType>(PtrTy ))->getPointeeType ();
783
+ QualType FirstPteTy = (cast<PointerType>(FristParmTy ))->getPointeeType ();
788
784
789
- if (!Ctx.getFILEType (). isNull () /* If `FILE *` is not ever in the ASTContext,
790
- there can't be any file pointer then */
791
- && PteTy .getCanonicalType () == Ctx.getFILEType ().getCanonicalType ()) {
785
+ if (!Ctx.getFILEType ()
786
+ . isNull () && // `FILE *` must be in the context if it is fprintf
787
+ FirstPteTy .getCanonicalType () == Ctx.getFILEType ().getCanonicalType ()) {
792
788
// It is a fprintf:
793
789
const Expr *UnsafeArg;
794
790
@@ -797,17 +793,32 @@ AST_MATCHER_P(CallExpr, hasUnsafePrintfStringArg,
797
793
return false ;
798
794
}
799
795
800
- const Expr *SecondArg = Node.getArg (1 );
801
-
802
- if (SecondArg->getType ()->isIntegerType ()) {
803
- // It is a snprintf:
796
+ if (FirstPteTy.isConstQualified ()) {
797
+ // If the first parameter is a `const char *`, it is a printf/kprintf:
798
+ bool isKprintf = false ;
804
799
const Expr *UnsafeArg;
805
800
806
- if (hasUnsafeFormatOrSArg (&Node, UnsafeArg, 2 , Ctx, false ))
801
+ if (auto *II = FD->getIdentifier ())
802
+ isKprintf = II->getName () == " kprintf" ;
803
+ if (hasUnsafeFormatOrSArg (&Node, UnsafeArg, 0 , Ctx, isKprintf))
807
804
return UnsafeStringArgMatcher.matches (*UnsafeArg, Finder, Builder);
808
805
return false ;
809
806
}
810
- // It is printf but the format string is passed by pointer. The only thing we
807
+
808
+ if (NumParms > 2 ) {
809
+ QualType SecondParmTy = FD->getParamDecl (1 )->getType ();
810
+
811
+ if (!FirstPteTy.isConstQualified () && SecondParmTy->isIntegerType ()) {
812
+ // If the first parameter type is non-const qualified `char *` and the
813
+ // second is an integer, it is a snprintf:
814
+ const Expr *UnsafeArg;
815
+
816
+ if (hasUnsafeFormatOrSArg (&Node, UnsafeArg, 2 , Ctx, false ))
817
+ return UnsafeStringArgMatcher.matches (*UnsafeArg, Finder, Builder);
818
+ return false ;
819
+ }
820
+ }
821
+ // We don't really recognize this "normal" printf, the only thing we
811
822
// can do is to require all pointers to be null-terminated:
812
823
for (auto Arg : Node.arguments ())
813
824
if (Arg->getType ()->isPointerType () && !isNullTermPointer (Arg))
@@ -826,12 +837,23 @@ AST_MATCHER_P(CallExpr, hasUnsafePrintfStringArg,
826
837
// size:= DRE.size()/DRE.size_bytes()
827
838
// And DRE is a hardened container or view.
828
839
AST_MATCHER (CallExpr, hasUnsafeSnprintfBuffer) {
829
- if (Node.getNumArgs () < 3 )
830
- return false ; // not an snprintf call
840
+ const FunctionDecl *FD = Node.getDirectCallee ();
841
+
842
+ assert (FD && " It should have been checked that FD is non-null." );
843
+
844
+ if (FD->getNumParams () < 3 )
845
+ return false ; // Not an snprint
846
+
847
+ QualType FirstParmTy = FD->getParamDecl (0 )->getType ();
848
+
849
+ if (!FirstParmTy->isPointerType ())
850
+ return false ; // Not an snprint
831
851
852
+ QualType FirstPteTy = cast<PointerType>(FirstParmTy)->getPointeeType ();
832
853
const Expr *Buf = Node.getArg (0 ), *Size = Node.getArg (1 );
833
854
834
- if (!Buf->getType ()->isPointerType () || !Size ->getType ()->isIntegerType ())
855
+ if (FirstPteTy.isConstQualified () || !Buf->getType ()->isPointerType () ||
856
+ !Size ->getType ()->isIntegerType ())
835
857
return false ; // not an snprintf call
836
858
837
859
static StringRef SizedObjs[] = {" span" , " array" , " vector" ,
0 commit comments