https://github.com/adrian-prantl updated https://github.com/llvm/llvm-project/pull/69465
>From 627f68e57b2526fb72285ef4831fc3c02a6ee6d0 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Wed, 18 Oct 2023 08:47:02 +0800 Subject: [PATCH 1/6] [clang-tidy]Add new check bugprone-casting-through-void Fixes: #68532 --- .../bugprone/BugproneTidyModule.cpp | 3 ++ .../clang-tidy/bugprone/CMakeLists.txt | 1 + .../bugprone/CastingThroughVoidCheck.cpp | 46 +++++++++++++++++++ .../bugprone/CastingThroughVoidCheck.h | 37 +++++++++++++++ clang-tools-extra/docs/ReleaseNotes.rst | 6 +++ .../checks/bugprone/casting-through-void.rst | 11 +++++ .../docs/clang-tidy/checks/list.rst | 1 + .../bugprone/casting-through-void.cpp | 18 ++++++++ 8 files changed, 123 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index 543c522899d7a52..7a910037368c832 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -16,6 +16,7 @@ #include "BadSignalToKillThreadCheck.h" #include "BoolPointerImplicitConversionCheck.h" #include "BranchCloneCheck.h" +#include "CastingThroughVoidCheck.h" #include "ComparePointerToMemberVirtualFunctionCheck.h" #include "CopyConstructorInitCheck.h" #include "DanglingHandleCheck.h" @@ -104,6 +105,8 @@ class BugproneModule : public ClangTidyModule { CheckFactories.registerCheck<BoolPointerImplicitConversionCheck>( "bugprone-bool-pointer-implicit-conversion"); CheckFactories.registerCheck<BranchCloneCheck>("bugprone-branch-clone"); + CheckFactories.registerCheck<CastingThroughVoidCheck>( + "bugprone-casting-through-void"); CheckFactories.registerCheck<ComparePointerToMemberVirtualFunctionCheck>( "bugprone-compare-pointer-to-member-virtual-function"); CheckFactories.registerCheck<CopyConstructorInitCheck>( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index 0df9e439b715e5a..d443fd8d1452f16 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(clangTidyBugproneModule BoolPointerImplicitConversionCheck.cpp BranchCloneCheck.cpp BugproneTidyModule.cpp + CastingThroughVoidCheck.cpp ComparePointerToMemberVirtualFunctionCheck.cpp CopyConstructorInitCheck.cpp DanglingHandleCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp new file mode 100644 index 000000000000000..7b9cd7dd51fc47f --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp @@ -0,0 +1,46 @@ +//===--- CastingThroughVoidCheck.cpp - clang-tidy -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CastingThroughVoidCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "llvm/ADT/StringSet.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +void CastingThroughVoidCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + explicitCastExpr( + hasDestinationType(qualType(pointsTo(qualType(unless(voidType())))) + .bind("target_type")), + hasSourceExpression( + explicitCastExpr(hasSourceExpression(expr( + hasType(qualType().bind("source_type")))), + hasDestinationType(pointsTo(voidType()))))) + .bind("cast"), + this); +} + +void CastingThroughVoidCheck::check(const MatchFinder::MatchResult &Result) { + ASTContext *Context = Result.Context; + const auto *CE = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast"); + const auto *TT = Result.Nodes.getNodeAs<QualType>("target_type"); + const auto *ST = Result.Nodes.getNodeAs<QualType>("source_type"); + if (Context->hasSameType(*TT, *ST)) + return; + diag(CE->getSourceRange().getBegin(), "do not cast %0 to %1 through void *", + DiagnosticIDs::Level::Warning) + << ST->getAsString() << TT->getAsString(); +} + +} // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h new file mode 100644 index 000000000000000..542b1c50dc782e7 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h @@ -0,0 +1,37 @@ +//===--- CastingThroughVoidCheck.h - clang-tidy -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CASTINGTHROUGHVOIDCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CASTINGTHROUGHVOIDCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::bugprone { + +/// A check detects usage of ``static_cast`` pointer to the other pointer +/// throght +/// ``static_cast`` to ``void *`` in C++ code. +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/casting-through-void.html +class CastingThroughVoidCheck : public ClangTidyCheck { +public: + CastingThroughVoidCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + std::optional<TraversalKind> getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } +}; + +} // namespace clang::tidy::bugprone + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_CASTINGTHROUGHVOIDCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index af164d0462d52c1..3ceb844a036240c 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -125,6 +125,12 @@ Improvements to clang-tidy New checks ^^^^^^^^^^ +- New :doc:`bugprone-casting-through-void + <clang-tidy/checks/bugprone/casting-through-void>` check. + + Detects usage of ``static_cast`` pointer to the other pointer throght + ``static_cast`` to ``void *`` in C++ code. + - New :doc:`bugprone-compare-pointer-to-member-virtual-function <clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst new file mode 100644 index 000000000000000..4a20d8eb9b41c8b --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst @@ -0,0 +1,11 @@ +.. title:: clang-tidy - bugprone-casting-through-void + +bugprone-casting-through-void +============================= + +A check detects usage of ``static_cast`` pointer to the other pointer throght +``static_cast`` to ``void *`` in C++ code. + +Use of these casts can violate type safety and cause the program to access a +variable that is actually of type ``X`` to be accessed as if it were of an +unrelated type ``Z``. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 2125ebd7a213c15..fa95bffdc45f9cb 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -82,6 +82,7 @@ Clang-Tidy Checks :doc:`bugprone-bad-signal-to-kill-thread <bugprone/bad-signal-to-kill-thread>`, :doc:`bugprone-bool-pointer-implicit-conversion <bugprone/bool-pointer-implicit-conversion>`, "Yes" :doc:`bugprone-branch-clone <bugprone/branch-clone>`, + :doc:`bugprone-casting-through-void <bugprone/casting-through-void>`, "Yes" :doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`, :doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes" :doc:`bugprone-dangling-handle <bugprone/dangling-handle>`, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp new file mode 100644 index 000000000000000..f9e8c57201ee802 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp @@ -0,0 +1,18 @@ +// RUN: %check_clang_tidy %s bugprone-casting-through-void %t + +using T = void*; + +void test() { + int i = 100; + double d = 100; + + static_cast<int *>(static_cast<void *>(&d)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not cast double * to int * through void * [bugprone-casting-through-void] + + static_cast<int *>(static_cast<T>(&d)); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not cast double * to int * through void * [bugprone-casting-through-void] + + static_cast<int *>(static_cast<void *>(&i)); + + static_cast<void *>(static_cast<void *>(&i)); +} >From 77d37e9a95191cfbeb7f4fe7504f86c6dfd0ad2e Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Wed, 18 Oct 2023 22:43:03 +0800 Subject: [PATCH 2/6] fix --- .../bugprone/CastingThroughVoidCheck.cpp | 18 ++++++++---------- .../docs/clang-tidy/checks/list.rst | 2 +- .../checkers/bugprone/casting-through-void.cpp | 4 ++-- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp index 7b9cd7dd51fc47f..f1d6c9170dbcbfe 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp @@ -26,21 +26,19 @@ void CastingThroughVoidCheck::registerMatchers(MatchFinder *Finder) { hasSourceExpression( explicitCastExpr(hasSourceExpression(expr( hasType(qualType().bind("source_type")))), - hasDestinationType(pointsTo(voidType()))))) - .bind("cast"), + hasDestinationType(pointsTo(voidType()))) + .bind("cast"))), this); } void CastingThroughVoidCheck::check(const MatchFinder::MatchResult &Result) { - ASTContext *Context = Result.Context; - const auto *CE = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast"); - const auto *TT = Result.Nodes.getNodeAs<QualType>("target_type"); - const auto *ST = Result.Nodes.getNodeAs<QualType>("source_type"); - if (Context->hasSameType(*TT, *ST)) + const auto TT = *Result.Nodes.getNodeAs<QualType>("target_type"); + const auto ST = *Result.Nodes.getNodeAs<QualType>("source_type"); + if (Result.Context->hasSameType(TT, ST)) return; - diag(CE->getSourceRange().getBegin(), "do not cast %0 to %1 through void *", - DiagnosticIDs::Level::Warning) - << ST->getAsString() << TT->getAsString(); + const auto *CE = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast"); + diag(CE->getSourceRange().getBegin(), "do not cast %0 to %1 through 'void*'") + << ST << TT; } } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index fa95bffdc45f9cb..0ce25772aa5b66b 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -82,7 +82,7 @@ Clang-Tidy Checks :doc:`bugprone-bad-signal-to-kill-thread <bugprone/bad-signal-to-kill-thread>`, :doc:`bugprone-bool-pointer-implicit-conversion <bugprone/bool-pointer-implicit-conversion>`, "Yes" :doc:`bugprone-branch-clone <bugprone/branch-clone>`, - :doc:`bugprone-casting-through-void <bugprone/casting-through-void>`, "Yes" + :doc:`bugprone-casting-through-void <bugprone/casting-through-void>`, :doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`, :doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes" :doc:`bugprone-dangling-handle <bugprone/dangling-handle>`, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp index f9e8c57201ee802..74265fce3f59068 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp @@ -7,10 +7,10 @@ void test() { double d = 100; static_cast<int *>(static_cast<void *>(&d)); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not cast double * to int * through void * [bugprone-casting-through-void] + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] static_cast<int *>(static_cast<T>(&d)); - // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not cast double * to int * through void * [bugprone-casting-through-void] + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] static_cast<int *>(static_cast<void *>(&i)); >From a432aed9e92e9cd3d4302c09e39fb4eac6dcd943 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Wed, 18 Oct 2023 23:30:20 +0800 Subject: [PATCH 3/6] add test --- .../bugprone/CastingThroughVoidCheck.cpp | 7 +- .../bugprone/casting-through-void.cpp | 81 ++++++++++++++++++- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp index f1d6c9170dbcbfe..4ce4e3c773f6766 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp @@ -34,7 +34,12 @@ void CastingThroughVoidCheck::registerMatchers(MatchFinder *Finder) { void CastingThroughVoidCheck::check(const MatchFinder::MatchResult &Result) { const auto TT = *Result.Nodes.getNodeAs<QualType>("target_type"); const auto ST = *Result.Nodes.getNodeAs<QualType>("source_type"); - if (Result.Context->hasSameType(TT, ST)) + if (Result.Context->hasSameType(TT->getUnqualifiedDesugaredType(), + ST->getUnqualifiedDesugaredType())) + return; + if (Result.Context->hasSameType( + TT->getPointeeType()->getUnqualifiedDesugaredType(), + ST->getPointeeType()->getUnqualifiedDesugaredType())) return; const auto *CE = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast"); diag(CE->getSourceRange().getBegin(), "do not cast %0 to %1 through 'void*'") diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp index 74265fce3f59068..4edb33310f45ec7 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp @@ -1,11 +1,14 @@ // RUN: %check_clang_tidy %s bugprone-casting-through-void %t using T = void*; +using CT = const void*; -void test() { - int i = 100; - double d = 100; +int i = 100; +double d = 100; +const int ci = 100; +const double cd = 100; +void normal_test() { static_cast<int *>(static_cast<void *>(&d)); // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] @@ -13,6 +16,76 @@ void test() { // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] static_cast<int *>(static_cast<void *>(&i)); - static_cast<void *>(static_cast<void *>(&i)); } + +void const_pointer_test() { + static_cast<int *const>(static_cast<void *>(&d)); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void*' [bugprone-casting-through-void] + + static_cast<int *const>(static_cast<T>(&d)); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void*' [bugprone-casting-through-void] + + static_cast<int *const>(static_cast<void *>(&i)); + static_cast<void *const>(static_cast<void *>(&i)); +} + +void const_test() { + static_cast<const int *>(static_cast<const void *>(&d)); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'void*' [bugprone-casting-through-void] + + static_cast<const int *>(static_cast<const T>(&d)); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'void*' [bugprone-casting-through-void] + + static_cast<const int *>(static_cast<const void *>(&i)); + static_cast<const void *>(static_cast<const void *>(&i)); + + static_cast<const int *>(static_cast<const void *>(&cd)); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'void*' [bugprone-casting-through-void] + + static_cast<const int *>(static_cast<const CT>(&cd)); + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'void*' [bugprone-casting-through-void] + + static_cast<const int *>(static_cast<const void *>(&ci)); + static_cast<const void *>(static_cast<const void *>(&ci)); +} + + +void reinterpret_cast_test() { + static_cast<int *>(reinterpret_cast<void *>(&d)); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] + reinterpret_cast<int *>(static_cast<void *>(&d)); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] + reinterpret_cast<int *>(reinterpret_cast<void *>(&d)); + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] + + static_cast<int *>(reinterpret_cast<void *>(&i)); + static_cast<void *>(reinterpret_cast<void *>(&i)); + reinterpret_cast<int *>(reinterpret_cast<void *>(&i)); + reinterpret_cast<void *>(reinterpret_cast<void *>(&i)); + static_cast<int *>(reinterpret_cast<void *>(&i)); + static_cast<void *>(reinterpret_cast<void *>(&i)); +} + +void c_style_cast_test() { + static_cast<int *>((void *)&d); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] + (int *)(void *)&d; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] + static_cast<int *>((void *)&d); + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] + + static_cast<int *>(reinterpret_cast<void *>(&i)); + static_cast<void *>(reinterpret_cast<void *>(&i)); +} + +struct A { + A(void*); +}; +void cxx_functional_cast() { + A(static_cast<void*>(&i)); +} + +void bit_cast() { + __builtin_bit_cast(int *, static_cast<void *>(&i)); +} >From 858aff0c29fb8946572c4dc749cfa99ac6f75320 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Wed, 18 Oct 2023 23:47:33 +0800 Subject: [PATCH 4/6] support __builtin_bit_cast --- .../clang-tidy/bugprone/CastingThroughVoidCheck.cpp | 3 ++- .../clang-tidy/bugprone/CastingThroughVoidCheck.h | 8 ++------ clang-tools-extra/docs/ReleaseNotes.rst | 4 ++-- .../checks/bugprone/casting-through-void.rst | 4 ++-- .../checkers/bugprone/casting-through-void.cpp | 2 +- clang/include/clang/ASTMatchers/ASTMatchers.h | 10 ++++++++++ 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp index 4ce4e3c773f6766..4ac0eda72dc30ad 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp @@ -27,7 +27,8 @@ void CastingThroughVoidCheck::registerMatchers(MatchFinder *Finder) { explicitCastExpr(hasSourceExpression(expr( hasType(qualType().bind("source_type")))), hasDestinationType(pointsTo(voidType()))) - .bind("cast"))), + .bind("cast")), + unless(builtinBitCastExpr())), this); } diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h index 542b1c50dc782e7..369242036115814 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h @@ -13,9 +13,8 @@ namespace clang::tidy::bugprone { -/// A check detects usage of ``static_cast`` pointer to the other pointer -/// throght -/// ``static_cast`` to ``void *`` in C++ code. +/// A check detects usage of cast pointer to the other pointer throght cast to +/// ``void *`` in C/C++ code. /// For the user-facing documentation see: /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/casting-through-void.html class CastingThroughVoidCheck : public ClangTidyCheck { @@ -24,9 +23,6 @@ class CastingThroughVoidCheck : public ClangTidyCheck { : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { - return LangOpts.CPlusPlus; - } std::optional<TraversalKind> getCheckTraversalKind() const override { return TK_IgnoreUnlessSpelledInSource; } diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 3ceb844a036240c..08ba3ca79aa87ef 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -128,8 +128,8 @@ New checks - New :doc:`bugprone-casting-through-void <clang-tidy/checks/bugprone/casting-through-void>` check. - Detects usage of ``static_cast`` pointer to the other pointer throght - ``static_cast`` to ``void *`` in C++ code. + Detects usage of cast pointer to the other pointer throght cast to + ``void *`` in C/C++ code. - New :doc:`bugprone-compare-pointer-to-member-virtual-function <clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst index 4a20d8eb9b41c8b..4c5e70533fa3bc6 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst @@ -3,8 +3,8 @@ bugprone-casting-through-void ============================= -A check detects usage of ``static_cast`` pointer to the other pointer throght -``static_cast`` to ``void *`` in C++ code. +A check detects usage of cast pointer to the other pointer throght cast to +``void *`` in C/C++ code. Use of these casts can violate type safety and cause the program to access a variable that is actually of type ``X`` to be accessed as if it were of an diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp index 4edb33310f45ec7..8cf15c3b08cdb14 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp @@ -87,5 +87,5 @@ void cxx_functional_cast() { } void bit_cast() { - __builtin_bit_cast(int *, static_cast<void *>(&i)); + __builtin_bit_cast(int *, static_cast<void *>(&d)); } diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 82a26356c58f556..1dad8594ec92843 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2732,6 +2732,16 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CastExpr> castExpr; extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXFunctionalCastExpr> cxxFunctionalCastExpr; +/// Matches a builtin bit cast expression. +/// +/// Example: Matches __builtin_bit_cast(double, i) in +/// \code +/// int64_t i = 100; +/// double d = __builtin_bit_cast(double, i); +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher<Stmt, BuiltinBitCastExpr> + builtinBitCastExpr; + /// Matches functional cast expressions having N != 1 arguments /// /// Example: Matches Foo(bar, bar) >From 01c3ab74d3c3f3828366fb9e472cb2e4c6b93466 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Thu, 19 Oct 2023 00:11:28 +0800 Subject: [PATCH 5/6] add functional cast test --- .../bugprone/casting-through-void.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp index 8cf15c3b08cdb14..f36f51a88d183e2 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp @@ -1,7 +1,7 @@ // RUN: %check_clang_tidy %s bugprone-casting-through-void %t -using T = void*; -using CT = const void*; +using V = void*; +using CV = const void*; int i = 100; double d = 100; @@ -12,7 +12,7 @@ void normal_test() { static_cast<int *>(static_cast<void *>(&d)); // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] - static_cast<int *>(static_cast<T>(&d)); + static_cast<int *>(static_cast<V>(&d)); // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not cast 'double *' to 'int *' through 'void*' [bugprone-casting-through-void] static_cast<int *>(static_cast<void *>(&i)); @@ -23,7 +23,7 @@ void const_pointer_test() { static_cast<int *const>(static_cast<void *>(&d)); // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void*' [bugprone-casting-through-void] - static_cast<int *const>(static_cast<T>(&d)); + static_cast<int *const>(static_cast<V>(&d)); // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not cast 'double *' to 'int *const' through 'void*' [bugprone-casting-through-void] static_cast<int *const>(static_cast<void *>(&i)); @@ -34,7 +34,7 @@ void const_test() { static_cast<const int *>(static_cast<const void *>(&d)); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'void*' [bugprone-casting-through-void] - static_cast<const int *>(static_cast<const T>(&d)); + static_cast<const int *>(static_cast<const V>(&d)); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'double *' to 'const int *' through 'void*' [bugprone-casting-through-void] static_cast<const int *>(static_cast<const void *>(&i)); @@ -43,7 +43,7 @@ void const_test() { static_cast<const int *>(static_cast<const void *>(&cd)); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'void*' [bugprone-casting-through-void] - static_cast<const int *>(static_cast<const CT>(&cd)); + static_cast<const int *>(static_cast<const CV>(&cd)); // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not cast 'const double *' to 'const int *' through 'void*' [bugprone-casting-through-void] static_cast<const int *>(static_cast<const void *>(&ci)); @@ -82,8 +82,13 @@ void c_style_cast_test() { struct A { A(void*); }; +using I = int *; +using D = double *; void cxx_functional_cast() { - A(static_cast<void*>(&i)); + A(static_cast<void*>(&d)); + D(static_cast<void*>(&d)); + I(static_cast<void*>(&d)); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not cast 'double *' to 'I' (aka 'int *') through 'void*' [bugprone-casting-through-void] } void bit_cast() { >From e073d026aa7e12720af1d1760b8c49e22ae970d8 Mon Sep 17 00:00:00 2001 From: Congcong Cai <congcongcai0...@163.com> Date: Thu, 19 Oct 2023 00:20:36 +0800 Subject: [PATCH 6/6] doc --- .../bugprone/CastingThroughVoidCheck.h | 3 +- clang-tools-extra/docs/ReleaseNotes.rst | 3 +- .../checks/bugprone/casting-through-void.rst | 31 ++++++++++++++++--- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h index 369242036115814..86ed84275006f92 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.h @@ -13,8 +13,7 @@ namespace clang::tidy::bugprone { -/// A check detects usage of cast pointer to the other pointer throght cast to -/// ``void *`` in C/C++ code. +/// A check detects unsafe or redundant two-step casting operations involving ``void*``. /// For the user-facing documentation see: /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/casting-through-void.html class CastingThroughVoidCheck : public ClangTidyCheck { diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 08ba3ca79aa87ef..e3943b858ee4596 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -128,8 +128,7 @@ New checks - New :doc:`bugprone-casting-through-void <clang-tidy/checks/bugprone/casting-through-void>` check. - Detects usage of cast pointer to the other pointer throght cast to - ``void *`` in C/C++ code. + Detects unsafe or redundant two-step casting operations involving ``void*``. - New :doc:`bugprone-compare-pointer-to-member-virtual-function <clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst index 4c5e70533fa3bc6..c9f851b0679c247 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/casting-through-void.rst @@ -3,9 +3,30 @@ bugprone-casting-through-void ============================= -A check detects usage of cast pointer to the other pointer throght cast to -``void *`` in C/C++ code. +A check detects unsafe or redundant two-step casting operations involving ``void*``. -Use of these casts can violate type safety and cause the program to access a -variable that is actually of type ``X`` to be accessed as if it were of an -unrelated type ``Z``. +Two-step type conversions via void* are discouraged for several reasons. + +1. They obscure code and impede its understandability, complicating maintenance. +2. These conversions bypass valuable compiler support, erasing warnings related + to pointer alignment. It may violate strict aliasing rule and leading to + undefined behavior. +3. In scenarios involving multiple inheritance, ambiguity and unexpected outcomes + can arise due to the loss of type information, posing runtime issues. + +In summary, avoiding two-step type conversions through void* ensures clearer code, +maintains essential compiler warnings, and prevents ambiguity and potential runtime +errors, particularly in complex inheritance scenarios. + +Examples: + +.. code-block:: c++ + using IntegerPointer = int *; + double *ptr; + + static_cast<IntegerPointer>(static_cast<void *>(ptr)); // WRONG + reinterpret_cast<IntegerPointer>(reinterpret_cast<void *>(ptr)); // WRONG + (IntegerPointer)(void *)ptr; // WRONG + IntegerPointer(static_cast<void *>(ptr)); // WRONG + + __bultin_bit_cast(IntegerPointer, static_cast<void *>(ptr)) // GOOD, __builtin_bit_cast is used to implement std::bit_cast _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits