================ @@ -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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits