Skip to content

Commit edc49ca

Browse files
haoNoQjrtc27
authored andcommitted
[analyzer] pr43179: Make CallDescription defensive against C variadic functions.
Most functions that our checkers react upon are not C-style variadic functions, and therefore they have as many actual arguments as they have formal parameters. However, it's not impossible to define a variadic function with the same name. This will crash any checker that relies on CallDescription to check the number of arguments but silently assumes that the number of parameters is the same. Change CallDescription to check both the number of arguments and the number of parameters by default. If we're intentionally trying to match variadic functions, allow specifying arguments and parameters separately (possibly omitting any of them). For now we only have one CallDescription which would make use of those, namely __builtin_va_start itself. Differential Revision: https://reviews.llvm.org/D67019 llvm-svn: 371256
2 parents e48714a + 2b1b4ca commit edc49ca

File tree

4 files changed

+33
-6
lines changed

4 files changed

+33
-6
lines changed

clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,8 +1064,19 @@ class CallDescription {
10641064
// e.g. "{a, b}" represent the qualified names, like "a::b".
10651065
std::vector<const char *> QualifiedName;
10661066
Optional<unsigned> RequiredArgs;
1067+
Optional<size_t> RequiredParams;
10671068
int Flags;
10681069

1070+
// A constructor helper.
1071+
static Optional<size_t> readRequiredParams(Optional<unsigned> RequiredArgs,
1072+
Optional<size_t> RequiredParams) {
1073+
if (RequiredParams)
1074+
return RequiredParams;
1075+
if (RequiredArgs)
1076+
return static_cast<size_t>(*RequiredArgs);
1077+
return None;
1078+
}
1079+
10691080
public:
10701081
/// Constructs a CallDescription object.
10711082
///
@@ -1078,14 +1089,17 @@ class CallDescription {
10781089
/// call. Omit this parameter to match every occurrence of call with a given
10791090
/// name regardless the number of arguments.
10801091
CallDescription(int Flags, ArrayRef<const char *> QualifiedName,
1081-
Optional<unsigned> RequiredArgs = None)
1092+
Optional<unsigned> RequiredArgs = None,
1093+
Optional<size_t> RequiredParams = None)
10821094
: QualifiedName(QualifiedName), RequiredArgs(RequiredArgs),
1095+
RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)),
10831096
Flags(Flags) {}
10841097

10851098
/// Construct a CallDescription with default flags.
10861099
CallDescription(ArrayRef<const char *> QualifiedName,
1087-
Optional<unsigned> RequiredArgs = None)
1088-
: CallDescription(0, QualifiedName, RequiredArgs) {}
1100+
Optional<unsigned> RequiredArgs = None,
1101+
Optional<size_t> RequiredParams = None)
1102+
: CallDescription(0, QualifiedName, RequiredArgs, RequiredParams) {}
10891103

10901104
/// Get the name of the function that this object matches.
10911105
StringRef getFunctionName() const { return QualifiedName.back(); }

clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@ const SmallVector<ValistChecker::VAListAccepter, 15>
116116
// vswprintf is the wide version of vsnprintf,
117117
// vsprintf has no wide version
118118
{{"vswscanf", 3}, 2}};
119-
const CallDescription ValistChecker::VaStart("__builtin_va_start", 2),
119+
120+
const CallDescription
121+
ValistChecker::VaStart("__builtin_va_start", /*Args=*/2, /*Params=*/1),
120122
ValistChecker::VaCopy("__builtin_va_copy", 2),
121123
ValistChecker::VaEnd("__builtin_va_end", 1);
122124
} // end anonymous namespace

clang/lib/StaticAnalyzer/Core/CallEvent.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,8 @@ bool CallEvent::isCalled(const CallDescription &CD) const {
368368

369369
if (CD.Flags & CDF_MaybeBuiltin) {
370370
return CheckerContext::isCLibraryFunction(FD, CD.getFunctionName()) &&
371-
(!CD.RequiredArgs || CD.RequiredArgs <= getNumArgs());
371+
(!CD.RequiredArgs || CD.RequiredArgs <= getNumArgs()) &&
372+
(!CD.RequiredParams || CD.RequiredParams <= parameters().size());
372373
}
373374

374375
if (!CD.IsLookupDone) {
@@ -407,7 +408,8 @@ bool CallEvent::isCalled(const CallDescription &CD) const {
407408
return false;
408409
}
409410

410-
return (!CD.RequiredArgs || CD.RequiredArgs == getNumArgs());
411+
return (!CD.RequiredArgs || CD.RequiredArgs == getNumArgs()) &&
412+
(!CD.RequiredParams || CD.RequiredParams == parameters().size());
411413
}
412414

413415
SVal CallEvent::getArgSVal(unsigned Index) const {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=core,apiModeling -verify %s
2+
3+
// expected-no-diagnostics
4+
5+
namespace llvm {
6+
template <typename>
7+
void cast(...);
8+
void a() { cast<int>(int()); } // no-crash
9+
} // namespace llvm

0 commit comments

Comments
 (0)