martong updated this revision to Diff 262098.
martong marked 2 inline comments as done.
martong added a comment.

- Rebase to latest parent patch
- Create BufSize constraints in a more descriptive way


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D77148/new/

https://reviews.llvm.org/D77148

Files:
  clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
  clang/test/Analysis/std-c-library-functions-arg-constraints.c

Index: clang/test/Analysis/std-c-library-functions-arg-constraints.c
===================================================================
--- clang/test/Analysis/std-c-library-functions-arg-constraints.c
+++ clang/test/Analysis/std-c-library-functions-arg-constraints.c
@@ -149,3 +149,27 @@
   // bugpath-note{{TRUE}} \
   // bugpath-note{{'s' is <= 2}}
 }
+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}}
+  __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}} \
+  // bugpath-note{{Function argument constraint is not satisfied}}
+}
+void test_buf_size_symbolic_with_multiplication(size_t s) {
+  short buf[3];
+  __buf_size_arg_constraint_mul(buf, s, sizeof(short));
+  clang_analyzer_eval(s * sizeof(short) <= 6); // \
+  // report-warning{{TRUE}} \
+  // bugpath-warning{{TRUE}} \
+  // bugpath-note{{TRUE}}
+}
+void test_buf_size_symbolic_and_offset_with_multiplication(size_t s) {
+  short buf[3];
+  __buf_size_arg_constraint_mul(buf + 1, s, sizeof(short));
+  clang_analyzer_eval(s * sizeof(short) <= 4); // \
+  // report-warning{{TRUE}} \
+  // bugpath-warning{{TRUE}} \
+  // bugpath-note{{TRUE}}
+}
Index: clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -215,28 +215,45 @@
   // Represents a buffer argument with an additional size argument.
   // E.g. the first two arguments here:
   //   ctime_s(char *buffer, rsize_t bufsz, const time_t *time);
+  // Another example:
+  //   size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
+  //   // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
   class BufferSizeConstraint : public ValueConstraint {
     // The argument which holds the size of the buffer.
     ArgNo SizeArgN;
+    // The argument which is a multiplier to size. This is set in case of
+    // `fread` like functions where the size is computed as a multiplication of
+    // two arguments.
+    llvm::Optional<ArgNo> SizeMultiplierArgN;
     // The operator we use in apply. This is negated in negate().
     BinaryOperator::Opcode Op = BO_LE;
 
   public:
-    BufferSizeConstraint(ArgNo BufArgN, ArgNo SizeArgN)
-        : ValueConstraint(BufArgN), SizeArgN(SizeArgN) {}
+    BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize)
+        : ValueConstraint(Buffer), SizeArgN(BufSize) {}
+
+    BufferSizeConstraint(ArgNo Buffer, ArgNo BufSize, ArgNo BufSizeMultiplier)
+        : ValueConstraint(Buffer), SizeArgN(BufSize),
+          SizeMultiplierArgN(BufSizeMultiplier) {}
 
     ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
                           const Summary &Summary,
                           CheckerContext &C) const override {
+      SValBuilder &SvalBuilder = C.getSValBuilder();
       // The buffer argument.
       SVal BufV = getArgSVal(Call, getArgNo());
       // The size argument.
       SVal SizeV = getArgSVal(Call, SizeArgN);
+      // Multiply with another argument if given.
+      if (SizeMultiplierArgN) {
+        SVal SizeMulV = getArgSVal(Call, *SizeMultiplierArgN);
+        SizeV = SvalBuilder.evalBinOp(State, BO_Mul, SizeV, SizeMulV,
+                                      Summary.getArgType(SizeArgN));
+      }
       // The dynamic size of the buffer argument, got from the analyzer engine.
       SVal BufDynSize =
           getDynamicSizeWithOffset(State, BufV, C.getSValBuilder());
 
-      SValBuilder &SvalBuilder = C.getSValBuilder();
       SVal Feasible = SvalBuilder.evalBinOp(State, Op, SizeV, BufDynSize,
                                             SvalBuilder.getContext().BoolTy);
       if (auto F = Feasible.getAs<DefinedOrUnknownSVal>())
@@ -749,8 +766,8 @@
                               IntRangeVector Ranges) {
     return std::make_shared<RangeConstraint>(ArgN, Kind, Ranges);
   };
-  auto BufferSize = [](ArgNo BufArgN, ArgNo SizeArgN) {
-    return std::make_shared<BufferSizeConstraint>(BufArgN, SizeArgN);
+  auto BufferSize = [](auto... Args) {
+    return std::make_shared<BufferSizeConstraint>(Args...);
   };
   struct {
     auto operator()(RangeKind Kind, IntRangeVector Ranges) {
@@ -987,10 +1004,17 @@
                                     RetType{IntTy}, EvalCallAsPure)
                                 .ArgConstraint(NotNull(ArgNo(0)))
                                 .ArgConstraint(NotNull(ArgNo(1))));
-    addToFunctionSummaryMap("__buf_size_arg_constraint",
-                            Summary(ArgTypes{ConstVoidPtrTy, SizeTy},
-                                    RetType{IntTy}, EvalCallAsPure)
-                                .ArgConstraint(BufferSize(0, 1)));
+    addToFunctionSummaryMap(
+        "__buf_size_arg_constraint",
+        Summary(ArgTypes{ConstVoidPtrTy, SizeTy}, RetType{IntTy},
+                EvalCallAsPure)
+            .ArgConstraint(BufferSize(0 /*Buffer*/, 1 /*BufSize*/)));
+    addToFunctionSummaryMap(
+        "__buf_size_arg_constraint_mul",
+        Summary(ArgTypes{ConstVoidPtrTy, SizeTy, SizeTy}, RetType{IntTy},
+                EvalCallAsPure)
+            .ArgConstraint(BufferSize(0 /*Buffer*/, 1 /*BufSize*/,
+                                      2 /*BufSizeMultiplier*/)));
   }
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to