[clang] ddc5d40 - [clang][analyzer] Make messages of StdCLibraryFunctionsChecker user-friendly
Balázs Kéri via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 15 00:23:41 PST 2023
Author: Balázs Kéri
Date: 2023-02-15T09:22:48+01:00
New Revision: ddc5d40dd285d6422dc66b9aa25064502af3218b
URL: https://github.com/llvm/llvm-project/commit/ddc5d40dd285d6422dc66b9aa25064502af3218b
DIFF: https://github.com/llvm/llvm-project/commit/ddc5d40dd285d6422dc66b9aa25064502af3218b.diff
LOG: [clang][analyzer] Make messages of StdCLibraryFunctionsChecker user-friendly
Warnings and notes of checker alpha.unix.StdLibraryFunctionArgs are
improved. Previously one warning and one note was emitted for every
finding, now one warning is emitted only that contains a detailed
description of the found issue.
Reviewed By: Szelethus
Differential Revision: https://reviews.llvm.org/D143194
Added:
Modified:
clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp
clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
clang/test/Analysis/std-c-library-functions-arg-constraints.c
clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
clang/test/Analysis/stream-note.c
clang/test/Analysis/stream-stdlibraryfunctionargs.c
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 49b3db560843d..b36f72f2653c7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -84,9 +84,20 @@ class StdLibraryFunctionsChecker
typedef uint32_t ArgNo;
static const ArgNo Ret;
+ using DescString = SmallString<96>;
/// Returns the string representation of an argument index.
/// E.g.: (1) -> '1st arg', (2) - > '2nd arg'
static SmallString<8> getArgDesc(ArgNo);
+ /// Append textual description of a numeric range [RMin,RMax] to the string
+ /// 'Out'.
+ static void appendInsideRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
+ QualType ArgT, BasicValueFactory &BVF,
+ DescString &Out);
+ /// Append textual description of a numeric range out of [RMin,RMax] to the
+ /// string 'Out'.
+ static void appendOutOfRangeDesc(llvm::APSInt RMin, llvm::APSInt RMax,
+ QualType ArgT, BasicValueFactory &BVF,
+ DescString &Out);
class ValueConstraint;
@@ -101,6 +112,12 @@ class StdLibraryFunctionsChecker
/// (or return value) of a function. Derived classes implement
diff erent kind
/// of constraints, e.g range constraints or correlation between two
/// arguments.
+ /// These are used as argument constraints (preconditions) of functions, in
+ /// which case a bug report may be emitted if the constraint is not satisfied.
+ /// Another use is as conditions for summary cases, to create
diff erent
+ /// classes of behavior for a function. In this case no description of the
+ /// constraint is needed because the summary cases have an own (not generated)
+ /// description string.
class ValueConstraint {
public:
ValueConstraint(ArgNo ArgN) : ArgN(ArgN) {}
@@ -114,9 +131,9 @@ class StdLibraryFunctionsChecker
llvm_unreachable("Not implemented");
};
- // Check whether the constraint is malformed or not. It is malformed if the
- // specified argument has a mismatch with the given FunctionDecl (e.g. the
- // arg number is out-of-range of the function's argument list).
+ /// Check whether the constraint is malformed or not. It is malformed if the
+ /// specified argument has a mismatch with the given FunctionDecl (e.g. the
+ /// arg number is out-of-range of the function's argument list).
bool checkValidity(const FunctionDecl *FD) const {
const bool ValidArg = ArgN == Ret || ArgN < FD->getNumParams();
assert(ValidArg && "Arg out of range!");
@@ -127,31 +144,34 @@ class StdLibraryFunctionsChecker
}
ArgNo getArgNo() const { return ArgN; }
- // Return those arguments that should be tracked when we report a bug. By
- // default it is the argument that is constrained, however, in some special
- // cases we need to track other arguments as well. E.g. a buffer size might
- // be encoded in another argument.
+ /// Return those arguments that should be tracked when we report a bug. By
+ /// default it is the argument that is constrained, however, in some special
+ /// cases we need to track other arguments as well. E.g. a buffer size might
+ /// be encoded in another argument.
virtual std::vector<ArgNo> getArgsToTrack() const { return {ArgN}; }
virtual StringRef getName() const = 0;
- // Represents that in which context do we require a description of the
- // constraint.
+ /// Represents that in which context do we require a description of the
+ /// constraint.
enum class DescriptionKind {
- // The constraint is violated.
+ /// The constraint is violated.
Violation,
- // We assume that the constraint is satisfied.
+ /// We assume that the constraint is satisfied.
Assumption
};
- // Give a description that explains the constraint to the user. Used when
- // the bug is reported.
- virtual std::string describe(DescriptionKind DK, ProgramStateRef State,
+ /// Give a description that explains the constraint to the user. Used when
+ /// a bug is reported or when the constraint is applied and displayed as a
+ /// note.
+ virtual std::string describe(DescriptionKind DK, const CallEvent &Call,
+ ProgramStateRef State,
const Summary &Summary) const {
// There are some descendant classes that are not used as argument
// constraints, e.g. ComparisonConstraint. In that case we can safely
// ignore the implementation of this function.
- llvm_unreachable("Not implemented");
+ llvm_unreachable(
+ "Description not implemented for summary case constraints");
}
protected:
@@ -178,13 +198,19 @@ class StdLibraryFunctionsChecker
// type (e.g. [0, Socklen_tMax]). If the type is not found, then the range
// is default initialized to be empty.
IntRangeVector Ranges;
+ // A textual description of this constraint for the specific case where the
+ // constraint is used. If empty a generated description will be used.
+ StringRef Description;
public:
StringRef getName() const override { return "Range"; }
- RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges)
- : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {}
+ RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges,
+ StringRef Desc = "")
+ : ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges), Description(Desc) {
+ }
- std::string describe(DescriptionKind DK, ProgramStateRef State,
+ std::string describe(DescriptionKind DK, const CallEvent &Call,
+ ProgramStateRef State,
const Summary &Summary) const override;
const IntRangeVector &getRanges() const { return Ranges; }
@@ -256,7 +282,8 @@ class StdLibraryFunctionsChecker
public:
NotNullConstraint(ArgNo ArgN, bool CannotBeNull = true)
: ValueConstraint(ArgN), CannotBeNull(CannotBeNull) {}
- std::string describe(DescriptionKind DK, ProgramStateRef State,
+ std::string describe(DescriptionKind DK, const CallEvent &Call,
+ ProgramStateRef State,
const Summary &Summary) const override;
StringRef getName() const override { return "NonNull"; }
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
@@ -328,7 +355,8 @@ class StdLibraryFunctionsChecker
return Result;
}
- std::string describe(DescriptionKind DK, ProgramStateRef State,
+ std::string describe(DescriptionKind DK, const CallEvent &Call,
+ ProgramStateRef State,
const Summary &Summary) const override;
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
@@ -698,6 +726,11 @@ class StdLibraryFunctionsChecker
static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
return ArgN == Ret ? Call.getReturnValue() : Call.getArgSVal(ArgN);
}
+ static std::string getFunctionName(const CallEvent &Call) {
+ assert(Call.getDecl() &&
+ "Call was found by a summary, should have declaration");
+ return cast<NamedDecl>(Call.getDecl())->getNameAsString();
+ }
public:
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
@@ -729,28 +762,22 @@ class StdLibraryFunctionsChecker
CheckerContext &C) const {
if (!ChecksEnabled[CK_StdCLibraryFunctionArgsChecker])
return;
- std::string Msg =
- (Twine("Function argument constraint is not satisfied, constraint: ") +
- VC->getName().data())
- .str();
+ assert(Call.getDecl() &&
+ "Function found in summary must have a declaration available");
+ std::string Msg = VC->describe(ValueConstraint::DescriptionKind::Violation,
+ Call, C.getState(), Summary);
+ Msg[0] = toupper(Msg[0]);
if (!BT_InvalidArg)
BT_InvalidArg = std::make_unique<BugType>(
CheckNames[CK_StdCLibraryFunctionArgsChecker],
- "Unsatisfied argument constraints", categories::LogicError);
+ "Function call with invalid argument", categories::LogicError);
auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
- for (ArgNo ArgN : VC->getArgsToTrack())
+ for (ArgNo ArgN : VC->getArgsToTrack()) {
bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
-
- // Highlight the range of the argument that was violated.
- R->addRange(Call.getArgSourceRange(VC->getArgNo()));
-
- // Describe the argument constraint violation in a note.
- std::string Descr = VC->describe(
- ValueConstraint::DescriptionKind::Violation, C.getState(), Summary);
- // Capitalize the first letter b/c we want a full sentence.
- Descr[0] = toupper(Descr[0]);
- R->addNote(Descr, R->getLocation(), Call.getArgSourceRange(VC->getArgNo()));
+ // All tracked arguments are important, highlight them.
+ R->addRange(Call.getArgSourceRange(ArgN));
+ }
C.emitReport(std::move(R));
}
@@ -772,82 +799,170 @@ int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
const StdLibraryFunctionsChecker::ArgNo StdLibraryFunctionsChecker::Ret =
std::numeric_limits<ArgNo>::max();
-} // end of anonymous namespace
-
static BasicValueFactory &getBVF(ProgramStateRef State) {
ProgramStateManager &Mgr = State->getStateManager();
SValBuilder &SVB = Mgr.getSValBuilder();
return SVB.getBasicValueFactory();
}
+} // end of anonymous namespace
+
+SmallString<8>
+StdLibraryFunctionsChecker::getArgDesc(StdLibraryFunctionsChecker::ArgNo ArgN) {
+ SmallString<8> Result;
+ Result += std::to_string(ArgN + 1);
+ Result += llvm::getOrdinalSuffix(ArgN + 1);
+ Result += " argument";
+ return Result;
+}
+
+void StdLibraryFunctionsChecker::appendInsideRangeDesc(llvm::APSInt RMin,
+ llvm::APSInt RMax,
+ QualType ArgT,
+ BasicValueFactory &BVF,
+ DescString &Out) {
+ if (RMin.isZero() && RMax.isZero())
+ Out.append("zero");
+ else if (RMin == RMax)
+ RMin.toString(Out);
+ else if (RMin == BVF.getMinValue(ArgT)) {
+ if (RMax == -1)
+ Out.append("< 0");
+ else {
+ Out.append("<= ");
+ RMax.toString(Out);
+ }
+ } else if (RMax == BVF.getMaxValue(ArgT)) {
+ if (RMin.isOne())
+ Out.append("> 0");
+ else {
+ Out.append(">= ");
+ RMin.toString(Out);
+ }
+ } else if (RMin.isNegative() == RMax.isNegative() &&
+ RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
+ RMin.toString(Out);
+ Out.append(" or ");
+ RMax.toString(Out);
+ } else if (RMin.isNegative() == RMax.isNegative() &&
+ RMin.getLimitedValue() == RMax.getLimitedValue() - 2) {
+ RMin.toString(Out);
+ Out.append(", ");
+ (RMin + 1).toString(Out, 10, RMin.isSigned());
+ Out.append(" or ");
+ RMax.toString(Out);
+ } else {
+ Out.append("between ");
+ RMin.toString(Out);
+ Out.append(" and ");
+ RMax.toString(Out);
+ }
+}
+
+void StdLibraryFunctionsChecker::appendOutOfRangeDesc(llvm::APSInt RMin,
+ llvm::APSInt RMax,
+ QualType ArgT,
+ BasicValueFactory &BVF,
+ DescString &Out) {
+ if (RMin.isZero() && RMax.isZero())
+ Out.append("nonzero");
+ else if (RMin == RMax) {
+ Out.append("not equal to ");
+ RMin.toString(Out);
+ } else if (RMin == BVF.getMinValue(ArgT)) {
+ if (RMax == -1)
+ Out.append(">= 0");
+ else {
+ Out.append("> ");
+ RMax.toString(Out);
+ }
+ } else if (RMax == BVF.getMaxValue(ArgT)) {
+ if (RMin.isOne())
+ Out.append("<= 0");
+ else {
+ Out.append("< ");
+ RMin.toString(Out);
+ }
+ } else if (RMin.isNegative() == RMax.isNegative() &&
+ RMin.getLimitedValue() == RMax.getLimitedValue() - 1) {
+ Out.append("not ");
+ RMin.toString(Out);
+ Out.append(" and not ");
+ RMax.toString(Out);
+ } else {
+ Out.append("not between ");
+ RMin.toString(Out);
+ Out.append(" and ");
+ RMax.toString(Out);
+ }
+}
+
std::string StdLibraryFunctionsChecker::NotNullConstraint::describe(
- DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
+ DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
+ const Summary &Summary) const {
SmallString<48> Result;
const auto Violation = ValueConstraint::DescriptionKind::Violation;
Result += "the ";
Result += getArgDesc(ArgN);
- Result += DK == Violation ? " should not be NULL" : " is not NULL";
+ Result += " to '";
+ Result += getFunctionName(Call);
+ Result += DK == Violation ? "' should not be NULL" : "' is not NULL";
return Result.c_str();
}
std::string StdLibraryFunctionsChecker::RangeConstraint::describe(
- DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
+ DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
+ const Summary &Summary) const {
BasicValueFactory &BVF = getBVF(State);
QualType T = Summary.getArgType(getArgNo());
- SmallString<48> Result;
+ DescString Result;
const auto Violation = ValueConstraint::DescriptionKind::Violation;
Result += "the ";
Result += getArgDesc(ArgN);
- Result += DK == Violation ? " should be " : " is ";
-
- // Range kind as a string.
- Kind == OutOfRange ? Result += "out of" : Result += "within";
-
- // Get the range values as a string.
- Result += " the range ";
- if (Ranges.size() > 1)
- Result += "[";
- unsigned I = Ranges.size();
- for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
- Result += "[";
- const llvm::APSInt &Min = BVF.getValue(R.first, T);
- const llvm::APSInt &Max = BVF.getValue(R.second, T);
- Min.toString(Result);
- Result += ", ";
- Max.toString(Result);
- Result += "]";
- if (--I > 0)
- Result += ", ";
+ Result += " to '";
+ Result += getFunctionName(Call);
+ Result += DK == Violation ? "' should be " : "' is ";
+ if (!Description.empty()) {
+ Result += Description;
+ } else {
+ unsigned I = Ranges.size();
+ if (Kind == WithinRange) {
+ for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
+ appendInsideRangeDesc(BVF.getValue(R.first, T),
+ BVF.getValue(R.second, T), T, BVF, Result);
+ if (--I > 0)
+ Result += " or ";
+ }
+ } else {
+ for (const std::pair<RangeInt, RangeInt> &R : Ranges) {
+ appendOutOfRangeDesc(BVF.getValue(R.first, T),
+ BVF.getValue(R.second, T), T, BVF, Result);
+ if (--I > 0)
+ Result += " and ";
+ }
+ }
}
- if (Ranges.size() > 1)
- Result += "]";
return Result.c_str();
}
-SmallString<8>
-StdLibraryFunctionsChecker::getArgDesc(StdLibraryFunctionsChecker::ArgNo ArgN) {
- SmallString<8> Result;
- Result += std::to_string(ArgN + 1);
- Result += llvm::getOrdinalSuffix(ArgN + 1);
- Result += " argument";
- return Result;
-}
-
std::string StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
- DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
+ DescriptionKind DK, const CallEvent &Call, ProgramStateRef State,
+ const Summary &Summary) const {
SmallString<96> Result;
const auto Violation = ValueConstraint::DescriptionKind::Violation;
Result += "the size of the ";
Result += getArgDesc(ArgN);
- Result += DK == Violation ? " should be " : " is ";
- Result += "equal to or greater than the value of ";
+ Result += " to '";
+ Result += getFunctionName(Call);
+ Result += DK == Violation ? "' should be " : "' is ";
+ Result += "equal to or greater than ";
if (ConcreteSize) {
ConcreteSize->toString(Result);
} else if (SizeArgN) {
- Result += "the ";
+ Result += "the value of the ";
Result += getArgDesc(*SizeArgN);
if (SizeMultiplierArgN) {
Result += " times the ";
@@ -998,7 +1113,7 @@ void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
SmallString<64> Msg;
Msg += "Assuming ";
Msg += Constraint->describe(ValueConstraint::DescriptionKind::Assumption,
- NewState, Summary);
+ Call, NewState, Summary);
const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
NewNode = C.addTransition(
NewState, NewNode,
@@ -1358,9 +1473,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
} addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
// Below are helpers functions to create the summaries.
- auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind,
- IntRangeVector Ranges) {
- return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
+ auto ArgumentCondition = [](ArgNo ArgN, RangeKind Kind, IntRangeVector Ranges,
+ StringRef Desc = "") {
+ return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges, Desc);
};
auto BufferSize = [](auto... Args) {
return std::make_shared<BufferSizeConstraint>(Args...);
@@ -1443,8 +1558,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
{{'0', '9'}, {'A', 'Z'}, {'a', 'z'}, {128, UCharRangeMax}}),
ReturnValueCondition(WithinRange, SingleValue(0))},
ErrnoIrrelevant, "Assuming the character is non-alphanumeric")
- .ArgConstraint(ArgumentCondition(
- 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+ .ArgConstraint(ArgumentCondition(0U, WithinRange,
+ {{EOFv, EOFv}, {0, UCharRangeMax}},
+ "an unsigned char value or EOF")));
addToFunctionSummaryMap(
"isalpha", Signature(ArgTypes{IntTy}, RetType{IntTy}),
Summary(EvalCallAsPure)
@@ -1603,18 +1719,21 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
addToFunctionSummaryMap(
"toupper", Signature(ArgTypes{IntTy}, RetType{IntTy}),
Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(
- 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+ .ArgConstraint(ArgumentCondition(0U, WithinRange,
+ {{EOFv, EOFv}, {0, UCharRangeMax}},
+ "an unsigned char value or EOF")));
addToFunctionSummaryMap(
"tolower", Signature(ArgTypes{IntTy}, RetType{IntTy}),
Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(
- 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+ .ArgConstraint(ArgumentCondition(0U, WithinRange,
+ {{EOFv, EOFv}, {0, UCharRangeMax}},
+ "an unsigned char value or EOF")));
addToFunctionSummaryMap(
"toascii", Signature(ArgTypes{IntTy}, RetType{IntTy}),
Summary(EvalCallAsPure)
- .ArgConstraint(ArgumentCondition(
- 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+ .ArgConstraint(ArgumentCondition(0U, WithinRange,
+ {{EOFv, EOFv}, {0, UCharRangeMax}},
+ "an unsigned char value or EOF")));
// The getc() family of functions that returns either a char or an EOF.
addToFunctionSummaryMap(
@@ -3097,11 +3216,13 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
// Functions for testing.
if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) {
+ const RangeInt IntMin = BVF.getMinValue(IntTy).getLimitedValue();
+
addToFunctionSummaryMap(
"__not_null", Signature(ArgTypes{IntPtrTy}, RetType{IntTy}),
Summary(EvalCallAsPure).ArgConstraint(NotNull(ArgNo(0))));
- // Test range values.
+ // Test inside range constraints.
addToFunctionSummaryMap(
"__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
Summary(EvalCallAsPure)
@@ -3114,11 +3235,124 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
"__range_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
Summary(EvalCallAsPure)
.ArgConstraint(ArgumentCondition(0U, WithinRange, Range(1, 2))));
- addToFunctionSummaryMap("__range_1_2__4_5",
+ addToFunctionSummaryMap(
+ "__range_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-1, 1))));
+ addToFunctionSummaryMap(
+ "__range_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-2, -1))));
+ addToFunctionSummaryMap(
+ "__range_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, WithinRange, Range(-10, 10))));
+ addToFunctionSummaryMap("__range_m1_inf",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, WithinRange, Range(-1, IntMax))));
+ addToFunctionSummaryMap("__range_0_inf",
Signature(ArgTypes{IntTy}, RetType{IntTy}),
Summary(EvalCallAsPure)
.ArgConstraint(ArgumentCondition(
- 0U, WithinRange, Range({1, 2}, {4, 5}))));
+ 0U, WithinRange, Range(0, IntMax))));
+ addToFunctionSummaryMap("__range_1_inf",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, WithinRange, Range(1, IntMax))));
+ addToFunctionSummaryMap("__range_minf_m1",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, WithinRange, Range(IntMin, -1))));
+ addToFunctionSummaryMap("__range_minf_0",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, WithinRange, Range(IntMin, 0))));
+ addToFunctionSummaryMap("__range_minf_1",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, WithinRange, Range(IntMin, 1))));
+ addToFunctionSummaryMap("__range_1_2__4_6",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, WithinRange, Range({1, 2}, {4, 6}))));
+ addToFunctionSummaryMap(
+ "__range_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, WithinRange,
+ Range({1, 2}, {4, IntMax}))));
+
+ // Test out of range constraints.
+ addToFunctionSummaryMap(
+ "__single_val_out_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(0))));
+ addToFunctionSummaryMap(
+ "__single_val_out_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, OutOfRange, SingleValue(1))));
+ addToFunctionSummaryMap(
+ "__range_out_1_2", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(1, 2))));
+ addToFunctionSummaryMap(
+ "__range_out_m1_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-1, 1))));
+ addToFunctionSummaryMap(
+ "__range_out_m2_m1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-2, -1))));
+ addToFunctionSummaryMap(
+ "__range_out_m10_10", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, OutOfRange, Range(-10, 10))));
+ addToFunctionSummaryMap("__range_out_m1_inf",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, OutOfRange, Range(-1, IntMax))));
+ addToFunctionSummaryMap("__range_out_0_inf",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, OutOfRange, Range(0, IntMax))));
+ addToFunctionSummaryMap("__range_out_1_inf",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, OutOfRange, Range(1, IntMax))));
+ addToFunctionSummaryMap("__range_out_minf_m1",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, OutOfRange, Range(IntMin, -1))));
+ addToFunctionSummaryMap("__range_out_minf_0",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, OutOfRange, Range(IntMin, 0))));
+ addToFunctionSummaryMap("__range_out_minf_1",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, OutOfRange, Range(IntMin, 1))));
+ addToFunctionSummaryMap("__range_out_1_2__4_6",
+ Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, OutOfRange, Range({1, 2}, {4, 6}))));
+ addToFunctionSummaryMap(
+ "__range_out_1_2__4_inf", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(
+ ArgumentCondition(0U, OutOfRange, Range({1, 2}, {4, IntMax}))));
// Test range kind.
addToFunctionSummaryMap(
diff --git a/clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp b/clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp
index 50e07d39cd5be..2ddcf7a3136fb 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints-note-tags.cpp
@@ -19,7 +19,7 @@ int clang_analyzer_getExtent(void *);
// Check NotNullConstraint assumption notes.
int __not_null(int *);
int test_not_null_note(int *x, int y) {
- __not_null(x); // expected-note{{Assuming the 1st argument is not NULL}}
+ __not_null(x); // expected-note{{Assuming the 1st argument to '__not_null' is not NULL}}
if (x) // expected-note{{'x' is non-null}} \
// expected-note{{Taking true branch}}
if (!y) // expected-note{{Assuming 'y' is 0}} \
@@ -33,7 +33,7 @@ int test_not_null_note(int *x, int y) {
// Check the RangeConstraint assumption notes.
int __single_val_0(int); // [0, 0]
int test_range_constraint_note(int x, int y) {
- __single_val_0(x); // expected-note{{Assuming the 1st argument is within the range [0, 0]}}
+ __single_val_0(x); // expected-note{{Assuming the 1st argument to '__single_val_0' is zero}}
return y / x; // expected-warning{{Division by zero}} \
// expected-note{{Division by zero}}
}
@@ -41,7 +41,7 @@ int test_range_constraint_note(int x, int y) {
// Check the BufferSizeConstraint assumption notes.
int __buf_size_arg_constraint_concrete(const void *buf); // size of buf must be >= 10
void test_buffer_size_note(char *buf, int y) {
- __buf_size_arg_constraint_concrete(buf); // expected-note {{Assuming the size of the 1st argument is equal to or greater than the value of 10}}
+ __buf_size_arg_constraint_concrete(buf); // expected-note {{Assuming the size of the 1st argument to '__buf_size_arg_constraint_concrete' is equal to or greater than 10}}
clang_analyzer_eval(clang_analyzer_getExtent(buf) >= 10); // expected-warning{{TRUE}} \
// expected-note{{TRUE}}
diff --git a/clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp b/clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
index 7481a015e5580..2a9b4821b8fdb 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints-notes.cpp
@@ -15,8 +15,7 @@
int __not_null(int *);
void test_not_null(int *x) {
__not_null(nullptr); // \
- // expected-note{{The 1st argument should not be NULL}} \
- // expected-warning{{}}
+ // expected-warning{{The 1st argument to '__not_null' should not be NULL}}
}
// Check the BufferSizeConstraint violation notes.
@@ -29,66 +28,159 @@ void test_buffer_size(int x) {
case 1: {
char buf[9];
__buf_size_arg_constraint_concrete(buf); // \
- // expected-note{{The size of the 1st argument should be equal to or greater than the value of 10}} \
- // expected-warning{{}}
+ // expected-warning{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}}
break;
}
case 2: {
char buf[3];
__buf_size_arg_constraint(buf, 4); // \
- // expected-note{{The size of the 1st argument should be equal to or greater than the value of the 2nd arg}} \
- // expected-warning{{}}
+ // expected-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}}
break;
}
case 3: {
char buf[3];
__buf_size_arg_constraint_mul(buf, 4, 2); // \
- // expected-note{{The size of the 1st argument should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
- // expected-warning{{}}
+ // expected-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}}
break;
}
}
}
// Check the RangeConstraint violation notes.
-int __single_val_1(int); // [1, 1]
-int __range_1_2(int); // [1, 2]
-int __range_1_2__4_5(int); // [1, 2], [4, 5]
-void test_range(int x) {
- __single_val_1(2); // \
- // expected-note{{The 1st argument should be within the range [1, 1]}} \
- // expected-warning{{}}
-}
-// Do more specific check against the range strings.
+
+int __single_val_0(int); // [0, 0]
+int __single_val_1(int); // [1, 1]
+int __range_1_2(int); // [1, 2]
+int __range_m1_1(int); // [-1, 1]
+int __range_m2_m1(int); // [-2, -1]
+int __range_m10_10(int); // [-10, 10]
+int __range_m1_inf(int); // [-1, inf]
+int __range_0_inf(int); // [0, inf]
+int __range_1_inf(int); // [1, inf]
+int __range_minf_m1(int); // [-inf, -1]
+int __range_minf_0(int); // [-inf, 0]
+int __range_minf_1(int); // [-inf, 1]
+int __range_1_2__4_6(int); // [1, 2], [4, 6]
+int __range_1_2__4_inf(int); // [1, 2], [4, inf]
+
+int __single_val_out_0(int); // [0, 0]
+int __single_val_out_1(int); // [1, 1]
+int __range_out_1_2(int); // [1, 2]
+int __range_out_m1_1(int); // [-1, 1]
+int __range_out_m2_m1(int); // [-2, -1]
+int __range_out_m10_10(int); // [-10, 10]
+int __range_out_m1_inf(int); // [-1, inf]
+int __range_out_0_inf(int); // [0, inf]
+int __range_out_1_inf(int); // [1, inf]
+int __range_out_minf_m1(int); // [-inf, -1]
+int __range_out_minf_0(int); // [-inf, 0]
+int __range_out_minf_1(int); // [-inf, 1]
+int __range_out_1_2__4_6(int); // [1, 2], [4, 6]
+int __range_out_1_2__4_inf(int); // [1, 2], [4, inf]
+
void test_range_values(int x) {
switch (x) {
- case 1:
- __single_val_1(2); // expected-note{{[1, 1]}} \
- // expected-warning{{}}
- break;
- case 2:
- __range_1_2(3); // expected-note{{[1, 2]}} \
- // expected-warning{{}}
- break;
- case 3:
- __range_1_2__4_5(3); // expected-note{{[[1, 2], [4, 5]]}} \
- // expected-warning{{}}
- break;
+ case 0:
+ __single_val_0(1); // expected-warning{{should be zero}}
+ break;
+ case 1:
+ __single_val_1(2); // expected-warning{{should be 1}}
+ break;
+ case 2:
+ __range_1_2(3); // expected-warning{{should be 1 or 2}}
+ break;
+ case 3:
+ __range_m1_1(3); // expected-warning{{should be between -1 and 1}}
+ break;
+ case 4:
+ __range_m2_m1(1); // expected-warning{{should be -2 or -1}}
+ break;
+ case 5:
+ __range_m10_10(11); // expected-warning{{should be between -10 and 10}}
+ break;
+ case 6:
+ __range_m10_10(-11); // expected-warning{{should be between -10 and 10}}
+ break;
+ case 7:
+ __range_1_2__4_6(3); // expected-warning{{should be 1 or 2 or 4, 5 or 6}}
+ break;
+ case 8:
+ __range_1_2__4_inf(3); // expected-warning{{should be 1 or 2 or >= 4}}
+ break;
}
}
-// Do more specific check against the range kinds.
-int __within(int); // [1, 1]
-int __out_of(int); // [1, 1]
-void test_range_kind(int x) {
+
+void test_range_values_inf(int x) {
switch (x) {
- case 1:
- __within(2); // expected-note{{within}} \
- // expected-warning{{}}
- break;
- case 2:
- __out_of(1); // expected-note{{out of}} \
- // expected-warning{{}}
- break;
+ case 1:
+ __range_m1_inf(-2); // expected-warning{{should be >= -1}}
+ break;
+ case 2:
+ __range_0_inf(-1); // expected-warning{{should be >= 0}}
+ break;
+ case 3:
+ __range_1_inf(0); // expected-warning{{should be > 0}}
+ break;
+ case 4:
+ __range_minf_m1(0); // expected-warning{{should be < 0}}
+ break;
+ case 5:
+ __range_minf_0(1); // expected-warning{{should be <= 0}}
+ break;
+ case 6:
+ __range_minf_1(2); // expected-warning{{should be <= 1}}
+ break;
}
}
+void test_range_values_out(int x) {
+ switch (x) {
+ case 0:
+ __single_val_out_0(0); // expected-warning{{should be nonzero}}
+ break;
+ case 1:
+ __single_val_out_1(1); // expected-warning{{should be not equal to 1}}
+ break;
+ case 2:
+ __range_out_1_2(2); // expected-warning{{should be not 1 and not 2}}
+ break;
+ case 3:
+ __range_out_m1_1(-1); // expected-warning{{should be not between -1 and 1}}
+ break;
+ case 4:
+ __range_out_m2_m1(-2); // expected-warning{{should be not -2 and not -1}}
+ break;
+ case 5:
+ __range_out_m10_10(0); // expected-warning{{should be not between -10 and 10}}
+ break;
+ case 6:
+ __range_out_1_2__4_6(1); // expected-warning{{should be not 1 and not 2 and not between 4 and 6}}
+ break;
+ case 7:
+ __range_out_1_2__4_inf(4); // expected-warning{{should be not 1 and not 2 and < 4}}
+ break;
+ }
+}
+
+void test_range_values_out_inf(int x) {
+ switch (x) {
+ case 1:
+ __range_out_minf_m1(-1); // expected-warning{{should be >= 0}}
+ break;
+ case 2:
+ __range_out_minf_0(0); // expected-warning{{should be > 0}}
+ break;
+ case 3:
+ __range_out_minf_1(1); // expected-warning{{should be > 1}}
+ break;
+ case 4:
+ __range_out_m1_inf(-1); // expected-warning{{should be < -1}}
+ break;
+ case 5:
+ __range_out_0_inf(0); // expected-warning{{should be < 0}}
+ break;
+ case 6:
+ __range_out_1_inf(1); // expected-warning{{should be <= 0}}
+ break;
+ }
+}
diff --git a/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c b/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
index afdff5b2ffac0..38b5f03e46551 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints-tracking-notes.c
@@ -16,9 +16,8 @@ void test_buf_size_concrete(void) {
char buf[3]; // bugpath-note{{'buf' initialized here}}
int s = 4; // bugpath-note{{'s' initialized to 4}}
__buf_size_arg_constraint(buf, s); // \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}} \
+ // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}}
}
int __buf_size_arg_constraint_mul(const void *, size_t, size_t);
@@ -27,7 +26,6 @@ void test_buf_size_concrete_with_multiplication(void) {
int s1 = 4; // bugpath-note{{'s1' initialized to 4}}
int s2 = sizeof(short); // bugpath-note{{'s2' initialized to}}
__buf_size_arg_constraint_mul(buf, s1, s2); // \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
+ // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}}
}
diff --git a/clang/test/Analysis/std-c-library-functions-arg-constraints.c b/clang/test/Analysis/std-c-library-functions-arg-constraints.c
index 1e9165321232d..cff435d627530 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints.c
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.c
@@ -30,11 +30,9 @@ int isalnum(int);
void test_alnum_concrete(int v) {
int ret = isalnum(256); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \
+ // bugpath-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \
+ // bugpath-note{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}}
(void)ret;
}
@@ -57,11 +55,9 @@ void test_alnum_symbolic2(int x) {
// bugpath-note{{Taking true branch}}
int ret = isalnum(x); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \
+ // bugpath-warning{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}} \
+ // bugpath-note{{The 1st argument to 'isalnum' should be an unsigned char value or EOF}}
(void)ret;
}
@@ -71,11 +67,9 @@ int toupper(int);
void test_toupper_concrete(int v) {
int ret = toupper(256); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \
+ // bugpath-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \
+ // bugpath-note{{The 1st argument to 'toupper' should be an unsigned char value or EOF}}
(void)ret;
}
@@ -97,11 +91,9 @@ void test_toupper_symbolic2(int x) {
// bugpath-note{{Taking true branch}}
int ret = toupper(x); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \
+ // bugpath-warning{{The 1st argument to 'toupper' should be an unsigned char value or EOF}} \
+ // bugpath-note{{The 1st argument to 'toupper' should be an unsigned char value or EOF}}
(void)ret;
}
@@ -111,11 +103,9 @@ int tolower(int);
void test_tolower_concrete(int v) {
int ret = tolower(256); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \
+ // bugpath-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \
+ // bugpath-note{{The 1st argument to 'tolower' should be an unsigned char value or EOF}}
(void)ret;
}
@@ -137,11 +127,9 @@ void test_tolower_symbolic2(int x) {
// bugpath-note{{Taking true branch}}
int ret = tolower(x); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \
+ // bugpath-warning{{The 1st argument to 'tolower' should be an unsigned char value or EOF}} \
+ // bugpath-note{{The 1st argument to 'tolower' should be an unsigned char value or EOF}}
(void)ret;
}
@@ -151,11 +139,9 @@ int toascii(int);
void test_toascii_concrete(int v) {
int ret = toascii(256); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \
+ // bugpath-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \
+ // bugpath-note{{The 1st argument to 'toascii' should be an unsigned char value or EOF}}
(void)ret;
}
@@ -177,11 +163,9 @@ void test_toascii_symbolic2(int x) {
// bugpath-note{{Taking true branch}}
int ret = toascii(x); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \
+ // bugpath-warning{{The 1st argument to 'toascii' should be an unsigned char value or EOF}} \
+ // bugpath-note{{The 1st argument to 'toascii' should be an unsigned char value or EOF}}
(void)ret;
}
@@ -192,11 +176,9 @@ typedef typeof(sizeof(int)) size_t;
size_t fread(void *restrict, size_t, size_t, FILE *restrict);
void test_notnull_concrete(FILE *fp) {
fread(0, sizeof(int), 10, fp); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 1st argument to 'fread' should not be NULL}} \
+ // bugpath-warning{{The 1st argument to 'fread' should not be NULL}} \
+ // bugpath-note{{The 1st argument to 'fread' should not be NULL}}
}
void test_notnull_symbolic(FILE *fp, int *buf) {
fread(buf, sizeof(int), 10, fp);
@@ -210,11 +192,9 @@ void test_notnull_symbolic2(FILE *fp, int *buf) {
if (!buf) // bugpath-note{{Assuming 'buf' is null}} \
// bugpath-note{{Taking true branch}}
fread(buf, sizeof(int), 10, fp); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 1st argument to 'fread' should not be NULL}} \
+ // bugpath-warning{{The 1st argument to 'fread' should not be NULL}} \
+ // bugpath-note{{The 1st argument to 'fread' should not be NULL}}
}
void test_no_node_after_bug(FILE *fp, size_t size, size_t n, void *buf) {
if (fp) // \
@@ -222,11 +202,9 @@ void test_no_node_after_bug(FILE *fp, size_t size, size_t n, void *buf) {
// bugpath-note{{Taking false branch}}
return;
size_t ret = fread(buf, size, n, fp); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 4th argument to 'fread' should not be NULL}} \
+ // bugpath-warning{{The 4th argument to 'fread' should not be NULL}} \
+ // bugpath-note{{The 4th argument to 'fread' should not be NULL}}
clang_analyzer_warnIfReached(); // not reachable
}
@@ -242,11 +220,9 @@ void ARR38_C_F(FILE *file) {
// The 3rd parameter should be the number of elements to read, not
// the size in bytes.
fread(wbuf, size, nitems, file); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The size of the 1st argument to 'fread' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
+ // bugpath-warning{{The size of the 1st argument to 'fread' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
+ // bugpath-note{{The size of the 1st argument to 'fread' should be equal to or greater than the value of the 2nd argument times the 3rd argument}}
}
int __two_constrained_args(int, int);
@@ -279,22 +255,18 @@ void test_multiple_constraints_on_same_arg(int x) {
int __variadic(void *stream, const char *format, ...);
void test_arg_constraint_on_variadic_fun(void) {
__variadic(0, "%d%d", 1, 2); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The 1st argument to '__variadic' should not be NULL}} \
+ // bugpath-warning{{The 1st argument to '__variadic' should not be NULL}} \
+ // bugpath-note{{The 1st argument to '__variadic' should not be NULL}}
}
int __buf_size_arg_constraint(const void *, size_t);
void test_buf_size_concrete(void) {
char buf[3]; // bugpath-note{{'buf' initialized here}}
__buf_size_arg_constraint(buf, 4); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}} \
+ // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}} \
+ // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint' should be equal to or greater than the value of the 2nd argument}}
}
void test_buf_size_symbolic(int s) {
char buf[3];
@@ -319,11 +291,9 @@ int __buf_size_arg_constraint_mul(const void *, size_t, size_t);
void test_buf_size_concrete_with_multiplication(void) {
short buf[3]; // bugpath-note{{'buf' initialized here}}
__buf_size_arg_constraint_mul(buf, 4, sizeof(short)); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
+ // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}} \
+ // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint_mul' should be equal to or greater than the value of the 2nd argument times the 3rd argument}}
}
void test_buf_size_symbolic_with_multiplication(size_t s) {
short buf[3];
@@ -347,9 +317,7 @@ int __buf_size_arg_constraint_concrete(const void *);
void test_min_buf_size(void) {
char buf[9];// bugpath-note{{'buf' initialized here}}
__buf_size_arg_constraint_concrete(buf); // \
- // report-warning{{Function argument constraint is not satisfied}} \
- // report-note{{}} \
- // bugpath-warning{{Function argument constraint is not satisfied}} \
- // bugpath-note{{}} \
- // bugpath-note{{Function argument constraint is not satisfied}}
+ // report-warning{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}} \
+ // bugpath-warning{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}} \
+ // bugpath-note{{The size of the 1st argument to '__buf_size_arg_constraint_concrete' should be equal to or greater than 10}}
}
diff --git a/clang/test/Analysis/std-c-library-functions-arg-constraints.cpp b/clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
index 2e646dc2574a8..86fa98bf4f10c 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.cpp
@@ -14,6 +14,5 @@ int __defaultparam(void *, int y = 3);
void test_arg_constraint_on_fun_with_default_param() {
__defaultparam(nullptr); // \
- // expected-warning{{Function argument constraint is not satisfied}} \
- // expected-note{{}}
+ // expected-warning{{The 1st argument to '__defaultparam' should not be NULL}}
}
diff --git a/clang/test/Analysis/stream-note.c b/clang/test/Analysis/stream-note.c
index 42e46d45601d7..cd711bc27711a 100644
--- a/clang/test/Analysis/stream-note.c
+++ b/clang/test/Analysis/stream-note.c
@@ -88,9 +88,8 @@ void check_track_null(void) {
fclose(F);
return;
}
- fclose(F); // stdargs-warning {{Function argument constraint is not satisfied}}
- // stdargs-note at -1 {{Function argument constraint is not satisfied}}
- // stdargs-note at -2 {{The 1st argument should not be NULL}}
+ fclose(F); // stdargs-warning {{The 1st argument to 'fclose' should not be NULL}}
+ // stdargs-note at -1 {{The 1st argument to 'fclose' should not be NULL}}
}
void check_eof_notes_feof_after_feof(void) {
diff --git a/clang/test/Analysis/stream-stdlibraryfunctionargs.c b/clang/test/Analysis/stream-stdlibraryfunctionargs.c
index 469d40b456914..9d1b9244f0f24 100644
--- a/clang/test/Analysis/stream-stdlibraryfunctionargs.c
+++ b/clang/test/Analysis/stream-stdlibraryfunctionargs.c
@@ -18,37 +18,31 @@ size_t n;
void test_fopen(void) {
FILE *fp = fopen("path", "r");
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}} any-warning{{FALSE}}
- fclose(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ fclose(fp); // stdargs-warning{{should not be NULL}}
}
void test_tmpfile(void) {
FILE *fp = tmpfile();
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}} any-warning{{FALSE}}
- fclose(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ fclose(fp); // stdargs-warning{{should not be NULL}}
}
void test_fclose(void) {
FILE *fp = tmpfile();
- fclose(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ fclose(fp); // stdargs-warning{{should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
}
void test_freopen(void) {
FILE *fp = tmpfile();
- fp = freopen("file", "w", fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 3rd argument should not be NULL}}
- fclose(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ fp = freopen("file", "w", fp); // stdargs-warning{{should not be NULL}}
+ fclose(fp); // stdargs-warning{{should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
}
void test_fread(void) {
FILE *fp = tmpfile();
- size_t ret = fread(buf, size, n, fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 4th argument should not be NULL}}
+ size_t ret = fread(buf, size, n, fp); // stdargs-warning{{The 4th argument to 'fread' should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
clang_analyzer_eval(ret <= n); // any-warning{{TRUE}}
clang_analyzer_eval(ret == n); // any-warning{{TRUE}} any-warning{{FALSE}}
@@ -58,8 +52,7 @@ void test_fread(void) {
void test_fwrite(void) {
FILE *fp = tmpfile();
- size_t ret = fwrite(buf, size, n, fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 4th argument should not be NULL}}
+ size_t ret = fwrite(buf, size, n, fp); // stdargs-warning{{The 4th argument to 'fwrite' should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
clang_analyzer_eval(ret <= n); // any-warning{{TRUE}}
clang_analyzer_eval(ret == n); // any-warning{{TRUE}} any-warning{{FALSE}}
@@ -69,24 +62,21 @@ void test_fwrite(void) {
void test_fseek(void) {
FILE *fp = tmpfile();
- fseek(fp, 0, 0); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ fseek(fp, 0, 0); // stdargs-warning{{should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
fclose(fp);
}
void test_ftell(void) {
FILE *fp = tmpfile();
- ftell(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ ftell(fp); // stdargs-warning{{should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
fclose(fp);
}
void test_rewind(void) {
FILE *fp = tmpfile();
- rewind(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ rewind(fp); // stdargs-warning{{should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
fclose(fp);
}
@@ -94,8 +84,7 @@ void test_rewind(void) {
void test_fgetpos(void) {
FILE *fp = tmpfile();
fpos_t pos;
- fgetpos(fp, &pos); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ fgetpos(fp, &pos); // stdargs-warning{{should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
fclose(fp);
}
@@ -103,40 +92,35 @@ void test_fgetpos(void) {
void test_fsetpos(void) {
FILE *fp = tmpfile();
fpos_t pos;
- fsetpos(fp, &pos); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ fsetpos(fp, &pos); // stdargs-warning{{should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
fclose(fp);
}
void test_clearerr(void) {
FILE *fp = tmpfile();
- clearerr(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ clearerr(fp); // stdargs-warning{{should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
fclose(fp);
}
void test_feof(void) {
FILE *fp = tmpfile();
- feof(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ feof(fp); // stdargs-warning{{should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
fclose(fp);
}
void test_ferror(void) {
FILE *fp = tmpfile();
- ferror(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ ferror(fp); // stdargs-warning{{should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
fclose(fp);
}
void test_fileno(void) {
FILE *fp = tmpfile();
- fileno(fp); // stdargs-warning{{Function argument constraint is not satisfied}} \
- // stdargs-note{{The 1st argument should not be NULL}}
+ fileno(fp); // stdargs-warning{{should not be NULL}}
clang_analyzer_eval(fp != NULL); // any-warning{{TRUE}}
fclose(fp);
}
More information about the cfe-commits
mailing list