@@ -177,6 +177,10 @@ class ArrayBoundChecker : public Checker<check::PostStmt<ArraySubscriptExpr>,
177177 static bool isInAddressOf (const Stmt *S, ASTContext &AC);
178178
179179public:
180+ // When this parameter is set to true, the checker treats all
181+ // unknown values as tainted and reports wanings if such values
182+ // are used as offsets to access array elements
183+ bool IsAggressive = false ;
180184 void checkPostStmt (const ArraySubscriptExpr *E, CheckerContext &C) const {
181185 performCheck (E, C);
182186 }
@@ -478,6 +482,17 @@ static Messages getNonTaintMsgs(const ASTContext &ACtx,
478482 std::string (Buf)};
479483}
480484
485+ static Messages getTaintMsgs (const MemSpaceRegion *Space,
486+ const SubRegion *Region, const char *OffsetName,
487+ bool AlsoMentionUnderflow) {
488+ std::string RegName = getRegionName (Space, Region);
489+ return {formatv (" Potential out of bound access to {0} with tainted {1}" ,
490+ RegName, OffsetName),
491+ formatv (" Access of {0} with a tainted {1} that may be {2}too large" ,
492+ RegName, OffsetName,
493+ AlsoMentionUnderflow ? " negative or " : " " )};
494+ }
495+
481496const NoteTag *StateUpdateReporter::createNoteTag (CheckerContext &C) const {
482497 // Don't create a note tag if we didn't assume anything:
483498 if (!AssumedNonNegative && !AssumedUpperBound)
@@ -675,15 +690,46 @@ void ArrayBoundChecker::performCheck(const Expr *E, CheckerContext &C) const {
675690 C.addTransition (ExceedsUpperBound, SUR.createNoteTag (C));
676691 return ;
677692 }
693+
694+ BadOffsetKind Problem = AlsoMentionUnderflow
695+ ? BadOffsetKind::Indeterminate
696+ : BadOffsetKind::Overflowing;
697+ Messages Msgs =
698+ getNonTaintMsgs (C.getASTContext (), Space, Reg, ByteOffset,
699+ *KnownSize, Location, Problem);
700+ reportOOB (C, ExceedsUpperBound, Msgs, ByteOffset, KnownSize);
701+ return ;
678702 }
703+ if (!IsAggressive) {
704+ // ...and it can be valid as well...
705+ if (isTainted (State, ByteOffset)) {
706+ // ...but it's tainted, so report an error.
707+
708+ // Diagnostic detail: saying "tainted offset" is always correct, but
709+ // the common case is that 'idx' is tainted in 'arr[idx]' and then it's
710+ // nicer to say "tainted index".
711+ const char *OffsetName = " offset" ;
712+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
713+ if (isTainted (State, ASE->getIdx (), C.getLocationContext ()))
714+ OffsetName = " index" ;
715+
716+ Messages Msgs =
717+ getTaintMsgs (Space, Reg, OffsetName, AlsoMentionUnderflow);
718+ reportOOB (C, ExceedsUpperBound, Msgs, ByteOffset, KnownSize,
719+ /* IsTaintBug=*/ true );
720+ return ;
721+ }
679722
680- BadOffsetKind Problem = AlsoMentionUnderflow
681- ? BadOffsetKind::Indeterminate
682- : BadOffsetKind::Overflowing;
683- Messages Msgs = getNonTaintMsgs (C.getASTContext (), Space, Reg, ByteOffset,
684- *KnownSize, Location, Problem);
685- reportOOB (C, ExceedsUpperBound, Msgs, ByteOffset, KnownSize);
686- return ;
723+ // ...and it isn't tainted, so the checker will (optimistically) assume
724+ // that the offset is in bounds and mention this in the note tag.
725+ SUR.recordUpperBoundAssumption (*KnownSize);
726+ } else {
727+ Messages Msgs =
728+ getTaintMsgs (Space, Reg, " offset" , AlsoMentionUnderflow);
729+ reportOOB (C, ExceedsUpperBound, Msgs, ByteOffset, KnownSize,
730+ /* IsTaintBug=*/ true );
731+ return ;
732+ }
687733 }
688734
689735 // Actually update the state. The "if" only fails in the extremely unlikely
@@ -725,7 +771,7 @@ void ArrayBoundChecker::reportOOB(CheckerContext &C, ProgramStateRef ErrorState,
725771 std::optional<NonLoc> Extent,
726772 bool IsTaintBug /* =false*/ ) const {
727773
728- ExplodedNode *ErrorNode = C.generateNonFatalErrorNode (ErrorState);
774+ ExplodedNode *ErrorNode = C.generateErrorNode (ErrorState);
729775 if (!ErrorNode)
730776 return ;
731777
@@ -804,7 +850,10 @@ bool ArrayBoundChecker::isIdiomaticPastTheEndPtr(const Expr *E,
804850}
805851
806852void ento::registerArrayBoundChecker (CheckerManager &mgr) {
807- mgr.registerChecker <ArrayBoundChecker>();
853+ ArrayBoundChecker *checker = mgr.registerChecker <ArrayBoundChecker>();
854+ checker->IsAggressive =
855+ mgr.getAnalyzerOptions ().getCheckerBooleanOption (
856+ checker, " AggressiveReport" );
808857}
809858
810859bool ento::shouldRegisterArrayBoundChecker (const CheckerManager &mgr) {
0 commit comments