Skip to content

Commit dd02857

Browse files
Merge pull request #9584 from swiftlang/msamak-cherrypick-vector-data
Cherrypick [-Wunsafe-buffer-usage] Emit a warning if pointer returned by vector::data and array::data is cast to larger type
2 parents 7649a05 + 5cb47bd commit dd02857

File tree

4 files changed

+82
-33
lines changed

4 files changed

+82
-33
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12475,7 +12475,7 @@ def warn_unsafe_buffer_variable : Warning<
1247512475
InGroup<UnsafeBufferUsage>, DefaultIgnore;
1247612476
def warn_unsafe_buffer_operation : Warning<
1247712477
"%select{unsafe pointer operation|unsafe pointer arithmetic|"
12478-
"unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of span::data|"
12478+
"unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of %1|"
1247912479
"field %1 prone to unsafe buffer manipulation}0">,
1248012480
InGroup<UnsafeBufferUsage>, DefaultIgnore;
1248112481
def warn_unsafe_buffer_libc_call : Warning<

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,8 +1505,11 @@ class DataInvocationGadget : public WarningGadget {
15051505
}
15061506

15071507
static Matcher matcher() {
1508-
Matcher callExpr = cxxMemberCallExpr(
1509-
callee(cxxMethodDecl(hasName("data"), ofClass(hasName("std::span")))));
1508+
1509+
Matcher callExpr = cxxMemberCallExpr(callee(
1510+
cxxMethodDecl(hasName("data"),
1511+
ofClass(anyOf(hasName("std::span"), hasName("std::array"),
1512+
hasName("std::vector"))))));
15101513
return stmt(
15111514
explicitCastExpr(anyOf(has(callExpr), has(parenExpr(has(callExpr)))))
15121515
.bind(OpTag));

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,9 +2279,18 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
22792279
QualType srcType = ECE->getSubExpr()->getType();
22802280
const uint64_t sSize =
22812281
Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType());
2282+
22822283
if (sSize >= dSize)
22832284
return;
22842285

2286+
if (const auto *CE = dyn_cast<CXXMemberCallExpr>(
2287+
ECE->getSubExpr()->IgnoreParens())) {
2288+
D = CE->getMethodDecl();
2289+
}
2290+
2291+
if (!D)
2292+
return;
2293+
22852294
MsgParam = 4;
22862295
}
22872296
Loc = Operation->getBeginLoc();

clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,38 +32,68 @@ void foo(int *p){}
3232
namespace std{
3333
template <typename T> class span {
3434

35-
T *elements;
35+
T *elements;
3636

37-
span(T *, unsigned){}
37+
span(T *, unsigned){}
3838

39-
public:
39+
public:
4040

41-
constexpr span<T> subspan(size_t offset, size_t count) const {
42-
return span<T> (elements+offset, count); // expected-warning{{unsafe pointer arithmetic}}
43-
}
41+
constexpr span<T> subspan(size_t offset, size_t count) const {
42+
return span<T> (elements+offset, count); // expected-warning{{unsafe pointer arithmetic}}
43+
}
4444

45-
constexpr T* data() const noexcept {
46-
return elements;
47-
}
45+
constexpr T* data() const noexcept {
46+
return elements;
47+
}
48+
49+
constexpr T* hello() const noexcept {
50+
return elements;
51+
}
52+
};
53+
54+
template <typename T> class vector {
55+
56+
T *elements;
57+
58+
public:
59+
60+
vector(size_t n) {
61+
elements = new T[n];
62+
}
63+
64+
constexpr T* data() const noexcept {
65+
return elements;
66+
}
67+
68+
~vector() {
69+
delete[] elements;
70+
}
71+
};
72+
73+
template <class T, size_t N>
74+
class array {
75+
T elements[N];
76+
77+
public:
78+
79+
constexpr const T* data() const noexcept {
80+
return elements;
81+
}
82+
83+
};
4884

49-
50-
constexpr T* hello() const noexcept {
51-
return elements;
52-
}
53-
};
54-
5585
template <typename T> class span_duplicate {
56-
span_duplicate(T *, unsigned){}
86+
span_duplicate(T *, unsigned){}
5787

58-
T array[10];
88+
T array[10];
5989

60-
public:
90+
public:
6191

62-
T* data() {
63-
return array;
64-
}
92+
T* data() {
93+
return array;
94+
}
6595

66-
};
96+
};
6797
}
6898

6999
using namespace std;
@@ -89,21 +119,28 @@ void cast_without_data(int *ptr) {
89119
float *p = (float*) ptr;
90120
}
91121

92-
void warned_patterns(std::span<int> span_ptr, std::span<Base> base_span, span<int> span_without_qual) {
93-
A *a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of span::data}}
94-
a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of span::data}}
122+
void warned_patterns_span(std::span<int> span_ptr, std::span<Base> base_span, span<int> span_without_qual) {
123+
A *a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of 'data'}}
124+
a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of 'data'}}
95125

96-
a1 = (A*)(span_ptr.data()); // expected-warning{{unsafe invocation of span::data}}
97-
A *a2 = (A*) (span_without_qual.data()); // expected-warning{{unsafe invocation of span::data}}
126+
a1 = (A*)(span_ptr.data()); // expected-warning{{unsafe invocation of 'data'}}
127+
A *a2 = (A*) (span_without_qual.data()); // expected-warning{{unsafe invocation of 'data'}}
98128

99-
a2 = (A*) span_without_qual.data(); // expected-warning{{unsafe invocation of span::data}}
129+
a2 = (A*) span_without_qual.data(); // expected-warning{{unsafe invocation of 'data'}}
100130

101131
// TODO:: Should we warn when we cast from base to derived type?
102-
Derived *b = dynamic_cast<Derived*> (base_span.data());// expected-warning{{unsafe invocation of span::data}}
132+
Derived *b = dynamic_cast<Derived*> (base_span.data());// expected-warning{{unsafe invocation of 'data'}}
103133

104134
// TODO:: This pattern is safe. We can add special handling for it, if we decide this
105135
// is the recommended fixit for the unsafe invocations.
106-
A *a3 = (A*)span_ptr.subspan(0, sizeof(A)).data(); // expected-warning{{unsafe invocation of span::data}}
136+
A *a3 = (A*)span_ptr.subspan(0, sizeof(A)).data(); // expected-warning{{unsafe invocation of 'data'}}
137+
}
138+
139+
void warned_patterns_array(std::array<int, 5> array_ptr, std::array<Base, 10> base_span, span<int> span_without_qual) {
140+
const A *a1 = (A*)array_ptr.data(); // expected-warning{{unsafe invocation of 'data'}}
141+
a1 = (A*)array_ptr.data(); // expected-warning{{unsafe invocation of 'data'}}
142+
143+
a1 = (A*)(array_ptr.data()); // expected-warning{{unsafe invocation of 'data'}}
107144
}
108145

109146
void not_warned_patterns(std::span<A> span_ptr, std::span<Base> base_span) {

0 commit comments

Comments
 (0)