@@ -588,14 +588,8 @@ class EstimateSizeFormatHandler
588
588
589
589
} // namespace
590
590
591
- /// Check a call to BuiltinID for buffer overflows. If BuiltinID is a
592
- /// __builtin_*_chk function, then use the object size argument specified in the
593
- /// source. Otherwise, infer the object size using __builtin_object_size.
594
591
void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
595
592
CallExpr *TheCall) {
596
- // FIXME: There are some more useful checks we could be doing here:
597
- // - Evaluate strlen of strcpy arguments, use as object size.
598
-
599
593
if (TheCall->isValueDependent() || TheCall->isTypeDependent() ||
600
594
isConstantEvaluated())
601
595
return;
@@ -607,13 +601,66 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
607
601
const TargetInfo &TI = getASTContext().getTargetInfo();
608
602
unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType());
609
603
604
+ auto ComputeExplicitObjectSizeArgument =
605
+ [&](unsigned Index) -> Optional<llvm::APSInt> {
606
+ Expr::EvalResult Result;
607
+ Expr *SizeArg = TheCall->getArg(Index);
608
+ if (!SizeArg->EvaluateAsInt(Result, getASTContext()))
609
+ return llvm::None;
610
+ return Result.Val.getInt();
611
+ };
612
+
613
+ auto ComputeSizeArgument = [&](unsigned Index) -> Optional<llvm::APSInt> {
614
+ // If the parameter has a pass_object_size attribute, then we should use its
615
+ // (potentially) more strict checking mode. Otherwise, conservatively assume
616
+ // type 0.
617
+ int BOSType = 0;
618
+ if (const auto *POS =
619
+ FD->getParamDecl(Index)->getAttr<PassObjectSizeAttr>())
620
+ BOSType = POS->getType();
621
+
622
+ const Expr *ObjArg = TheCall->getArg(Index);
623
+ uint64_t Result;
624
+ if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType))
625
+ return llvm::None;
626
+
627
+ // Get the object size in the target's size_t width.
628
+ return llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth);
629
+ };
630
+
631
+ auto ComputeStrLenArgument = [&](unsigned Index) -> Optional<llvm::APSInt> {
632
+ Expr *ObjArg = TheCall->getArg(Index);
633
+ uint64_t Result;
634
+ if (!ObjArg->tryEvaluateStrLen(Result, getASTContext()))
635
+ return llvm::None;
636
+ // Add 1 for null byte.
637
+ return llvm::APSInt::getUnsigned(Result + 1).extOrTrunc(SizeTypeWidth);
638
+ };
639
+
640
+ Optional<llvm::APSInt> SourceSize;
641
+ Optional<llvm::APSInt> DestinationSize;
610
642
unsigned DiagID = 0;
611
643
bool IsChkVariant = false;
612
- Optional<llvm::APSInt> UsedSize;
613
- unsigned SizeIndex, ObjectIndex;
644
+
614
645
switch (BuiltinID) {
615
646
default:
616
647
return;
648
+ case Builtin::BI__builtin_strcpy:
649
+ case Builtin::BIstrcpy: {
650
+ DiagID = diag::warn_fortify_strlen_overflow;
651
+ SourceSize = ComputeStrLenArgument(1);
652
+ DestinationSize = ComputeSizeArgument(0);
653
+ break;
654
+ }
655
+
656
+ case Builtin::BI__builtin___strcpy_chk: {
657
+ DiagID = diag::warn_fortify_strlen_overflow;
658
+ SourceSize = ComputeStrLenArgument(1);
659
+ DestinationSize = ComputeExplicitObjectSizeArgument(2);
660
+ IsChkVariant = true;
661
+ break;
662
+ }
663
+
617
664
case Builtin::BIsprintf:
618
665
case Builtin::BI__builtin___sprintf_chk: {
619
666
size_t FormatIndex = BuiltinID == Builtin::BIsprintf ? 1 : 3;
@@ -639,14 +686,13 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
639
686
H, FormatBytes, FormatBytes + StrLen, getLangOpts(),
640
687
Context.getTargetInfo(), false)) {
641
688
DiagID = diag::warn_fortify_source_format_overflow;
642
- UsedSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound())
643
- .extOrTrunc(SizeTypeWidth);
689
+ SourceSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound())
690
+ .extOrTrunc(SizeTypeWidth);
644
691
if (BuiltinID == Builtin::BI__builtin___sprintf_chk) {
692
+ DestinationSize = ComputeExplicitObjectSizeArgument(2);
645
693
IsChkVariant = true;
646
- ObjectIndex = 2;
647
694
} else {
648
- IsChkVariant = false;
649
- ObjectIndex = 0;
695
+ DestinationSize = ComputeSizeArgument(0);
650
696
}
651
697
break;
652
698
}
@@ -664,18 +710,19 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
664
710
case Builtin::BI__builtin___memccpy_chk:
665
711
case Builtin::BI__builtin___mempcpy_chk: {
666
712
DiagID = diag::warn_builtin_chk_overflow;
713
+ SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 2);
714
+ DestinationSize =
715
+ ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1);
667
716
IsChkVariant = true;
668
- SizeIndex = TheCall->getNumArgs() - 2;
669
- ObjectIndex = TheCall->getNumArgs() - 1;
670
717
break;
671
718
}
672
719
673
720
case Builtin::BI__builtin___snprintf_chk:
674
721
case Builtin::BI__builtin___vsnprintf_chk: {
675
722
DiagID = diag::warn_builtin_chk_overflow;
723
+ SourceSize = ComputeExplicitObjectSizeArgument(1);
724
+ DestinationSize = ComputeExplicitObjectSizeArgument(3);
676
725
IsChkVariant = true;
677
- SizeIndex = 1;
678
- ObjectIndex = 3;
679
726
break;
680
727
}
681
728
@@ -691,8 +738,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
691
738
// size larger than the destination buffer though; this is a runtime abort
692
739
// in _FORTIFY_SOURCE mode, and is quite suspicious otherwise.
693
740
DiagID = diag::warn_fortify_source_size_mismatch;
694
- SizeIndex = TheCall->getNumArgs() - 1;
695
- ObjectIndex = 0 ;
741
+ SourceSize = ComputeExplicitObjectSizeArgument( TheCall->getNumArgs() - 1) ;
742
+ DestinationSize = ComputeSizeArgument(0) ;
696
743
break;
697
744
}
698
745
@@ -705,59 +752,23 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
705
752
case Builtin::BImempcpy:
706
753
case Builtin::BI__builtin_mempcpy: {
707
754
DiagID = diag::warn_fortify_source_overflow;
708
- SizeIndex = TheCall->getNumArgs() - 1;
709
- ObjectIndex = 0 ;
755
+ SourceSize = ComputeExplicitObjectSizeArgument( TheCall->getNumArgs() - 1) ;
756
+ DestinationSize = ComputeSizeArgument(0) ;
710
757
break;
711
758
}
712
759
case Builtin::BIsnprintf:
713
760
case Builtin::BI__builtin_snprintf:
714
761
case Builtin::BIvsnprintf:
715
762
case Builtin::BI__builtin_vsnprintf: {
716
763
DiagID = diag::warn_fortify_source_size_mismatch;
717
- SizeIndex = 1 ;
718
- ObjectIndex = 0 ;
764
+ SourceSize = ComputeExplicitObjectSizeArgument(1) ;
765
+ DestinationSize = ComputeSizeArgument(0) ;
719
766
break;
720
767
}
721
768
}
722
769
723
- llvm::APSInt ObjectSize;
724
- // For __builtin___*_chk, the object size is explicitly provided by the caller
725
- // (usually using __builtin_object_size). Use that value to check this call.
726
- if (IsChkVariant) {
727
- Expr::EvalResult Result;
728
- Expr *SizeArg = TheCall->getArg(ObjectIndex);
729
- if (!SizeArg->EvaluateAsInt(Result, getASTContext()))
730
- return;
731
- ObjectSize = Result.Val.getInt();
732
-
733
- // Otherwise, try to evaluate an imaginary call to __builtin_object_size.
734
- } else {
735
- // If the parameter has a pass_object_size attribute, then we should use its
736
- // (potentially) more strict checking mode. Otherwise, conservatively assume
737
- // type 0.
738
- int BOSType = 0;
739
- if (const auto *POS =
740
- FD->getParamDecl(ObjectIndex)->getAttr<PassObjectSizeAttr>())
741
- BOSType = POS->getType();
742
-
743
- Expr *ObjArg = TheCall->getArg(ObjectIndex);
744
- uint64_t Result;
745
- if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType))
746
- return;
747
- // Get the object size in the target's size_t width.
748
- ObjectSize = llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth);
749
- }
750
-
751
- // Evaluate the number of bytes of the object that this call will use.
752
- if (!UsedSize) {
753
- Expr::EvalResult Result;
754
- Expr *UsedSizeArg = TheCall->getArg(SizeIndex);
755
- if (!UsedSizeArg->EvaluateAsInt(Result, getASTContext()))
756
- return;
757
- UsedSize = Result.Val.getInt().extOrTrunc(SizeTypeWidth);
758
- }
759
-
760
- if (UsedSize.getValue().ule(ObjectSize))
770
+ if (!SourceSize || !DestinationSize ||
771
+ SourceSize.getValue().ule(DestinationSize.getValue()))
761
772
return;
762
773
763
774
StringRef FunctionName = getASTContext().BuiltinInfo.getName(BuiltinID);
@@ -770,10 +781,13 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
770
781
FunctionName = FunctionName.drop_front(std::strlen("__builtin_"));
771
782
}
772
783
784
+ SmallString<16> DestinationStr;
785
+ SmallString<16> SourceStr;
786
+ DestinationSize->toString(DestinationStr, /*Radix=*/10);
787
+ SourceSize->toString(SourceStr, /*Radix=*/10);
773
788
DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall,
774
789
PDiag(DiagID)
775
- << FunctionName << toString(ObjectSize, /*Radix=*/10)
776
- << toString(UsedSize.getValue(), /*Radix=*/10));
790
+ << FunctionName << DestinationStr << SourceStr);
777
791
}
778
792
779
793
static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall,
0 commit comments