Skip to content

Commit f2eb00d

Browse files
committed
updated documentation, changed options
1 parent 95634ba commit f2eb00d

File tree

4 files changed

+82
-85
lines changed

4 files changed

+82
-85
lines changed

clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.cpp

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,42 +17,31 @@ namespace clang::tidy::bugprone {
1717

1818
CastToStructCheck::CastToStructCheck(StringRef Name, ClangTidyContext *Context)
1919
: ClangTidyCheck(Name, Context),
20-
IgnoredFunctions(
21-
utils::options::parseStringList(Options.get("IgnoredFunctions", ""))),
22-
IgnoredFromTypes(
23-
utils::options::parseStringList(Options.get("IgnoredFromTypes", ""))),
24-
IgnoredToTypes(
25-
utils::options::parseStringList(Options.get("IgnoredToTypes", ""))) {}
20+
IgnoredCasts(
21+
utils::options::parseStringList(Options.get("IgnoredCasts", ""))) {}
2622

2723
void CastToStructCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
28-
Options.store(Opts, "IgnoredFunctions",
29-
utils::options::serializeStringList(IgnoredFunctions));
30-
Options.store(Opts, "IgnoredFromTypes",
31-
utils::options::serializeStringList(IgnoredFromTypes));
32-
Options.store(Opts, "IgnoredToTypes",
33-
utils::options::serializeStringList(IgnoredToTypes));
24+
Options.store(Opts, "IgnoredCasts",
25+
utils::options::serializeStringList(IgnoredCasts));
3426
}
3527

3628
void CastToStructCheck::registerMatchers(MatchFinder *Finder) {
3729
auto FromPointee =
3830
qualType(hasUnqualifiedDesugaredType(type().bind("FromType")),
39-
unless(qualType(matchers::matchesAnyListedTypeName(
40-
IgnoredFromTypes, false))))
31+
unless(voidType()),
32+
unless(hasDeclaration(recordDecl(isUnion()))))
4133
.bind("FromPointee");
4234
auto ToPointee =
43-
qualType(hasUnqualifiedDesugaredType(recordType().bind("ToType")),
44-
unless(qualType(
45-
matchers::matchesAnyListedTypeName(IgnoredToTypes, false))))
35+
qualType(hasUnqualifiedDesugaredType(
36+
recordType(unless(hasDeclaration(recordDecl(isUnion()))))
37+
.bind("ToType")))
4638
.bind("ToPointee");
4739
auto FromPtrType = qualType(pointsTo(FromPointee)).bind("FromPtr");
4840
auto ToPtrType = qualType(pointsTo(ToPointee)).bind("ToPtr");
49-
Finder->addMatcher(
50-
cStyleCastExpr(hasSourceExpression(hasType(FromPtrType)),
51-
hasType(ToPtrType),
52-
unless(hasAncestor(functionDecl(
53-
matchers::matchesAnyListedName(IgnoredFunctions)))))
54-
.bind("CastExpr"),
55-
this);
41+
Finder->addMatcher(cStyleCastExpr(hasSourceExpression(hasType(FromPtrType)),
42+
hasType(ToPtrType))
43+
.bind("CastExpr"),
44+
this);
5645
}
5746

