mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 12:56:08 +00:00
[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
This commit is contained in:
parent
a633da5391
commit
fe0972d3e4
@ -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())
|
||||
return false;
|
||||
// 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 argument types.
|
||||
// Check the return type.
|
||||
if (!isIrrelevant(RetTy)) {
|
||||
QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
|
||||
if (RetTy != FDRetTy)
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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 different 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
24
clang/test/Analysis/std-c-library-functions-restrict.c
Normal file
24
clang/test/Analysis/std-c-library-functions-restrict.c
Normal file
@ -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();
|
||||
}
|
25
clang/test/Analysis/std-c-library-functions-restrict.cpp
Normal file
25
clang/test/Analysis/std-c-library-functions-restrict.cpp
Normal file
@ -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();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user