@@ -130,6 +130,20 @@ struct Messages {
130130 std::string Short, Full;
131131};
132132
133+ enum class BadOffsetKind { Negative, Overflowing, Indeterminate };
134+
135+ constexpr llvm::StringLiteral Adjectives[] = {" a negative" , " an overflowing" ,
136+ " a negative or overflowing" };
137+ static StringRef asAdjective (BadOffsetKind Problem) {
138+ return Adjectives[static_cast <int >(Problem)];
139+ }
140+
141+ constexpr llvm::StringLiteral Prepositions[] = {" preceding" , " after the end of" ,
142+ " around" };
143+ static StringRef asPreposition (BadOffsetKind Problem) {
144+ return Prepositions[static_cast <int >(Problem)];
145+ }
146+
133147// NOTE: The `ArraySubscriptExpr` and `UnaryOperator` callbacks are `PostStmt`
134148// instead of `PreStmt` because the current implementation passes the whole
135149// expression to `CheckerContext::getSVal()` which only works after the
@@ -388,18 +402,6 @@ static std::optional<int64_t> getConcreteValue(std::optional<NonLoc> SV) {
388402 return SV ? getConcreteValue (*SV) : std::nullopt ;
389403}
390404
391- static Messages getPrecedesMsgs (const MemSpaceRegion *Space,
392- const SubRegion *Region, NonLoc Offset) {
393- std::string RegName = getRegionName (Space, Region), OffsetStr = " " ;
394-
395- if (auto ConcreteOffset = getConcreteValue (Offset))
396- OffsetStr = formatv (" {0}" , ConcreteOffset);
397-
398- return {
399- formatv (" Out of bound access to memory preceding {0}" , RegName),
400- formatv (" Access of {0} at negative byte offset{1}" , RegName, OffsetStr)};
401- }
402-
403405// / Try to divide `Val1` and `Val2` (in place) by `Divisor` and return true if
404406// / it can be performed (`Divisor` is nonzero and there is no remainder). The
405407// / values `Val1` and `Val2` may be nullopt and in that case the corresponding
@@ -419,10 +421,11 @@ static bool tryDividePair(std::optional<int64_t> &Val1,
419421 return true ;
420422}
421423
422- static Messages getExceedsMsgs (ASTContext &ACtx, const MemSpaceRegion *Space,
423- const SubRegion *Region, NonLoc Offset,
424- NonLoc Extent, SVal Location,
425- bool AlsoMentionUnderflow) {
424+ static Messages getNonTaintMsgs (const ASTContext &ACtx,
425+ const MemSpaceRegion *Space,
426+ const SubRegion *Region, NonLoc Offset,
427+ std::optional<NonLoc> Extent, SVal Location,
428+ BadOffsetKind Problem) {
426429 std::string RegName = getRegionName (Space, Region);
427430 const auto *EReg = Location.getAsRegion ()->getAs <ElementRegion>();
428431 assert (EReg && " this checker only handles element access" );
@@ -439,15 +442,21 @@ static Messages getExceedsMsgs(ASTContext &ACtx, const MemSpaceRegion *Space,
439442 SmallString<256 > Buf;
440443 llvm::raw_svector_ostream Out (Buf);
441444 Out << " Access of " ;
442- if (!ExtentN && !UseByteOffsets)
445+ if (OffsetN && !ExtentN && !UseByteOffsets) {
446+ // If the offset is reported as an index, then the report must mention the
447+ // element type (because it is not always clear from the code). It's more
448+ // natural to mention the element type later where the extent is described,
449+ // but if the extent is unknown/irrelevant, then the element type can be
450+ // inserted into the message at this point.
443451 Out << " '" << ElemType.getAsString () << " ' element in " ;
452+ }
444453 Out << RegName << " at " ;
445- if (AlsoMentionUnderflow ) {
446- Out << " a negative or overflowing " << OffsetOrIndex;
447- } else if (OffsetN) {
454+ if (OffsetN ) {
455+ if (Problem == BadOffsetKind::Negative)
456+ Out << " negative " ;
448457 Out << OffsetOrIndex << " " << *OffsetN;
449458 } else {
450- Out << " an overflowing " << OffsetOrIndex;
459+ Out << asAdjective (Problem) << " " << OffsetOrIndex;
451460 }
452461 if (ExtentN) {
453462 Out << " , while it holds only " ;
@@ -465,8 +474,7 @@ static Messages getExceedsMsgs(ASTContext &ACtx, const MemSpaceRegion *Space,
465474 }
466475
467476 return {formatv (" Out of bound access to memory {0} {1}" ,
468- AlsoMentionUnderflow ? " around" : " after the end of" ,
469- RegName),
477+ asPreposition (Problem), RegName),
470478 std::string (Buf)};
471479}
472480
@@ -635,7 +643,9 @@ void ArrayBoundChecker::performCheck(const Expr *E, CheckerContext &C) const {
635643 } else {
636644 if (!WithinLowerBound) {
637645 // ...and it cannot be valid (>= 0), so report an error.
638- Messages Msgs = getPrecedesMsgs (Space, Reg, ByteOffset);
646+ Messages Msgs = getNonTaintMsgs (C.getASTContext (), Space, Reg,
647+ ByteOffset, /* Extent=*/ std::nullopt ,
648+ Location, BadOffsetKind::Negative);
639649 reportOOB (C, PrecedesLowerBound, Msgs, ByteOffset, std::nullopt );
640650 return ;
641651 }
@@ -677,9 +687,12 @@ void ArrayBoundChecker::performCheck(const Expr *E, CheckerContext &C) const {
677687 return ;
678688 }
679689
690+ BadOffsetKind Problem = AlsoMentionUnderflow
691+ ? BadOffsetKind::Indeterminate
692+ : BadOffsetKind::Overflowing;
680693 Messages Msgs =
681- getExceedsMsgs (C.getASTContext (), Space, Reg, ByteOffset,
682- *KnownSize, Location, AlsoMentionUnderflow );
694+ getNonTaintMsgs (C.getASTContext (), Space, Reg, ByteOffset,
695+ *KnownSize, Location, Problem );
683696 reportOOB (C, ExceedsUpperBound, Msgs, ByteOffset, KnownSize);
684697 return ;
685698 }
0 commit comments