5847
void CastToStructCheck::check(const MatchFinder::MatchResult &Result) {
@@ -65,13 +54,24 @@ void CastToStructCheck::check(const MatchFinder::MatchResult &Result) {
6554
const auto *const ToPointee = Result.Nodes.getNodeAs<QualType>("ToPointee");
6655
const auto *const FromType = Result.Nodes.getNodeAs<Type>("FromType");
6756
const auto *const ToType = Result.Nodes.getNodeAs<RecordType>("ToType");
68-
if (!FromPointee || !ToPointee)
69-
return;
70-
if (FromType->isVoidType() || FromType->isUnionType() ||
71-
ToType->isUnionType())
72-
return;
57+
7358
if (FromType == ToType)
7459
return;
60+
61+
const std::string FromName = FromPointee->getAsString();
62+
const std::string ToName = ToPointee->getAsString();
63+
llvm::Regex FromR;
64+
llvm::Regex ToR;
65+
for (auto [Idx, Str] : llvm::enumerate(IgnoredCasts)) {
66+
if (Idx % 2 == 0) {
67+
FromR = llvm::Regex(Str);
68+
} else {
69+
ToR = llvm::Regex(Str);
70+
if (FromR.match(FromName) && ToR.match(ToName))
71+
return;
72+
}
73+
}
74+
7575
diag(FoundCastExpr->getExprLoc(),
7676
"casting a %0 pointer to a "
7777
"%1 pointer and accessing a field can lead to memory "

clang-tools-extra/clang-tidy/bugprone/CastToStructCheck.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ class CastToStructCheck : public ClangTidyCheck {
2929
}
3030

3131
private:
32-
std::vector<llvm::StringRef> IgnoredFunctions;
33-
std::vector<llvm::StringRef> IgnoredFromTypes;
34-
std::vector<llvm::StringRef> IgnoredToTypes;
32+
std::vector<llvm::StringRef> IgnoredCasts;
3533
};
3634

3735
} // namespace clang::tidy::bugprone

clang-tools-extra/docs/clang-tidy/checks/bugprone/cast-to-struct.rst

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ bugprone-cast-to-struct
66
Finds casts from pointers to struct or scalar type to pointers to struct type.
77

88
Casts between pointers to different structs can be unsafe because it is possible
9-
to access uninitialized or undefined data after the cast. There may be issues
10-
with type compatibility or data alignment. Cast from a pointer to a scalar type
11-
(which points often to an array or memory block) to a `struct` type pointer can
12-
be unsafe for similar reasons. This check warns at casts from any non-`struct`
13-
type to a `struct` type. No warning is produced at cast from type `void *` (this
14-
is the usual way of allocating memory with `malloc`-like functions). It is
15-
possible to specify additional types to ignore by the check. In addition,
16-
`union` types are completely excluded from the check. The check does not take
17-
into account type compatibility or data layout, only the names of the types.
9+
to access uninitialized or undefined data after the cast. Cast from a
10+
scalar-type pointer (which points often to an array or memory block) to a
11+
``struct`` type pointer can be unsafe for similar reasons. This check warns at
12+
pointer casts from any non-struct type to a struct type. No warning is produced
13+
at cast from type ``void *`` (this is the usual way of allocating memory with
14+
``malloc``-like functions). In addition, ``union`` types are excluded from the
15+
check. It is possible to specify additional types to ignore. The check does not
16+
take into account type compatibility or data layout, only the names of the
17+
types.
1818

1919
.. code-block:: c
2020
@@ -33,22 +33,28 @@ into account type compatibility or data layout, only the names of the types.
3333
s = (struct S1 *)calloc(1, sizeof(struct S1)); // no warning
3434
}
3535
36-
Options
37-
-------
38-
39-
.. option:: IgnoredFromTypes
36+
Limitations
37+
-----------
4038

41-
Semicolon-separated list of types for which the checker should not warn if
42-
encountered at cast source. Can contain regular expressions. The `*`
43-
character (for pointer type) is not needed in the type names.
39+
The check does run only on `C` code.
4440

45-
.. option:: IgnoredToTypes
41+
C-style casts are discouraged in `C++` and should be converted to more type-safe
42+
casts. The ``reinterpreted_cast`` is used for the most unsafe cases and
43+
indicates by itself a potentially dangerous operation. Additionally, inheritance
44+
and dynamic types would make such a check less useful.
4645

47-
Semicolon-separated list of types for which the checker should not warn if
48-
encountered at cast destination. Can contain regular expressions. The `*`
49-
character (for pointer type) is not needed in the type names.
50-
51-
.. option:: IgnoredFunctions
46+
Options
47+
-------
5248

