[clang] fe0972d - [analyzer][StdLibraryFunctionsChecker] Do not match based on the restrict qualifier in C++

Gabor Marton via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 4 02:48:48 PDT 2020


Author: Gabor Marton
Date: 2020-09-04T11:48:38+02:00
New Revision: fe0972d3e4a65b4c5f5fa602b17ad30e463050b3

URL: https://github.com/llvm/llvm-project/commit/fe0972d3e4a65b4c5f5fa602b17ad30e463050b3
DIFF: https://github.com/llvm/llvm-project/commit/fe0972d3e4a65b4c5f5fa602b17ad30e463050b3.diff

LOG: [analyzer][StdLibraryFunctionsChecker] Do not match based on the restrict qualifier in C++

The "restrict" keyword is illegal in C++, however, many libc
implementations use the "__restrict" compiler intrinsic in functions
prototypes. The "__restrict" keyword qualifies a type as a restricted type
even in C++.
In case of any non-C99 languages, we don't want to match based on the
restrict qualifier because we cannot know if the given libc implementation
qualifies the paramter type or not.

Differential Revision: https://reviews.llvm.org/D87097

Added: 
    clang/test/Analysis/std-c-library-functions-restrict.c
    clang/test/Analysis/std-c-library-functions-restrict.cpp

Modified: 
    clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index c65d58e49d78..2c20422a9cc4 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -744,21 +744,38 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
 bool StdLibraryFunctionsChecker::Signature::matches(
     const FunctionDecl *FD) const {
   assert(!isInvalid());
-  // Check number of arguments:
+  // Check the number of arguments.
   if (FD->param_size() != ArgTys.size())
     return false;
 
-  // Check return type.
-  if (!isIrrelevant(RetTy))
-    if (RetTy != FD->getReturnType().getCanonicalType())
+  // The "restrict" keyword is illegal in C++, however, many libc
+  // implementations use the "__restrict" compiler intrinsic in functions
+  // prototypes. The "__restrict" keyword qualifies a type as a restricted type
+  // even in C++.
+  // In case of any non-C99 languages, we don't want to match based on the
+  // restrict qualifier because we cannot know if the given libc implementation
+  // qualifies the paramter type or not.
+  auto RemoveRestrict = [&FD](QualType T) {
+    if (!FD->getASTContext().getLangOpts().C99)
+      T.removeLocalRestrict();
+    return T;
+  };
+
+  // Check the return type.
+  if (!isIrrelevant(RetTy)) {
+    QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
+    if (RetTy != FDRetTy)
       return false;
+  }
 
-  // Check argument types.
+  // Check the argument types.
   for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
     QualType ArgTy = ArgTys[I];
     if (isIrrelevant(ArgTy))
       continue;
-    if (ArgTy != FD->getParamDecl(I)->getType().getCanonicalType())
+    QualType FDArgTy =
+        RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType());
+    if (ArgTy != FDArgTy)
       return false;
   }
 
@@ -989,6 +1006,12 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
       for (const Summary &S : Summaries)
         operator()(Name, S);
     }
+    // Add the same summary for 
diff erent names with the Signature explicitly
+    // given.
+    void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
+      for (StringRef Name : Names)
+        operator()(Name, Sign, Sum);
+    }
   } addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
 
   // Below are helpers functions to create the summaries.
@@ -2048,6 +2071,11 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
                 EvalCallAsPure)
             .ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
                                       /*BufSizeMultiplier=*/ArgNo(2))));
+    addToFunctionSummaryMap(
+        {"__test_restrict_param_0", "__test_restrict_param_1",
+         "__test_restrict_param_2"},
+        Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
+        Summary(EvalCallAsPure));
   }
 }
 

diff  --git a/clang/test/Analysis/std-c-library-functions-restrict.c b/clang/test/Analysis/std-c-library-functions-restrict.c
new file mode 100644
index 000000000000..7cf5f2bc630a
--- /dev/null
+++ b/clang/test/Analysis/std-c-library-functions-restrict.c
@@ -0,0 +1,24 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=apiModeling.StdCLibraryFunctions \
+// RUN:   -analyzer-checker=debug.StdCLibraryFunctionsTester \
+// RUN:   -analyzer-config apiModeling.StdCLibraryFunctions:DisplayLoadedSummaries=true \
+// RUN:   -triple i686-unknown-linux 2>&1 | FileCheck %s
+
+// The signatures for these functions are the same and they specify their
+// parameter with the restrict qualifier. In C, the signature should match only
+// if the restrict qualifier is there on the parameter. Thus, the summary
+// should be loaded for the last two declarations only.
+void __test_restrict_param_0(void *p);
+void __test_restrict_param_1(void *__restrict p);
+void __test_restrict_param_2(void *restrict p);
+
+// CHECK-NOT: Loaded summary for: void __test_restrict_param_0
+//     CHECK: Loaded summary for: void __test_restrict_param_1(void *restrict p)
+//     CHECK: Loaded summary for: void __test_restrict_param_2(void *restrict p)
+
+// Must have at least one call expression to initialize the summary map.
+int bar(void);
+void foo() {
+  bar();
+}

diff  --git a/clang/test/Analysis/std-c-library-functions-restrict.cpp b/clang/test/Analysis/std-c-library-functions-restrict.cpp
new file mode 100644
index 000000000000..d1cd090f5ef8
--- /dev/null
+++ b/clang/test/Analysis/std-c-library-functions-restrict.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_analyze_cc1 %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=apiModeling.StdCLibraryFunctions \
+// RUN:   -analyzer-checker=debug.StdCLibraryFunctionsTester \
+// RUN:   -analyzer-config apiModeling.StdCLibraryFunctions:DisplayLoadedSummaries=true \
+// RUN:   -triple i686-unknown-linux 2>&1 | FileCheck %s
+
+// The signatures for these functions are the same and they specify their
+// parameter with the restrict qualifier. In C++, however, we are more
+// indulgent and we do not match based on this qualifier. Thus, the given
+// signature should match for both of the declarations below, i.e the summary
+// should be loaded for both of them.
+void __test_restrict_param_0(void *p);
+void __test_restrict_param_1(void *__restrict p);
+// The below declaration is illegal, "restrict" is not a keyword in C++.
+// void __test_restrict_param_2(void *restrict p);
+
+// CHECK: Loaded summary for: void __test_restrict_param_0(void *p)
+// CHECK: Loaded summary for: void __test_restrict_param_1(void *__restrict p)
+
+// Must have at least one call expression to initialize the summary map.
+int bar(void);
+void foo() {
+  bar();
+}


        


More information about the cfe-commits mailing list