Index: clang-tidy/bugprone/BugproneTidyModule.cpp =================================================================== --- clang-tidy/bugprone/BugproneTidyModule.cpp +++ clang-tidy/bugprone/BugproneTidyModule.cpp @@ -30,6 +30,7 @@ #include "MoveForwardingReferenceCheck.h" #include "MultipleStatementMacroCheck.h" #include "ParentVirtualCallCheck.h" +#include "PlacementNewTargetTypeMismatch.h" #include "SizeofContainerCheck.h" #include "SizeofExpressionCheck.h" #include "StringConstructorCheck.h" @@ -102,6 +103,8 @@ "bugprone-narrowing-conversions"); CheckFactories.registerCheck( "bugprone-parent-virtual-call"); + CheckFactories.registerCheck( + "bugprone-placement-new-target-type-mismatch"); CheckFactories.registerCheck( "bugprone-sizeof-container"); CheckFactories.registerCheck( Index: clang-tidy/bugprone/CMakeLists.txt =================================================================== --- clang-tidy/bugprone/CMakeLists.txt +++ clang-tidy/bugprone/CMakeLists.txt @@ -22,6 +22,7 @@ MoveForwardingReferenceCheck.cpp MultipleStatementMacroCheck.cpp ParentVirtualCallCheck.cpp + PlacementNewTargetTypeMismatch.cpp SizeofContainerCheck.cpp SizeofExpressionCheck.cpp StringConstructorCheck.cpp Index: clang-tidy/bugprone/PlacementNewTargetTypeMismatch.h =================================================================== --- /dev/null +++ clang-tidy/bugprone/PlacementNewTargetTypeMismatch.h @@ -0,0 +1,35 @@ +//===--- PlacementNewTargetTypeMismatch.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_PLACEMENTNEWTARGETTYPEMISMATCHCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_PLACEMENTNEWTARGETTYPEMISMATCHCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace bugprone { + +/// Finds placement-new calls where the pointer type of the adress mismatches +/// the type of the created value. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-placement-new-target-type-mismatch.html +class PlacementNewTargetTypeMismatch : public ClangTidyCheck { +public: + PlacementNewTargetTypeMismatch(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace bugprone +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_PLACEMENTNEWTARGETTYPEMISMATCHCHECK_H Index: clang-tidy/bugprone/PlacementNewTargetTypeMismatch.cpp =================================================================== --- /dev/null +++ clang-tidy/bugprone/PlacementNewTargetTypeMismatch.cpp @@ -0,0 +1,71 @@ +//===--- PlacementNewTargetTypeMismatch.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 "PlacementNewTargetTypeMismatch.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace bugprone { + +void PlacementNewTargetTypeMismatch::registerMatchers(MatchFinder *Finder) { + // We only want the records that call 'new' with an adress parameter + Finder->addMatcher(cxxNewExpr().bind("NewExpr"), this); +} + +void PlacementNewTargetTypeMismatch::check( + const MatchFinder::MatchResult &Result) { + const auto *NewExpr = Result.Nodes.getNodeAs("NewExpr"); + assert(NewExpr && "Matched node bound by 'NewExpr' shoud be a 'CXXNewExpr'"); + + if (0 == NewExpr->getNumPlacementArgs()) { + return; + } + + // fetch the cast from the Expr of the placement argument if it exists + const Expr *PlacementExpr = NewExpr->getPlacementArg(0); + assert(PlacementExpr != nullptr && "PlacementExpr should not be null"); + const CastExpr *Cast = dyn_cast(PlacementExpr); + if (nullptr == Cast) { + return; + } + + assert(Cast->getSubExpr()->getType()->isPointerType() && + "Cast of placement parameter requires a pointer type"); + const QualType &PlacementParameterType = + Cast->getSubExpr()->getType()->getPointeeType().getCanonicalType(); + // const Type *DesugaredSubExprType = SubExprType.getTypePtr(); + // if (nullptr == DesugaredSubExprType) { + // return; + // } + // const QualType &PlacementParameterType = + // DesugaredSubExprType->getPointeeType().getCanonicalType(); + const QualType &AllocatedType = + NewExpr->getAllocatedType().getCanonicalType(); + + if (PlacementParameterType != AllocatedType) { + diag(PlacementExpr->getExprLoc(), "placement new of incompatible types"); + // llvm::outs() << PlacementParameterType.getAsString() << " vs " + // << AllocatedType.getAsString() << "\n"; + + // llvm::outs() << "Placement:\n"; + // PlacementParameterType.getCanonicalType().dump(); + // llvm::outs() << "Allocated:\n"; + // AllocatedType.getCanonicalType().dump(); + // llvm::outs() << "SubExpr:\n"; + // SubExprType.getCanonicalType().dump(); + } +} + +} // namespace bugprone +} // namespace tidy +} // namespace clang Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -130,6 +130,12 @@ ` now supports `OverrideSpelling` and `FinalSpelling` options. +- New :doc:`bugprone-placement-new-target-type-mismatch + ` check. + + Finds placement-new calls where the pointer type of the adress mismatches the + type of the created value. + - New :doc:`openmp-exception-escape ` check. Index: docs/clang-tidy/checks/bugprone-placement-new-target-type-mismatch.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/bugprone-placement-new-target-type-mismatch.rst @@ -0,0 +1,8 @@ +.. title:: clang-tidy - bugprone-placement-new-target-type-mismatch + +bugprone-placement-new-target-type-mismatch +======================================= + +Finds placement-new calls where the pointer type of the adress mismatches the +type of the created value. + Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -55,6 +55,7 @@ bugprone-move-forwarding-reference bugprone-multiple-statement-macro bugprone-parent-virtual-call + bugprone-placement-new-target-type-mismatch bugprone-sizeof-container bugprone-sizeof-expression bugprone-string-constructor Index: test/clang-tidy/bugprone-placement-new-target-type-mismatch.cpp =================================================================== --- /dev/null +++ test/clang-tidy/bugprone-placement-new-target-type-mismatch.cpp @@ -0,0 +1,76 @@ +// RUN: %check_clang_tidy %s bugprone-placement-new-target-type-mismatch %t + +// definitions + +using size_type = unsigned long; +void *operator new(size_type, void *); +void *operator new[](size_type, void *); + +namespace std { +template T* addressof(T& arg) noexcept; +} // namespace std + +struct Foo { + int a; + int b; + int c; + int d; +}; + +template +T& getT() { + static T f; + return f; +} + +// instances emitting warnings + +void f1() { + struct Dummy { + int a; + int b; + }; + int *ptr = new int; + new (ptr) Dummy; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: placement new of incompatible types [bugprone-placement-new-target-type-mismatch] +} + +void f2() { + int * ptr = new int; + new (ptr) Foo; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: placement new of incompatible types [bugprone-placement-new-target-type-mismatch] +} + +void f3() { + char *ptr = new char[17*sizeof(char)]; + new (ptr) float[13]; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: placement new of incompatible types [bugprone-placement-new-target-type-mismatch] +} + +void f4() { + new (std::addressof(getT())) Foo; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: placement new of incompatible types [bugprone-placement-new-target-type-mismatch] +} + +void f5() { + char *ptr = new char[17*sizeof(char)]; + new (ptr) float{13.f}; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: placement new of incompatible types [bugprone-placement-new-target-type-mismatch] +} + +void f6() { + new ((void *)std::addressof(getT())) Foo; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: placement new of incompatible types [bugprone-placement-new-target-type-mismatch] +} + +// instances not emitting a warning + +void f7() { + Foo * ptr = new Foo; + new (ptr) Foo; +} + +void f8() { + char *ptr = new char[17*sizeof(char)]; + new((float *)ptr) float{13.f}; +} \ No newline at end of file