================
@@ -2243,6 +2246,102 @@ void CStringChecker::evalStrcpyCommon(CheckerContext
&C, const CallEvent &Call,
C.addTransition(state);
}
+void CStringChecker::evalStrxfrm(CheckerContext &C,
+ const CallEvent &Call) const {
+ // size_t strxfrm(char *dest, const char *src, size_t n);
+ CurrentFunctionDescription = "locale transformation function";
+
+ ProgramStateRef State = C.getState();
+ const LocationContext *LCtx = C.getLocationContext();
+ SValBuilder &SVB = C.getSValBuilder();
+
+ // Get arguments
+ DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
+ SourceArgExpr Source = {{Call.getArgExpr(1), 1}};
+ SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
+
+ // `src` can never be null
+ SVal SrcVal = State->getSVal(Source.Expression, LCtx);
+ State = checkNonNull(C, State, Source, SrcVal);
+ if (!State)
+ return;
+
+ // Check overlaps
+ State = CheckOverlap(C, State, Size, Dest, Source, CK_Regular);
+ if (!State)
+ return;
+
+ // The function returns an implementation-defined length needed for
+ // transformation
+ SVal RetVal = SVB.conjureSymbolVal(Call, C.blockCount());
+
+ State = State->BindExpr(Call.getOriginExpr(), LCtx, RetVal);
+
+ // Check if size is zero
+ SVal SizeVal = State->getSVal(Size.Expression, LCtx);
+ QualType SizeTy = Size.Expression->getType();
+
+ auto [StateZeroSize, StateSizeNonZero] =
+ assumeZero(C, State, SizeVal, SizeTy);
+
+ // If `n` is 0, we just return the implementation defined length
+ if (StateZeroSize && !StateSizeNonZero) {
+ C.addTransition(StateZeroSize);
+ return;
+ }
+
+ if (!StateSizeNonZero)
+ return;
+
+ // If `n` is not 0, `dest` can not be null.
+ SVal DestVal = State->getSVal(Dest.Expression, LCtx);
+ StateSizeNonZero = checkNonNull(C, StateSizeNonZero, Dest, DestVal);
+ if (!StateSizeNonZero)
+ return;
+
+ // Check that we can write to the destination buffer
+ StateSizeNonZero = CheckBufferAccess(C, StateSizeNonZero, Dest, Size,
+ AccessKind::write, CK_Regular);
+ if (!StateSizeNonZero)
+ return;
+
+ // Success: return value < `n`
+ // Failure: return value >= `n`
+ auto ComparisonVal = SVB.evalBinOp(StateSizeNonZero, BO_LT, RetVal, SizeVal,
+ SVB.getConditionType())
+ .getAs<DefinedOrUnknownSVal>();
+
+ if (ComparisonVal) {
+ auto [StateSuccess, StateFailure] =
+ StateSizeNonZero->assume(*ComparisonVal);
+
+ if (StateSuccess) {
+ // In this case, the transformation invalidated the buffer.
+ StateSuccess = invalidateDestinationBufferBySize(
+ C, StateSuccess, Dest.Expression, Call.getCFGElementRef(), DestVal,
+ SizeVal, Size.Expression->getType());
+
+ C.addTransition(StateSuccess);
+ }
+
+ if (StateFailure) {
+ // In this case, dest buffer content is undefined
+ if (std::optional<Loc> DestLoc = DestVal.getAs<Loc>()) {
+ StateFailure = StateFailure->bindLoc(*DestLoc, UndefinedVal{}, LCtx);
+ }
----------------
balazs-benics-sonarsource wrote:
Wouldn't this only mark the first element (byte) undefined? Could you please
check the Store of the buffer in this case?
https://github.com/llvm/llvm-project/pull/156507
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits