[llvm-branch-commits] [clang] 64c979d - [analyzer] StdLibraryFunctionsChecker: Add support for new functions
Zurab Tsinadze via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Aug 12 07:15:42 PDT 2020
Author: Zurab Tsinadze
Date: 2020-08-12T16:11:14+02:00
New Revision: 64c979d948f7af2e88416618f8abe658c7014d9c
URL: https://github.com/llvm/llvm-project/commit/64c979d948f7af2e88416618f8abe658c7014d9c
DIFF: https://github.com/llvm/llvm-project/commit/64c979d948f7af2e88416618f8abe658c7014d9c.diff
LOG: [analyzer] StdLibraryFunctionsChecker: Add support for new functions
`toupper`, `tolower`, `toascii` functions were added to
StdLibraryFunctionsChecker to fully cover CERT STR37-C rule:
https://wiki.sei.cmu.edu/confluence/x/BNcxBQ
Reviewed By: martong
Differential Revision: https://reviews.llvm.org/D85093
Added:
Modified:
clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
clang/test/Analysis/std-c-library-functions-arg-constraints.c
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index e437c33bd81a..030f995739e3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -40,12 +40,12 @@
//
// The following standard C functions are currently supported:
//
-// fgetc getline isdigit isupper
+// fgetc getline isdigit isupper toascii
// fread isalnum isgraph isxdigit
// fwrite isalpha islower read
// getc isascii isprint write
-// getchar isblank ispunct
-// getdelim iscntrl isspace
+// getchar isblank ispunct toupper
+// getdelim iscntrl isspace tolower
//
//===----------------------------------------------------------------------===//
@@ -147,9 +147,7 @@ class StdLibraryFunctionsChecker
RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Args)
: ValueConstraint(ArgN), Kind(Kind), Args(Args) {}
- const IntRangeVector &getRanges() const {
- return Args;
- }
+ const IntRangeVector &getRanges() const { return Args; }
private:
ProgramStateRef applyAsOutOfRange(ProgramStateRef State,
@@ -158,6 +156,7 @@ class StdLibraryFunctionsChecker
ProgramStateRef applyAsWithinRange(ProgramStateRef State,
const CallEvent &Call,
const Summary &Summary) const;
+
public:
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
const Summary &Summary,
@@ -408,7 +407,7 @@ class StdLibraryFunctionsChecker
return *this;
}
- Summary &Case(ConstraintSet&& CS) {
+ Summary &Case(ConstraintSet &&CS) {
CaseConstraints.push_back(std::move(CS));
return *this;
}
@@ -796,13 +795,13 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
const QualType LongLongTy = ACtx.LongLongTy;
const QualType SizeTy = ACtx.getSizeType();
- const QualType VoidPtrTy = ACtx.VoidPtrTy; // void *
+ const QualType VoidPtrTy = ACtx.VoidPtrTy; // void *
const QualType IntPtrTy = ACtx.getPointerType(IntTy); // int *
const QualType UnsignedIntPtrTy =
ACtx.getPointerType(UnsignedIntTy); // unsigned int *
const QualType VoidPtrRestrictTy = getRestrictTy(VoidPtrTy);
const QualType ConstVoidPtrTy =
- ACtx.getPointerType(ACtx.VoidTy.withConst()); // const void *
+ ACtx.getPointerType(ACtx.VoidTy.withConst()); // const void *
const QualType CharPtrTy = ACtx.getPointerType(ACtx.CharTy); // char *
const QualType CharPtrRestrictTy = getRestrictTy(CharPtrTy);
const QualType ConstCharPtrTy =
@@ -1117,6 +1116,18 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case({ArgumentCondition(0U, OutOfRange,
{{'0', '9'}, {'A', 'F'}, {'a', 'f'}}),
ReturnValueCondition(WithinRange, SingleValue(0))}));
+ addToFunctionSummaryMap(
+ "toupper", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+ addToFunctionSummaryMap(
+ "tolower", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
+ addToFunctionSummaryMap(
+ "toascii", Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(
+ 0U, WithinRange, {{EOFv, EOFv}, {0, UCharRangeMax}})));
// The getc() family of functions that returns either a char or an EOF.
if (FilePtrTy) {
@@ -2033,7 +2044,8 @@ void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX");
}
-bool ento::shouldRegisterStdCLibraryFunctionsChecker(const CheckerManager &mgr) {
+bool ento::shouldRegisterStdCLibraryFunctionsChecker(
+ const CheckerManager &mgr) {
return true;
}
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 b23700a96f38..e926cd15384d 100644
--- a/clang/test/Analysis/std-c-library-functions-arg-constraints.c
+++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.c
@@ -45,7 +45,6 @@ void test_alnum_symbolic(int x) {
// bugpath-note{{TRUE}} \
// bugpath-note{{Left side of '&&' is true}} \
// bugpath-note{{'x' is <= 255}}
-
}
void test_alnum_symbolic2(int x) {
@@ -62,6 +61,114 @@ void test_alnum_symbolic2(int x) {
}
}
+int toupper(int);
+
+void test_toupper_concrete(int v) {
+ int ret = toupper(256); // \
+ // report-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-note{{Function argument constraint is not satisfied}}
+ (void)ret;
+}
+
+void test_toupper_symbolic(int x) {
+ int ret = toupper(x);
+ (void)ret;
+
+ clang_analyzer_eval(EOF <= x && x <= 255); // \
+ // report-warning{{TRUE}} \
+ // bugpath-warning{{TRUE}} \
+ // bugpath-note{{TRUE}} \
+ // bugpath-note{{Left side of '&&' is true}} \
+ // bugpath-note{{'x' is <= 255}}
+}
+
+void test_toupper_symbolic2(int x) {
+ if (x > 255) { // \
+ // bugpath-note{{Assuming 'x' is > 255}} \
+ // bugpath-note{{Taking true branch}}
+
+ int ret = toupper(x); // \
+ // report-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-note{{Function argument constraint is not satisfied}}
+
+ (void)ret;
+ }
+}
+
+int tolower(int);
+
+void test_tolower_concrete(int v) {
+ int ret = tolower(256); // \
+ // report-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-note{{Function argument constraint is not satisfied}}
+ (void)ret;
+}
+
+void test_tolower_symbolic(int x) {
+ int ret = tolower(x);
+ (void)ret;
+
+ clang_analyzer_eval(EOF <= x && x <= 255); // \
+ // report-warning{{TRUE}} \
+ // bugpath-warning{{TRUE}} \
+ // bugpath-note{{TRUE}} \
+ // bugpath-note{{Left side of '&&' is true}} \
+ // bugpath-note{{'x' is <= 255}}
+}
+
+void test_tolower_symbolic2(int x) {
+ if (x > 255) { // \
+ // bugpath-note{{Assuming 'x' is > 255}} \
+ // bugpath-note{{Taking true branch}}
+
+ int ret = tolower(x); // \
+ // report-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-note{{Function argument constraint is not satisfied}}
+
+ (void)ret;
+ }
+}
+
+int toascii(int);
+
+void test_toascii_concrete(int v) {
+ int ret = toascii(256); // \
+ // report-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-note{{Function argument constraint is not satisfied}}
+ (void)ret;
+}
+
+void test_toascii_symbolic(int x) {
+ int ret = toascii(x);
+ (void)ret;
+
+ clang_analyzer_eval(EOF <= x && x <= 255); // \
+ // report-warning{{TRUE}} \
+ // bugpath-warning{{TRUE}} \
+ // bugpath-note{{TRUE}} \
+ // bugpath-note{{Left side of '&&' is true}} \
+ // bugpath-note{{'x' is <= 255}}
+}
+
+void test_toascii_symbolic2(int x) {
+ if (x > 255) { // \
+ // bugpath-note{{Assuming 'x' is > 255}} \
+ // bugpath-note{{Taking true branch}}
+
+ int ret = toascii(x); // \
+ // report-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-warning{{Function argument constraint is not satisfied}} \
+ // bugpath-note{{Function argument constraint is not satisfied}}
+
+ (void)ret;
+ }
+}
+
typedef struct FILE FILE;
typedef typeof(sizeof(int)) size_t;
size_t fread(void *restrict, size_t, size_t, FILE *restrict);
@@ -80,7 +187,7 @@ void test_notnull_symbolic(FILE *fp, int *buf) {
// bugpath-note{{'buf' is not equal to null}}
}
void test_notnull_symbolic2(FILE *fp, int *buf) {
- if (!buf) // bugpath-note{{Assuming 'buf' is null}} \
+ 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}} \
@@ -151,7 +258,7 @@ void test_buf_size_symbolic_and_offset(int s) {
}
int __buf_size_arg_constraint_mul(const void *, size_t, size_t);
void test_buf_size_concrete_with_multiplication() {
- short buf[3]; // bugpath-note{{'buf' initialized here}}
+ 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}} \
// bugpath-warning{{Function argument constraint is not satisfied}} \
More information about the llvm-branch-commits
mailing list