@@ -420,6 +420,122 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) {
420420 return false ;
421421}
422422
423+ class MaxValueEval : public RecursiveASTVisitor <MaxValueEval> {
424+
425+ std::vector<llvm::APInt> val;
426+ ASTContext &Context;
427+ llvm::APInt Max;
428+ unsigned bit_width;
429+
430+ public:
431+
432+ typedef RecursiveASTVisitor<MaxValueEval> VisitorBase;
433+
434+ explicit MaxValueEval (ASTContext &Ctx, const Expr *exp): Context(Ctx) {
435+ bit_width = Ctx.getIntWidth (exp->getType ());
436+ Max = llvm::APInt::getSignedMaxValue (bit_width);
437+ // Max.setAllBits();
438+ val.clear ();
439+ }
440+
441+ bool findMatch (Expr *exp) {
442+ TraverseStmt (exp);
443+ return true ;
444+ }
445+
446+ bool VisitDeclRefExpr (DeclRefExpr *dre) {
447+ val.push_back (Max);
448+ return false ;
449+ }
450+
451+ bool VisitArraySubscriptExpr (ArraySubscriptExpr *E) {
452+ val.push_back (Max);
453+ return false ;
454+ }
455+
456+ bool EvaluateExpression (Expr *exp) {
457+ Expr::EvalResult EVResult;
458+ if (exp->EvaluateAsInt (EVResult, Context)) {
459+ llvm::APSInt Result = EVResult.Val .getInt ();
460+ val.push_back (Result);
461+ return true ;
462+ }
463+ return false ;
464+ }
465+
466+ bool VisitBinaryOperator (BinaryOperator *E) {
467+
468+ if (EvaluateExpression (E)) {
469+ return false ;
470+ } else {
471+ TraverseStmt (E->getLHS ());
472+ llvm::APInt LHS = val.back ();
473+ val.pop_back ();
474+
475+ TraverseStmt (E->getRHS ());
476+ llvm::APInt RHS = val.back ();
477+ val.pop_back ();
478+ llvm::APInt Result = Max;
479+
480+ switch (E->getOpcode ()) {
481+ case BO_And:
482+ case BO_AndAssign:
483+ Result = LHS & RHS;
484+ break ;
485+
486+ case BO_Or:
487+ case BO_OrAssign:
488+ Result = LHS | RHS;
489+ break ;
490+
491+ case BO_Shl:
492+ case BO_ShlAssign:
493+ if (RHS != Max.getLimitedValue ())
494+ Result = LHS << RHS.getLimitedValue ();
495+ break ;
496+
497+ case BO_Shr:
498+ case BO_ShrAssign:
499+ if (RHS == Max.getLimitedValue ())
500+ Result = LHS;
501+ // else if(RHS.getLimitedValue() >= bit_width)
502+ // Result = llvm::APInt::getZero(bit_width);
503+ else
504+ Result = LHS.getLimitedValue () >> RHS.getLimitedValue ();
505+ break ;
506+
507+ case BO_Rem:
508+ case BO_RemAssign:
509+ if (LHS.getLimitedValue () < RHS.getLimitedValue ())
510+ Result = LHS;
511+ else
512+ Result = --RHS;
513+ break ;
514+
515+ default :
516+ break ;
517+ }
518+ val.push_back (Result);
519+ return false ;
520+ }
521+ return true ;
522+ }
523+
524+ bool VisitExpr (Expr *E) {
525+ if (EvaluateExpression (E)) {
526+ return false ;
527+ }
528+ return VisitorBase::VisitExpr (E);
529+ }
530+
531+ APInt getValue () {
532+ if (val.size () == 1 )
533+ return val[0 ];
534+ else // A pattern we didn't consider was encountered
535+ return Max;
536+ }
537+ };
538+
423539AST_MATCHER (ArraySubscriptExpr, isSafeArraySubscript) {
424540 // FIXME: Proper solution:
425541 // - refactor Sema::CheckArrayAccess
@@ -439,14 +555,13 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) {
439555 if (!CATy)
440556 return false ;
441557
442- if (const auto *IdxLit = dyn_cast<IntegerLiteral>(Node.getIdx ())) {
443- const APInt ArrIdx = IdxLit->getValue ();
444- // FIXME: ArrIdx.isNegative() we could immediately emit an error as that's a
445- // bug
446- if (ArrIdx.isNonNegative () &&
447- ArrIdx.getLimitedValue () < CATy->getLimitedSize ())
448- return true ;
449- }
558+ MaxValueEval Vis (Finder->getASTContext (), Node.getIdx ());
559+ Vis.findMatch (const_cast <Expr*>(Node.getIdx ()));
560+ APInt result = Vis.getValue ();
561+
562+ if (result.isNonNegative () &&
563+ result.getLimitedValue () < CATy->getLimitedSize ())
564+ return true ;
450565
451566 return false ;
452567}
@@ -1146,6 +1261,10 @@ class ArraySubscriptGadget : public WarningGadget {
11461261 // clang-format on
11471262 }
11481263
1264+ const ArraySubscriptExpr* getASE () const {
1265+ return ASE;
1266+ }
1267+
11491268 void handleUnsafeOperation (UnsafeBufferUsageHandler &Handler,
11501269 bool IsRelatedToDecl,
11511270 ASTContext &Ctx) const override {
@@ -3904,6 +4023,13 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
39044023 : FixItList{},
39054024 D, NaiveStrategy);
39064025 for (const auto &G : WarningGadgets) {
4026+ // const Stmt *Operation = Handler;
4027+ if (const auto ASG = dyn_cast<ArraySubscriptGadget>(G)) {
4028+ const auto * AS = ASG->getASE ();
4029+ MaxValueEval Vis (VD->getASTContext (), AS->getIdx ());
4030+ Vis.findMatch (const_cast <Expr*>(AS->getIdx ()));
4031+ APInt result = Vis.getValue ();
4032+ }
39074033 G->handleUnsafeOperation (Handler, /* IsRelatedToDecl=*/ true ,
39084034 D->getASTContext ());
39094035 }
0 commit comments