@@ -251,6 +251,8 @@ class CStringChecker
251251 const Expr *Ex,
252252 const MemRegion *MR,
253253 bool hypothetical);
254+ static const StringLiteral *getStringLiteralFromRegion (const MemRegion *MR);
255+
254256 SVal getCStringLength (CheckerContext &C,
255257 ProgramStateRef &state,
256258 const Expr *Ex,
@@ -983,6 +985,21 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
983985 return strLength;
984986}
985987
988+ const StringLiteral *
989+ CStringChecker::getStringLiteralFromRegion (const MemRegion *MR) {
990+ switch (MR->getKind ()) {
991+ case MemRegion::StringRegionKind:
992+ return cast<StringRegion>(MR)->getStringLiteral ();
993+ case MemRegion::NonParamVarRegionKind:
994+ if (const VarDecl *Decl = cast<NonParamVarRegion>(MR)->getDecl ();
995+ Decl->getType ().isConstQualified () && Decl->hasGlobalStorage ())
996+ return dyn_cast_or_null<StringLiteral>(Decl->getInit ());
997+ return nullptr ;
998+ default :
999+ return nullptr ;
1000+ }
1001+ }
1002+
9861003SVal CStringChecker::getCStringLength (CheckerContext &C, ProgramStateRef &state,
9871004 const Expr *Ex, SVal Buf,
9881005 bool hypothetical) const {
@@ -1013,30 +1030,19 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
10131030 // its length. For anything we can't figure out, just return UnknownVal.
10141031 MR = MR->StripCasts ();
10151032
1016- switch (MR->getKind ()) {
1017- case MemRegion::StringRegionKind: {
1018- // Modifying the contents of string regions is undefined [C99 6.4.5p6],
1019- // so we can assume that the byte length is the correct C string length.
1020- SValBuilder &svalBuilder = C.getSValBuilder ();
1021- QualType sizeTy = svalBuilder.getContext ().getSizeType ();
1022- const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral ();
1023- return svalBuilder.makeIntVal (strLit->getLength (), sizeTy);
1024- }
1025- case MemRegion::NonParamVarRegionKind: {
1033+ if (const StringLiteral *StrLit = getStringLiteralFromRegion (MR)) {
10261034 // If we have a global constant with a string literal initializer,
10271035 // compute the initializer's length.
1028- const VarDecl *Decl = cast<NonParamVarRegion>(MR)->getDecl ();
1029- if (Decl->getType ().isConstQualified () && Decl->hasGlobalStorage ()) {
1030- if (const Expr *Init = Decl->getInit ()) {
1031- if (auto *StrLit = dyn_cast<StringLiteral>(Init)) {
1032- SValBuilder &SvalBuilder = C.getSValBuilder ();
1033- QualType SizeTy = SvalBuilder.getContext ().getSizeType ();
1034- return SvalBuilder.makeIntVal (StrLit->getLength (), SizeTy);
1035- }
1036- }
1037- }
1038- [[fallthrough]];
1036+ // Modifying the contents of string regions is undefined [C99 6.4.5p6],
1037+ // so we can assume that the byte length is the correct C string length.
1038+ // FIXME: Embedded null characters are not handled.
1039+ SValBuilder &SVB = C.getSValBuilder ();
1040+ return SVB.makeIntVal (StrLit->getLength (), SVB.getContext ().getSizeType ());
10391041 }
1042+
1043+ switch (MR->getKind ()) {
1044+ case MemRegion::StringRegionKind:
1045+ case MemRegion::NonParamVarRegionKind:
10401046 case MemRegion::SymbolicRegionKind:
10411047 case MemRegion::AllocaRegionKind:
10421048 case MemRegion::ParamVarRegionKind:
@@ -1046,10 +1052,28 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
10461052 case MemRegion::CompoundLiteralRegionKind:
10471053 // FIXME: Can we track this? Is it necessary?
10481054 return UnknownVal ();
1049- case MemRegion::ElementRegionKind:
1050- // FIXME: How can we handle this? It's not good enough to subtract the
1051- // offset from the base string length; consider "123\x00567" and &a[5].
1055+ case MemRegion::ElementRegionKind: {
1056+ // If an offset into the string literal is used, use the original length
1057+ // minus the offset.
1058+ // FIXME: Embedded null characters are not handled.
1059+ const ElementRegion *ER = cast<ElementRegion>(MR);
1060+ const SubRegion *SuperReg =
1061+ cast<SubRegion>(ER->getSuperRegion ()->StripCasts ());
1062+ const StringLiteral *StrLit = getStringLiteralFromRegion (SuperReg);
1063+ if (!StrLit)
1064+ return UnknownVal ();
1065+ SValBuilder &SVB = C.getSValBuilder ();
1066+ NonLoc Idx = ER->getIndex ();
1067+ QualType SizeTy = SVB.getContext ().getSizeType ();
1068+ NonLoc LengthVal =
1069+ SVB.makeIntVal (StrLit->getLength (), SizeTy).castAs <NonLoc>();
1070+ if (state->assume (SVB.evalBinOpNN (state, BO_LE, Idx, LengthVal,
1071+ SVB.getConditionType ())
1072+ .castAs <DefinedOrUnknownSVal>(),
1073+ true ))
1074+ return SVB.evalBinOp (state, BO_Sub, LengthVal, Idx, SizeTy);
10521075 return UnknownVal ();
1076+ }
10531077 default :
10541078 // Other regions (mostly non-data) can't have a reliable C string length.
10551079 // In this case, an error is emitted and UndefinedVal is returned.
@@ -1074,6 +1098,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
10741098
10751099const StringLiteral *CStringChecker::getCStringLiteral (CheckerContext &C,
10761100 ProgramStateRef &state, const Expr *expr, SVal val) const {
1101+ // FIXME: use getStringLiteralFromRegion (and remove unused parameters)?
10771102
10781103 // Get the memory region pointed to by the val.
10791104 const MemRegion *bufRegion = val.getAsRegion ();
0 commit comments