@@ -83,6 +83,8 @@ class StateUpdateReporter {
83
83
AssumedUpperBound = UpperBoundVal;
84
84
}
85
85
86
+ bool assumedNonNegative () { return AssumedNonNegative; }
87
+
86
88
const NoteTag *createNoteTag (CheckerContext &C) const ;
87
89
88
90
private:
@@ -402,7 +404,8 @@ static bool tryDividePair(std::optional<int64_t> &Val1,
402
404
}
403
405
404
406
static Messages getExceedsMsgs (ASTContext &ACtx, const SubRegion *Region,
405
- NonLoc Offset, NonLoc Extent, SVal Location) {
407
+ NonLoc Offset, NonLoc Extent, SVal Location,
408
+ bool AlsoMentionUnderflow) {
406
409
std::string RegName = getRegionName (Region);
407
410
const auto *EReg = Location.getAsRegion ()->getAs <ElementRegion>();
408
411
assert (EReg && " this checker only handles element access" );
@@ -414,17 +417,20 @@ static Messages getExceedsMsgs(ASTContext &ACtx, const SubRegion *Region,
414
417
int64_t ElemSize = ACtx.getTypeSizeInChars (ElemType).getQuantity ();
415
418
416
419
bool UseByteOffsets = !tryDividePair (OffsetN, ExtentN, ElemSize);
420
+ const char *OffsetOrIndex = UseByteOffsets ? " byte offset" : " index" ;
417
421
418
422
SmallString<256 > Buf;
419
423
llvm::raw_svector_ostream Out (Buf);
420
424
Out << " Access of " ;
421
425
if (!ExtentN && !UseByteOffsets)
422
426
Out << " '" << ElemType.getAsString () << " ' element in " ;
423
427
Out << RegName << " at " ;
424
- if (OffsetN) {
425
- Out << (UseByteOffsets ? " byte offset " : " index " ) << *OffsetN;
428
+ if (AlsoMentionUnderflow) {
429
+ Out << " a negative or overflowing " << OffsetOrIndex;
430
+ } else if (OffsetN) {
431
+ Out << OffsetOrIndex << " " << *OffsetN;
426
432
} else {
427
- Out << " an overflowing " << (UseByteOffsets ? " byte offset " : " index " ) ;
433
+ Out << " an overflowing " << OffsetOrIndex ;
428
434
}
429
435
if (ExtentN) {
430
436
Out << " , while it holds only " ;
@@ -441,17 +447,20 @@ static Messages getExceedsMsgs(ASTContext &ACtx, const SubRegion *Region,
441
447
Out << " s" ;
442
448
}
443
449
444
- return {
445
- formatv (" Out of bound access to memory after the end of {0}" , RegName),
446
- std::string (Buf)};
450
+ return {formatv (" Out of bound access to memory {0} {1}" ,
451
+ AlsoMentionUnderflow ? " around" : " after the end of" ,
452
+ RegName),
453
+ std::string (Buf)};
447
454
}
448
455
449
- static Messages getTaintMsgs (const SubRegion *Region, const char *OffsetName) {
456
+ static Messages getTaintMsgs (const SubRegion *Region, const char *OffsetName,
457
+ bool AlsoMentionUnderflow) {
450
458
std::string RegName = getRegionName (Region);
451
459
return {formatv (" Potential out of bound access to {0} with tainted {1}" ,
452
460
RegName, OffsetName),
453
- formatv (" Access of {0} with a tainted {1} that may be too large" ,
454
- RegName, OffsetName)};
461
+ formatv (" Access of {0} with a tainted {1} that may be {2}too large" ,
462
+ RegName, OffsetName,
463
+ AlsoMentionUnderflow ? " negative or " : " " )};
455
464
}
456
465
457
466
const NoteTag *StateUpdateReporter::createNoteTag (CheckerContext &C) const {
@@ -600,6 +609,13 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, CheckerContext &C) const {
600
609
// CHECK UPPER BOUND
601
610
DefinedOrUnknownSVal Size = getDynamicExtent (State, Reg, SVB);
602
611
if (auto KnownSize = Size.getAs <NonLoc>()) {
612
+ // In a situation where both overflow and overflow are possible (but the
613
+ // index is either tainted or known to be invalid), the logic of this
614
+ // checker will first assume that the offset is non-negative, and then
615
+ // (with this additional assumption) it will detect an overflow error.
616
+ // In this situation the warning message should mention both possibilities.
617
+ bool AlsoMentionUnderflow = SUR.assumedNonNegative ();
618
+
603
619
auto [WithinUpperBound, ExceedsUpperBound] =
604
620
compareValueToThreshold (State, ByteOffset, *KnownSize, SVB);
605
621
@@ -615,8 +631,9 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, CheckerContext &C) const {
615
631
return ;
616
632
}
617
633
618
- Messages Msgs = getExceedsMsgs (C.getASTContext (), Reg, ByteOffset,
619
- *KnownSize, Location);
634
+ Messages Msgs =
635
+ getExceedsMsgs (C.getASTContext (), Reg, ByteOffset, *KnownSize,
636
+ Location, AlsoMentionUnderflow);
620
637
reportOOB (C, ExceedsUpperBound, Msgs, ByteOffset, KnownSize);
621
638
return ;
622
639
}
@@ -632,7 +649,7 @@ void ArrayBoundCheckerV2::performCheck(const Expr *E, CheckerContext &C) const {
632
649
if (isTainted (State, ASE->getIdx (), C.getLocationContext ()))
633
650
OffsetName = " index" ;
634
651
635
- Messages Msgs = getTaintMsgs (Reg, OffsetName);
652
+ Messages Msgs = getTaintMsgs (Reg, OffsetName, AlsoMentionUnderflow );
636
653
reportOOB (C, ExceedsUpperBound, Msgs, ByteOffset, KnownSize,
637
654
/* IsTaintBug=*/ true );
638
655
return ;
0 commit comments