@@ -420,6 +420,118 @@ 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+ typedef RecursiveASTVisitor<MaxValueEval> VisitorBase;
432+
433+ explicit MaxValueEval (ASTContext &Ctx, const Expr *exp) : Context(Ctx) {
434+ bit_width = Ctx.getIntWidth (exp->getType ());
435+ Max = llvm::APInt::getSignedMaxValue (bit_width);
436+ val.clear ();
437+ }
438+
439+ bool findMatch (Expr *exp) {
440+ TraverseStmt (exp);
441+ return true ;
442+ }
443+
444+ bool VisitDeclRefExpr (DeclRefExpr *dre) {
445+ val.push_back (Max);
446+ return false ;
447+ }
448+
449+ bool VisitArraySubscriptExpr (ArraySubscriptExpr *E) {
450+ val.push_back (Max);
451+ return false ;
452+ }
453+
454+ bool EvaluateExpression (Expr *exp) {
455+ Expr::EvalResult EVResult;
456+ if (exp->EvaluateAsInt (EVResult, Context)) {
457+ llvm::APSInt Result = EVResult.Val .getInt ();
458+ val.push_back (Result);
459+ return true ;
460+ }
461+ return false ;
462+ }
463+
464+ bool VisitBinaryOperator (BinaryOperator *E) {
465+
466+ if (EvaluateExpression (E)) {
467+ return false ;
468+ } else {
469+ TraverseStmt (E->getLHS ());
470+ llvm::APInt LHS = val.back ();
471+ val.pop_back ();
472+
473+ TraverseStmt (E->getRHS ());
474+ llvm::APInt RHS = val.back ();
475+ val.pop_back ();
476+ llvm::APInt Result = Max;
477+
478+ switch (E->getOpcode ()) {
479+ case BO_And:
480+ case BO_AndAssign:
481+ Result = LHS & RHS;
482+ break ;
483+
484+ case BO_Or:
485+ case BO_OrAssign:
486+ Result = LHS | RHS;
487+ break ;
488+
489+ case BO_Shl:
490+ case BO_ShlAssign:
491+ if (RHS != Max.getLimitedValue ())
492+ Result = LHS << RHS.getLimitedValue ();
493+ break ;
494+
495+ case BO_Shr:
496+ case BO_ShrAssign:
497+ if (RHS == Max.getLimitedValue ())
498+ Result = LHS;
499+ else
500+ Result = LHS.getLimitedValue () >> RHS.getLimitedValue ();
501+ break ;
502+
503+ case BO_Rem:
504+ case BO_RemAssign:
505+ if (LHS.getLimitedValue () < RHS.getLimitedValue ())
506+ Result = LHS;
507+ else
508+ Result = --RHS;
509+ break ;
510+
511+ default :
512+ break ;
513+ }
514+ val.push_back (Result);
515+ return false ;
516+ }
517+ return true ;
518+ }
519+
520+ bool VisitExpr (Expr *E) {
521+ if (EvaluateExpression (E)) {
522+ return false ;
523+ }
524+ return VisitorBase::VisitExpr (E);
525+ }
526+
527+ APInt getValue () {
528+ if (val.size () == 1 )
529+ return val[0 ];
530+ else // A pattern we didn't consider was encountered
531+ return Max;
532+ }
533+ };
534+
423535AST_MATCHER (ArraySubscriptExpr, isSafeArraySubscript) {
424536 // FIXME: Proper solution:
425537 // - refactor Sema::CheckArrayAccess
@@ -439,14 +551,13 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) {
439551 if (!CATy)
440552 return false ;
441553
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- }
554+ MaxValueEval Vis (Finder->getASTContext (), Node.getIdx ());
555+ Vis.findMatch (const_cast <Expr *>(Node.getIdx ()));
556+ APInt result = Vis.getValue ();
557+
558+ if (result.isNonNegative () &&
559+ result.getLimitedValue () < CATy->getLimitedSize ())
560+ return true ;
450561
451562 return false ;
452563}
0 commit comments