diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp @@ -46,29 +46,49 @@ return InnerMatcher.matches(*E, Finder, Builder); } + +AST_MATCHER(ImplicitCastExpr, isArrayToPointerDecay) { + return Node.getCastKind() == CK_ArrayToPointerDecay; +} + +AST_MATCHER(ImplicitCastExpr, sysSymbolDecayInSysHeader) { + auto &SM = Finder->getASTContext().getSourceManager(); + if (!SM.isInSystemMacro(Node.getBeginLoc())) { + return false; + } + + if (const auto *SymbolDeclRef = dyn_cast(Node.getSubExpr())) { + const ValueDecl *SymbolDecl = SymbolDeclRef->getDecl(); + if (SymbolDecl && SM.isInSystemHeader(SymbolDecl->getLocation())) + return true; + } + return false; +} } // namespace void ProBoundsArrayToPointerDecayCheck::registerMatchers(MatchFinder *Finder) { - // The only allowed array to pointer decay + // We only allowed array to pointer decays // 1) just before array subscription // 2) inside a range-for over an array // 3) if it converts a string literal to a pointer + // 4) if it is caused by a system macro Finder->addMatcher( - traverse(ast_type_traits::TK_AsIs, - implicitCastExpr( - unless(hasParent(arraySubscriptExpr())), - unless(hasParentIgnoringImpCasts(explicitCastExpr())), - unless(isInsideOfRangeBeginEndStmt()), - unless(hasSourceExpression(ignoringParens(stringLiteral())))) - .bind("cast")), + traverse( + ast_type_traits::TK_AsIs, + implicitCastExpr( + isArrayToPointerDecay(), unless(hasParent(arraySubscriptExpr())), + unless(hasParentIgnoringImpCasts(explicitCastExpr())), + unless(isInsideOfRangeBeginEndStmt()), + unless(hasSourceExpression(ignoringParens(stringLiteral()))), + unless(hasSourceExpression(ignoringParens(predefinedExpr()))), + unless(sysSymbolDecayInSysHeader())) + .bind("cast")), this); } void ProBoundsArrayToPointerDecayCheck::check( const MatchFinder::MatchResult &Result) { const auto *MatchedCast = Result.Nodes.getNodeAs("cast"); - if (MatchedCast->getCastKind() != CK_ArrayToPointerDecay) - return; diag(MatchedCast->getExprLoc(), "do not implicitly decay an array into a " "pointer; consider using gsl::array_view or " diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/cppcoreguidelines-pro-bounds-array-to-pointer-decay/macro.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/cppcoreguidelines-pro-bounds-array-to-pointer-decay/macro.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/cppcoreguidelines-pro-bounds-array-to-pointer-decay/macro.h @@ -0,0 +1,14 @@ +const char SYS_STRING[2] = "s"; +const int SYS_INT_ARRAY[2] = {0, 0}; + +void sys_fn_decay_str(const char *); +void sys_fn_decay_int_array(const int *); + +#define sys_macro_with_pretty_function_string_decay sys_fn_decay_str(__PRETTY_FUNCTION__) +#define sys_macro_with_sys_string_decay sys_fn_decay_str(SYS_STRING) +#define sys_macro_with_sys_int_array_decay sys_fn_decay_int_array(SYS_INT_ARRAY) + +#define user_code_in_sys_macro(expr) expr; + +#define decay_to_char_pointer_in_macro(expr) sys_fn_decay_str(expr) +#define decay_to_int_pointer_in_macro(expr) sys_fn_decay_int_array(expr) diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-bounds-array-to-pointer-decay.cpp @@ -1,4 +1,6 @@ -// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-array-to-pointer-decay %t +// RUN: %check_clang_tidy %s cppcoreguidelines-pro-bounds-array-to-pointer-decay %t -- -- -isystem%S/Inputs/cppcoreguidelines-pro-bounds-array-to-pointer-decay + +#include #include namespace gsl { @@ -8,7 +10,7 @@ template array_view(U (&arr)[N]); }; -} +} // namespace gsl void pointerfun(int *p); void arrayfun(int p[]); @@ -29,9 +31,9 @@ gsl::array_view av(a); arrayviewfun(av); // OK - int i = a[0]; // OK - int j = a[(1 + 2)];// OK - pointerfun(&a[0]); // OK + int i = a[0]; // OK + int j = a[(1 + 2)]; // OK + pointerfun(&a[0]); // OK for (auto &e : a) // OK, iteration internally decays array to pointer e = 1; @@ -41,11 +43,53 @@ return "clang"; // OK, decay string literal to pointer } const char *g2() { - return ("clang"); // OK, ParenExpr hides the literal-pointer decay + return ("clang"); // OK, ParenExpr hides the literal-pointer decay } void f2(void *const *); void bug25362() { void *a[2]; - f2(static_cast(a)); // OK, explicit cast + f2(static_cast(a)); // OK, explicit cast +} + +void user_fn_decay_str(const char *); +void user_fn_decay_int_array(const int *); +void bug32239() { + sys_macro_with_pretty_function_string_decay; // Ok + sys_macro_with_sys_string_decay; // Ok + sys_macro_with_sys_int_array_decay; // Ok + + sys_fn_decay_str(__PRETTY_FUNCTION__); // Ok + + sys_fn_decay_str(SYS_STRING); // Not Ok - should it be ok? + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay] + + sys_fn_decay_int_array(SYS_INT_ARRAY); // Not Ok + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay] + + user_code_in_sys_macro(sys_fn_decay_str(__PRETTY_FUNCTION__)); // Ok + + user_code_in_sys_macro(sys_fn_decay_str(SYS_STRING)); // Not Ok - should it be ok? + // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay] + + user_code_in_sys_macro(sys_fn_decay_int_array(SYS_INT_ARRAY)); // Not Ok + // CHECK-MESSAGES: :[[@LINE-1]]:49: warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay] + + const char UserString[1] = ""; + decay_to_char_pointer_in_macro(UserString); // Not Ok + // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay] + + decay_to_char_pointer_in_macro(__PRETTY_FUNCTION__); // Ok + + int a[5]; + decay_to_int_pointer_in_macro(a); // Not Ok + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay] + + user_fn_decay_str(__PRETTY_FUNCTION__); // Ok + + user_fn_decay_str(SYS_STRING); // Not Ok - should it be ok? + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay] + + user_fn_decay_int_array(SYS_INT_ARRAY); // Not ok + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay] }