[clang] [attributes][-Wunsafe-buffer-usage] Support adding unsafe_buffer_usage attribute to struct fields (PR #101585)

Malavika Samak via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 13 14:32:11 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}}
----------------
malavikasamak wrote:

I will add this to the tests. Clang allows adding the attribute for the anonymous struct in your example. Looks like it treats inner structs as a member as well. However, because the attribute is not explicitly attached to the field 'a', it doesn't issue any warning.

https://github.com/llvm/llvm-project/pull/101585


More information about the cfe-commits mailing list