Skip to content

Commit c5fa50a

Browse files
author
git apple-llvm automerger
committed
Merge commit '00330d235574' from apple/master into swift/master-next
2 parents d07bfda + 00330d2 commit c5fa50a

File tree

3 files changed

+83
-6
lines changed

3 files changed

+83
-6
lines changed

clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -744,21 +744,38 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
744744
bool StdLibraryFunctionsChecker::Signature::matches(
745745
const FunctionDecl *FD) const {
746746
assert(!isInvalid());
747-
// Check number of arguments:
747+
// Check the number of arguments.
748748
if (FD->param_size() != ArgTys.size())
749749
return false;
750750

751-
// Check return type.
752-
if (!isIrrelevant(RetTy))
753-
if (RetTy != FD->getReturnType().getCanonicalType())
751+
// The "restrict" keyword is illegal in C++, however, many libc
752+
// implementations use the "__restrict" compiler intrinsic in functions
753+
// prototypes. The "__restrict" keyword qualifies a type as a restricted type
754+
// even in C++.
755+
// In case of any non-C99 languages, we don't want to match based on the
756+
// restrict qualifier because we cannot know if the given libc implementation
757+
// qualifies the paramter type or not.
758+
auto RemoveRestrict = [&FD](QualType T) {
759+
if (!FD->getASTContext().getLangOpts().C99)
760+
T.removeLocalRestrict();
761+
return T;
762+
};
763+
764+
// Check the return type.
765+
if (!isIrrelevant(RetTy)) {
766+
QualType FDRetTy = RemoveRestrict(FD->getReturnType().getCanonicalType());
767+
if (RetTy != FDRetTy)
754768
return false;
769+
}
755770

756-
// Check argument types.
771+
// Check the argument types.
757772
for (size_t I = 0, E = ArgTys.size(); I != E; ++I) {
758773
QualType ArgTy = ArgTys[I];
759774
if (isIrrelevant(ArgTy))
760775
continue;
761-
if (ArgTy != FD->getParamDecl(I)->getType().getCanonicalType())
776+
QualType FDArgTy =
777+
RemoveRestrict(FD->getParamDecl(I)->getType().getCanonicalType());
778+
if (ArgTy != FDArgTy)
762779
return false;
763780
}
764781

@@ -989,6 +1006,12 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
9891006
for (const Summary &S : Summaries)
9901007
operator()(Name, S);
9911008
}
1009+
// Add the same summary for different names with the Signature explicitly
1010+
// given.
1011+
void operator()(std::vector<StringRef> Names, Signature Sign, Summary Sum) {
1012+
for (StringRef Name : Names)
1013+
operator()(Name, Sign, Sum);
1014+
}
9921015
} addToFunctionSummaryMap(ACtx, FunctionSummaryMap, DisplayLoadedSummaries);
9931016

9941017
// Below are helpers functions to create the summaries.
@@ -2048,6 +2071,11 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
20482071
EvalCallAsPure)
20492072
.ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
20502073
/*BufSizeMultiplier=*/ArgNo(2))));
2074+
addToFunctionSummaryMap(
2075+
{"__test_restrict_param_0", "__test_restrict_param_1",
2076+
"__test_restrict_param_2"},
2077+
Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
2078+
Summary(EvalCallAsPure));
20512079
}
20522080
}
20532081

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %clang_analyze_cc1 %s \
2+
// RUN: -analyzer-checker=core \
3+
// RUN: -analyzer-checker=apiModeling.StdCLibraryFunctions \
4+
// RUN: -analyzer-checker=debug.StdCLibraryFunctionsTester \
5+
// RUN: -analyzer-config apiModeling.StdCLibraryFunctions:DisplayLoadedSummaries=true \
6+
// RUN: -triple i686-unknown-linux 2>&1 | FileCheck %s
7+
8+
// The signatures for these functions are the same and they specify their
9+
// parameter with the restrict qualifier. In C, the signature should match only
10+
// if the restrict qualifier is there on the parameter. Thus, the summary
11+
// should be loaded for the last two declarations only.
12+
void __test_restrict_param_0(void *p);
13+
void __test_restrict_param_1(void *__restrict p);
14+
void __test_restrict_param_2(void *restrict p);
15+
16+
// CHECK-NOT: Loaded summary for: void __test_restrict_param_0
17+
// CHECK: Loaded summary for: void __test_restrict_param_1(void *restrict p)
18+
// CHECK: Loaded summary for: void __test_restrict_param_2(void *restrict p)
19+
20+
// Must have at least one call expression to initialize the summary map.
21+
int bar(void);
22+
void foo() {
23+
bar();
24+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang_analyze_cc1 %s \
2+
// RUN: -analyzer-checker=core \
3+
// RUN: -analyzer-checker=apiModeling.StdCLibraryFunctions \
4+
// RUN: -analyzer-checker=debug.StdCLibraryFunctionsTester \
5+
// RUN: -analyzer-config apiModeling.StdCLibraryFunctions:DisplayLoadedSummaries=true \
6+
// RUN: -triple i686-unknown-linux 2>&1 | FileCheck %s
7+
8+
// The signatures for these functions are the same and they specify their
9+
// parameter with the restrict qualifier. In C++, however, we are more
10+
// indulgent and we do not match based on this qualifier. Thus, the given
11+
// signature should match for both of the declarations below, i.e the summary
12+
// should be loaded for both of them.
13+
void __test_restrict_param_0(void *p);
14+
void __test_restrict_param_1(void *__restrict p);
15+
// The below declaration is illegal, "restrict" is not a keyword in C++.
16+
// void __test_restrict_param_2(void *restrict p);
17+
18+
// CHECK: Loaded summary for: void __test_restrict_param_0(void *p)
19+
// CHECK: Loaded summary for: void __test_restrict_param_1(void *__restrict p)
20+
21+
// Must have at least one call expression to initialize the summary map.
22+
int bar(void);
23+
void foo() {
24+
bar();
25+
}

0 commit comments

Comments
 (0)