From a1b1c23a3b5f2cbe38e90140227bb38a7783e574 Mon Sep 17 00:00:00 2001 From: Felix Berger Date: Wed, 24 Nov 2021 13:45:36 -0500 Subject: [PATCH] [clang] ASTMatchers: Fix out-of-bounds access in foreachArgumentWithParamType. The matcher crashes when a variadic function pointer is invoked because the FunctionProtoType has fewer parameters than arguments. Matching of non-variadic arguments now works. Differential Revision: https://reviews.llvm.org/D114559 Reviewed-by: sammccall --- clang/include/clang/ASTMatchers/ASTMatchers.h | 2 +- .../ASTMatchers/ASTMatchersTraversalTest.cpp | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 5221d05477d0..9f0b363ad546 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -4886,7 +4886,7 @@ AST_POLYMORPHIC_MATCHER_P2(forEachArgumentWithParamType, // This test is cheaper compared to the big matcher in the next if. // Therefore, please keep this order. - if (FProto) { + if (FProto && FProto->getNumParams() > ParamIndex) { QualType ParamType = FProto->getParamType(ParamIndex); if (ParamMatcher.matches(ParamType, Finder, &ParamMatches)) { Result.addMatch(ParamMatches); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index e6ddf200c369..7f4dc3b05d95 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -1094,6 +1094,31 @@ TEST(ForEachArgumentWithParamType, MatchesMemberFunctionPtrCalls) { S, CallExpr, std::make_unique>("arg"))); } +TEST(ForEachArgumentWithParamType, MatchesVariadicFunctionPtrCalls) { + StatementMatcher ArgumentY = + declRefExpr(to(varDecl(hasName("y")))).bind("arg"); + TypeMatcher IntType = qualType(builtinType()).bind("type"); + StatementMatcher CallExpr = + callExpr(forEachArgumentWithParamType(ArgumentY, IntType)); + + StringRef S = R"cpp( + void fcntl(int fd, int cmd, ...) {} + + template + void f(Func F) { + int y = 42; + F(y, 1, 3); + } + + void g() { f(fcntl); } + )cpp"; + + EXPECT_TRUE(matchAndVerifyResultTrue( + S, CallExpr, std::make_unique>("type"))); + EXPECT_TRUE(matchAndVerifyResultTrue( + S, CallExpr, std::make_unique>("arg"))); +} + TEST(QualType, hasCanonicalType) { EXPECT_TRUE(notMatches("typedef int &int_ref;" "int a;"