[clang] [attributes][-Wunsafe-buffer-usage] Support adding unsafe_buffer_usage attribute to struct fields (PR #101585)
Artem Dergachev via cfe-commits
cfe-commits at lists.llvm.org
Tue Aug 6 13:27:03 PDT 2024
================
@@ -0,0 +1,180 @@
+// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
+// RUN: -fsafe-buffer-usage-suggestions -verify %s
+
+using size_t = __typeof(sizeof(int));
+
+namespace std {
+ class type_info;
+ class bad_cast;
+ class bad_typeid;
+
+ template <typename T> class span {
+
+ private:
+ T *elements;
+ size_t size_;
+
+ public:
+ span(T *, size_t){}
+
+ constexpr T* data() const noexcept {
+ return elements;
+ }
+
+ constexpr size_t size() const noexcept {
+ return size_;
+ }
+
+ };
+}
+
+struct A {
+ [[clang::unsafe_buffer_usage]]
+ int *ptr;
+
+ size_t sz;
+};
+
+struct B {
+ A a;
+
+ [[clang::unsafe_buffer_usage]]
+ int buf[];
+};
+
+struct D {
+ [[clang::unsafe_buffer_usage]]
+ int *ptr, *ptr2;
+
+ [[clang::unsafe_buffer_usage]]
+ int buf[10];
+
+ size_t sz;
+
+};
+
+void foo(int *ptr);
+
+void foo_safe(std::span<int> sp);
+
+int* test_atribute_struct(A a) {
+ int b = *(a.ptr); //expected-warning{{field 'ptr' prone to unsafe buffer manipulation}}
+ a.sz++;
+ // expected-warning at +1{{unsafe pointer arithmetic}}
+ return a.ptr++; //expected-warning{{field 'ptr' prone to unsafe buffer manipulation}}
+}
+
+void test_attribute_field_deref_chain(B b) {
+ int *ptr = b.a.ptr;//expected-warning{{field 'ptr' prone to unsafe buffer manipulation}}
+ foo(b.buf); //expected-warning{{field 'buf' prone to unsafe buffer manipulation}}
+}
+
+void test_safe_writes(std::span<int> sp) {
+ A a;
+ // TODO: We should not warn for safe assignments from hardened types
+ a.ptr = sp.data(); //expected-warning{{field 'ptr' prone to unsafe buffer manipulation}}
+ a.sz = sp.size();
+
+ a.ptr = nullptr; // expected-warning{{field 'ptr' prone to unsafe buffer manipulation}}
+}
+
+void test_safe_reads(A a, A b) {
+ //expected-warning at +1{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
+ std::span<int> sp {a.ptr, a.sz}; //expected-warning{{field 'ptr' prone to unsafe buffer manipulation}}
+
+ // expected-warning at +1 3{{field 'ptr' prone to unsafe buffer manipulation}}
+ if(a.ptr != nullptr && a.ptr != b.ptr) {
+ foo_safe(sp);
+ }
+
+}
+
+void test_attribute_multiple_fields (D d) {
+ int *p =d.ptr; //expected-warning{{field 'ptr' prone to unsafe buffer manipulation}}
+ p = d.ptr2; //expected-warning{{field 'ptr2' prone to unsafe buffer manipulation}}
+
+ p = d.buf; //expected-warning{{field 'buf' prone to unsafe buffer manipulation}}
+
+ int v = d.buf[0]; //expected-warning{{field 'buf' prone to unsafe buffer manipulation}}
+
+ //expected-warning at +1{{unsafe buffer access}}
+ v = d.buf[5]; //expected-warning{{field 'buf' prone to unsafe buffer manipulation}}
+}
+
+template <typename T>
+struct TemplateArray {
+ [[clang::unsafe_buffer_usage]]
+ T *buf;
+
+ [[clang::unsafe_buffer_usage]]
+ size_t sz;
+};
+
+
+void test_struct_template (TemplateArray<int> t) {
+ int *p = t.buf; //expected-warning{{field 'buf' prone to unsafe buffer manipulation}}
+ size_t s = t.sz; //expected-warning{{field 'sz' prone to unsafe buffer manipulation}}
+}
+
+class R {
+ [[clang::unsafe_buffer_usage]]
+ int *array;
+
+ public:
+ int* getArray() {
+ return array; //expected-warning{{field 'array' prone to unsafe buffer manipulation}}
+ }
+
+ void setArray(int *arr) {
+ array = arr; //expected-warning{{field 'array' prone to unsafe buffer manipulation}}
+ }
+};
+
+template<class P>
+class Q {
+ [[clang::unsafe_buffer_usage]]
+ P *array;
+
+ public:
+ P* getArray() {
+ return array; //expected-warning{{field 'array' prone to unsafe buffer manipulation}}
+ }
+
+ void setArray(P *arr) {
+ array = arr; //expected-warning{{field 'array' prone to unsafe buffer manipulation}}
+ }
+};
+
+void test_class_template(Q<R> q) {
+ q.getArray();
+ q.setArray(nullptr);
+}
+
+struct AnonFields {
+ struct {
+ [[clang::unsafe_buffer_usage]]
+ int a;
+ };
+};
+
+void test_anon_fields(AnonFields anon) {
+ int val = anon.a; //expected-warning{{field 'a' prone to unsafe buffer manipulation}}
----------------
haoNoQ wrote:
In this case the field isn't anonymous, only the parent field is anonymous.
I wonder if this works too:
```
struct AnonFields {
[[clang::unsafe_buffer_usage]]
struct {
int a;
};
};
```
But this would probably cause the attribute to try to get attached to the struct decl, not to the field decl? So I'm not really aware of a realistic way to trigger this kind of problem.
But in case of functions this is going to be way more common. Eg., every overloaded operator is basically an anonymous function. ObjC methods are named but their names aren't simple identifiers so this is another source of crashes. Blocks... exist.
https://github.com/llvm/llvm-project/pull/101585
More information about the cfe-commits
mailing list