Skip to content

Commit fdbb888

Browse files
[analyzer] StdVariantChecker: fix crashes and incorrect retrieval of template arguments (#167341)
Although very unusual, the SVal of the argument is not checked for UnknownVal, so we may get a null pointer dereference. In addition, the template arguments of the variant are retrieved incorrectly when type aliases are involved, causing crashes and FPs/FNs.
1 parent 74c9168 commit fdbb888

File tree

2 files changed

+37
-5
lines changed

2 files changed

+37
-5
lines changed

clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ bool isStdVariant(const Type *Type) {
9090
static std::optional<ArrayRef<TemplateArgument>>
9191
getTemplateArgsFromVariant(const Type *VariantType) {
9292
const auto *TempSpecType = VariantType->getAs<TemplateSpecializationType>();
93+
while (TempSpecType && TempSpecType->isTypeAlias())
94+
TempSpecType =
95+
TempSpecType->getAliasedType()->getAs<TemplateSpecializationType>();
9396
if (!TempSpecType)
9497
return {};
9598

@@ -219,10 +222,12 @@ class StdVariantChecker : public Checker<eval::Call, check::RegionChanges> {
219222
bool handleStdGetCall(const CallEvent &Call, CheckerContext &C) const {
220223
ProgramStateRef State = C.getState();
221224

222-
const auto &ArgType = Call.getArgSVal(0)
223-
.getType(C.getASTContext())
224-
->getPointeeType()
225-
.getTypePtr();
225+
SVal ArgSVal = Call.getArgSVal(0);
226+
if (ArgSVal.isUnknown())
227+
return false;
228+
229+
const auto &ArgType =
230+
ArgSVal.getType(C.getASTContext())->getPointeeType().getTypePtr();
226231
// We have to make sure that the argument is an std::variant.
227232
// There is another std::get with std::pair argument
228233
if (!isStdVariant(ArgType))

clang/test/Analysis/std-variant-checker.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,4 +355,31 @@ void nonInlineFunctionCallPtr() {
355355
char c = std::get<char> (v); // no-warning
356356
(void)a;
357357
(void)c;
358-
}
358+
}
359+
360+
// ----------------------------------------------------------------------------//
361+
// Misc
362+
// ----------------------------------------------------------------------------//
363+
364+
void unknownVal() {
365+
// force the argument to be UnknownVal
366+
(void)std::get<int>(*(std::variant<int, float>*)(int)3.14f); // no crash
367+
}
368+
369+
template <typename T>
370+
using MyVariant = std::variant<int, float>;
371+
372+
void typeAlias() {
373+
MyVariant<bool> v;
374+
375+
(void)std::get<int>(v); // no-warning
376+
}
377+
378+
template <template<typename> typename Container>
379+
using MySpecialVariant = std::variant<int, float>;
380+
381+
void complexTypeAlias() {
382+
MySpecialVariant<std::vector> v;
383+
384+
(void)std::get<int>(v); // no crash
385+
}

0 commit comments

Comments
 (0)