@@ -420,6 +420,122 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) {
420
420
return false ;
421
421
}
422
422
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
+
423
539
AST_MATCHER (ArraySubscriptExpr, isSafeArraySubscript) {
424
540
// FIXME: Proper solution:
425
541
// - refactor Sema::CheckArrayAccess
@@ -439,14 +555,13 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) {
439
555
if (!CATy)
440
556
return false ;
441
557
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 ;
450
565
451
566
return false ;
452
567
}
@@ -1146,6 +1261,10 @@ class ArraySubscriptGadget : public WarningGadget {
1146
1261
// clang-format on
1147
1262
}
1148
1263
1264
+ const ArraySubscriptExpr* getASE () const {
1265
+ return ASE;
1266
+ }
1267
+
1149
1268
void handleUnsafeOperation (UnsafeBufferUsageHandler &Handler,
1150
1269
bool IsRelatedToDecl,
1151
1270
ASTContext &Ctx) const override {
@@ -3904,6 +4023,13 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
3904
4023
: FixItList{},
3905
4024
D, NaiveStrategy);
3906
4025
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
+ }
3907
4033
G->handleUnsafeOperation (Handler, /* IsRelatedToDecl=*/ true ,
3908
4034
D->getASTContext ());
3909
4035
}
0 commit comments