53-
List of function names from which the checker should produce no warnings. Can
54-
contain regular expressions.
49+
.. option:: IgnoredCasts
50+
51+
Can contain a semicolon-separated list of type names that specify cast
52+
types to ignore. The list should contain pairs of type names in a way that
53+
the first type is the "from" type, the second is the "to" type in a cast
54+
expression. The types in a pair and the pairs itself are separated by
55+
``;`` characters. For example ``char;Type1;char;Type2`` specifies that the
56+
check does not produce warning for casts from ``char *`` to ``Type1 *`` and
57+
casts from ``char *`` to ``Type2 *``. The list entries can be regular
58+
expressions. The type name in the cast expression is matched without
59+
resolution of type aliases like ``typedef``. Default value is empty list.
60+
(Casts from ``void *`` are ignored always regardless of this list.)
Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,33 @@
1-
// RUN: %check_clang_tidy -check-suffixes=FUNC %s bugprone-cast-to-struct %t -- \
2-
// RUN: -config="{CheckOptions: {bugprone-cast-to-struct.IgnoredFunctions: 'ignored_f$'}}"
3-
// RUN: %check_clang_tidy -check-suffixes=FROM-TY %s bugprone-cast-to-struct %t -- \
4-
// RUN: -config="{CheckOptions: {bugprone-cast-to-struct.IgnoredFromTypes: 'int'}}"
5-
// RUN: %check_clang_tidy -check-suffixes=TO-TY %s bugprone-cast-to-struct %t -- \
6-
// RUN: -config="{CheckOptions: {bugprone-cast-to-struct.IgnoredToTypes: 'IgnoredType'}}"
1+
// RUN: %check_clang_tidy %s bugprone-cast-to-struct %t -- \
2+
// RUN: -config="{CheckOptions: {bugprone-cast-to-struct.IgnoredCasts: 'char;S1;int;Other*'}}"
73

8-
struct IgnoredType {
4+
struct S1 {
95
int a;
106
};
117

12-
struct OtherType {
8+
struct S2 {
9+
char a;
10+
};
11+
12+
struct OtherS {
1313
int a;
1414
int b;
1515
};
1616

17-
void ignored_f(char *p) {
18-
struct OtherType *p1;
19-
p1 = (struct OtherType *)p;
20-
// CHECK-MESSAGES-FROM-TY: :[[@LINE-1]]:8: warning: casting a 'char *' pointer to a 'struct OtherType *' pointer and accessing a field can lead to memory access errors or data corruption
21-
// CHECK-MESSAGES-TO-TY: :[[@LINE-2]]:8: warning: casting a 'char *' pointer to a 'struct OtherType *' pointer and accessing a field can lead to memory access errors or data corruption
22-
}
23-
24-
void ignored_from_type(int *p) {
25-
struct OtherType *p1;
26-
p1 = (struct OtherType *)p;
27-
// CHECK-MESSAGES-FUNC: :[[@LINE-1]]:8: warning: casting a 'int *' pointer to a 'struct OtherType *' pointer and accessing a field can lead to memory access errors or data corruption
28-
// CHECK-MESSAGES-TO-TY: :[[@LINE-2]]:8: warning: casting a 'int *' pointer to a 'struct OtherType *' pointer and accessing a field can lead to memory access errors or data corruption
29-
}
30-
31-
void ignored_to_type(char *p) {
32-
struct IgnoredType *p1;
33-
p1 = (struct IgnoredType *)p;
34-
// CHECK-MESSAGES-FUNC: :[[@LINE-1]]:8: warning: casting a 'char *' pointer to a 'struct IgnoredType *' pointer and accessing a field can lead to memory access errors or data corruption
35-
// CHECK-MESSAGES-FROM-TY: :[[@LINE-2]]:8: warning: casting a 'char *' pointer to a 'struct IgnoredType *' pointer and accessing a field can lead to memory access errors or data corruption
17+
void test1(char *p1, int *p2) {
18+
struct S1 *s1;
19+
s1 = (struct S1 *)p1;
20+
struct S2 *s2;
21+
s2 = (struct S2 *)p1;
22+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: casting a 'char *' pointer to a 'struct S2 *'
23+
s2 = (struct S2 *)p2;
24+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: casting a 'int *' pointer to a 'struct S2 *'
25+
struct OtherS *s3;
26+
s3 = (struct OtherS *)p2;
27+
s3 = (struct OtherS *)p1;
28+
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: casting a 'char *' pointer to a 'struct OtherS *'
3629
}
3730

38-
struct OtherType *test_void_is_always_ignored(void *p) {
39-
return (struct OtherType *)p;
31+
struct S2 *test_void_is_always_ignored(void *p) {
32+
return (struct S2 *)p;
4033
}

0 commit comments

Comments
 (0)