Skip to content

Commit e8a4c74

Browse files
committed
[clang-tidy] Added DefaultOperatorNewCheck.
Summary: Added new checker 'cert-default-operator-new' that checks for CERT rule MEM57-CPP. Simple version. Reviewers: aaron.ballman, alexfh, JonasToth, lebedev.ri Reviewed By: aaron.ballman Subscribers: hiraditya, martong, mehdi_amini, mgorny, inglorion, xazax.hun, dkrupp, steven_wu, dexonsmith, Szelethus, gamesh411, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D67545
1 parent 5f026b6 commit e8a4c74

File tree

9 files changed

+193
-5
lines changed

9 files changed

+193
-5
lines changed

clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "../performance/MoveConstructorInitCheck.h"
2020
#include "../readability/UppercaseLiteralSuffixCheck.h"
2121
#include "CommandProcessorCheck.h"
22+
#include "DefaultOperatorNewAlignmentCheck.h"
2223
#include "DontModifyStdNamespaceCheck.h"
2324
#include "FloatLoopCounter.h"
2425
#include "LimitedRandomnessCheck.h"
@@ -48,11 +49,6 @@ class CERTModule : public ClangTidyModule {
4849
"cert-dcl58-cpp");
4950
CheckFactories.registerCheck<google::build::UnnamedNamespaceInHeaderCheck>(
5051
"cert-dcl59-cpp");
51-
// OOP
52-
CheckFactories.registerCheck<performance::MoveConstructorInitCheck>(
53-
"cert-oop11-cpp");
54-
CheckFactories.registerCheck<bugprone::UnhandledSelfAssignmentCheck>(
55-
"cert-oop54-cpp");
5652
// ERR
5753
CheckFactories.registerCheck<misc::ThrowByValueCatchByReferenceCheck>(
5854
"cert-err09-cpp");
@@ -61,10 +57,18 @@ class CERTModule : public ClangTidyModule {
6157
CheckFactories.registerCheck<ThrownExceptionTypeCheck>("cert-err60-cpp");
6258
CheckFactories.registerCheck<misc::ThrowByValueCatchByReferenceCheck>(
6359
"cert-err61-cpp");
60+
// MEM
61+
CheckFactories.registerCheck<DefaultOperatorNewAlignmentCheck>(
62+
"cert-mem57-cpp");
6463
// MSC
6564
CheckFactories.registerCheck<LimitedRandomnessCheck>("cert-msc50-cpp");
6665
CheckFactories.registerCheck<ProperlySeededRandomGeneratorCheck>(
6766
"cert-msc51-cpp");
67+
// OOP
68+
CheckFactories.registerCheck<performance::MoveConstructorInitCheck>(
69+
"cert-oop11-cpp");
70+
CheckFactories.registerCheck<bugprone::UnhandledSelfAssignmentCheck>(
71+
"cert-oop54-cpp");
6872

6973
// C checkers
7074
// DCL

clang-tools-extra/clang-tidy/cert/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS support)
33
add_clang_library(clangTidyCERTModule
44
CERTTidyModule.cpp
55
CommandProcessorCheck.cpp
6+
DefaultOperatorNewAlignmentCheck.cpp
67
DontModifyStdNamespaceCheck.cpp
78
FloatLoopCounter.cpp
89
LimitedRandomnessCheck.cpp
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//===--- DefaultOperatorNewCheck.cpp - clang-tidy --------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "DefaultOperatorNewAlignmentCheck.h"
10+
#include "clang/AST/ASTContext.h"
11+
#include "clang/ASTMatchers/ASTMatchFinder.h"
12+
13+
using namespace clang::ast_matchers;
14+
15+
namespace clang {
16+
namespace tidy {
17+
namespace cert {
18+
19+
AST_MATCHER(CXXNewExpr, isPlacementNew) {
20+
return Node.getNumPlacementArgs() > 0;
21+
}
22+
23+
void DefaultOperatorNewAlignmentCheck::registerMatchers(MatchFinder *Finder) {
24+
// Check not applicable in C++17 (or newer).
25+
if (getLangOpts().CPlusPlus17)
26+
return;
27+
28+
Finder->addMatcher(cxxNewExpr(unless(isPlacementNew())).bind("new"), this);
29+
}
30+
31+
void DefaultOperatorNewAlignmentCheck::check(
32+
const MatchFinder::MatchResult &Result) {
33+
// Get the found 'new' expression.
34+
const auto *NewExpr = Result.Nodes.getNodeAs<CXXNewExpr>("new");
35+
36+
QualType T = NewExpr->getAllocatedType();
37+
// Dependent types do not have fixed alignment.
38+
if (T->isDependentType())
39+
return;
40+
const TagDecl *D = T->getAsTagDecl();
41+
// Alignment can not be obtained for undefined type.
42+
if (!D || !D->getDefinition() || !D->isCompleteDefinition())
43+
return;
44+
45+
ASTContext &Context = D->getASTContext();
46+
47+
// Check if no alignment was specified for the type.
48+
if (!Context.isAlignmentRequired(T))
49+
return;
50+
51+
// The user-specified alignment (in bits).
52+
unsigned SpecifiedAlignment = D->getMaxAlignment();
53+
// Double-check if no alignment was specified.
54+
if (!SpecifiedAlignment)
55+
return;
56+
// The alignment used by default 'operator new' (in bits).
57+
unsigned DefaultNewAlignment = Context.getTargetInfo().getNewAlign();
58+
59+
bool OverAligned = SpecifiedAlignment > DefaultNewAlignment;
60+
bool HasDefaultOperatorNew =
61+
!NewExpr->getOperatorNew() || NewExpr->getOperatorNew()->isImplicit();
62+
63+
unsigned CharWidth = Context.getTargetInfo().getCharWidth();
64+
if (HasDefaultOperatorNew && OverAligned)
65+
diag(NewExpr->getBeginLoc(),
66+
"allocation function returns a pointer with alignment %0 but the "
67+
"over-aligned type being allocated requires alignment %1")
68+
<< (DefaultNewAlignment / CharWidth)
69+
<< (SpecifiedAlignment / CharWidth);
70+
}
71+
72+
} // namespace cert
73+
} // namespace tidy
74+
} // namespace clang
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===--- DefaultOperatorNewCheck.h - clang-tidy -----------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_DEFAULTOPERATORNEWALIGNMENTCHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_DEFAULTOPERATORNEWALIGNMENTCHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
14+
namespace clang {
15+
namespace tidy {
16+
namespace cert {
17+
18+
/// Checks if an object of type with extended alignment is allocated by using
19+
/// the default operator new.
20+
///
21+
/// For the user-facing documentation see:
22+
/// http://clang.llvm.org/extra/clang-tidy/checks/cert-mem57-cpp.html
23+
class DefaultOperatorNewAlignmentCheck : public ClangTidyCheck {
24+
public:
25+
DefaultOperatorNewAlignmentCheck(StringRef Name, ClangTidyContext *Context)
26+
: ClangTidyCheck(Name, Context) {}
27+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
28+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
29+
};
30+
31+
} // namespace cert
32+
} // namespace tidy
33+
} // namespace clang
34+
35+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_DEFAULTOPERATORNEWALIGNMENTCHECK_H

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ Improvements to clang-tidy
9494
Without the null terminator it can result in undefined behaviour when the
9595
string is read.
9696

97+
- New :doc:`cert-mem57-cpp
98+
<clang-tidy/checks/cert-mem57-cpp>` check.
99+
100+
Checks if an object of type with extended alignment is allocated by using
101+
the default ``operator new``.
102+
97103
- New alias :doc:`cert-pos44-c
98104
<clang-tidy/checks/cert-pos44-c>` to
99105
:doc:`bugprone-bad-signal-to-kill-thread
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.. title:: clang-tidy - cert-mem57-cpp
2+
3+
cert-mem57-cpp
4+
==============
5+
6+
This check flags uses of default ``operator new`` where the type has extended
7+
alignment (an alignment greater than the fundamental alignment). (The default
8+
``operator new`` is guaranteed to provide the correct alignmment if the
9+
requested alignment is less or equal to the fundamental alignment).
10+
Only cases are detected (by design) where the ``operator new`` is not
11+
user-defined and is not a placement new (the reason is that in these cases we
12+
assume that the user provided the correct memory allocation).
13+
14+
This check corresponds to the CERT C++ Coding Standard rule
15+
`MEM57-CPP. Avoid using default operator new for over-aligned types
16+
<https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM57-CPP.+Avoid+using+default+operator+new+for+over-aligned+types>`_.

clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ Clang-Tidy Checks
100100
cert-err61-cpp (redirects to misc-throw-by-value-catch-by-reference) <cert-err61-cpp>
101101
cert-fio38-c (redirects to misc-non-copyable-objects) <cert-fio38-c>
102102
cert-flp30-c
103+
cert-mem57-cpp
103104
cert-msc30-c (redirects to cert-msc50-cpp) <cert-msc30-c>
104105
cert-msc32-c (redirects to cert-msc51-cpp) <cert-msc32-c>
105106
cert-msc50-cpp
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %check_clang_tidy %s -std=c++14 cert-mem57-cpp %t
2+
// RUN: clang-tidy --extra-arg='-std=c++17' -checks='-*,cert-mem57-cpp' --warnings-as-errors='*' %s
3+
// RUN: clang-tidy --extra-arg='-std=c++2a' -checks='-*,cert-mem57-cpp' --warnings-as-errors='*' %s
4+
5+
struct alignas(32) Vector {
6+
char Elems[32];
7+
};
8+
9+
void f() {
10+
auto *V1 = new Vector; // CHECK-MESSAGES: warning: allocation function returns a pointer with alignment 16 but the over-aligned type being allocated requires alignment 32 [cert-mem57-cpp]
11+
auto *V1_Arr = new Vector[2]; // CHECK-MESSAGES: warning: allocation function returns a pointer with alignment 16 but the over-aligned type being allocated requires alignment 32 [cert-mem57-cpp]
12+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %check_clang_tidy %s -std=c++14 cert-mem57-cpp %t
2+
3+
namespace std {
4+
typedef __typeof(sizeof(int)) size_t;
5+
void *aligned_alloc(size_t, size_t);
6+
void free(void *);
7+
} // namespace std
8+
9+
struct alignas(32) Vector1 {
10+
char elems[32];
11+
};
12+
13+
struct Vector2 {
14+
char elems[32];
15+
};
16+
17+
struct alignas(32) Vector3 {
18+
char elems[32];
19+
static void *operator new(std::size_t nbytes) noexcept(true) {
20+
return std::aligned_alloc(alignof(Vector3), nbytes);
21+
}
22+
static void operator delete(void *p) {
23+
std::free(p);
24+
}
25+
};
26+
27+
struct alignas(8) Vector4 {
28+
char elems[32];
29+
};
30+
31+
void f() {
32+
auto *V1 = new Vector1;
33+
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: allocation function returns a pointer with alignment 16 but the over-aligned type being allocated requires alignment 32 [cert-mem57-cpp]
34+
auto *V2 = new Vector2;
35+
auto *V3 = new Vector3;
36+
auto *V4 = new Vector4;
37+
auto *V1_Arr = new Vector1[2];
38+
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: allocation function returns a pointer with alignment 16 but the over-aligned type being allocated requires alignment 32 [cert-mem57-cpp]
39+
}

0 commit comments

Comments
 (0)