aboutsummaryrefslogtreecommitdiff
path: root/clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp
blob: 08707d7ff545d8c48c3e4a1db943cb91d3edc1d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// RUN: %clang_cc1 -std=c++20  -Wno-all -Wunsafe-buffer-usage -Wno-unsafe-buffer-usage-in-container\
// RUN:            -fsafe-buffer-usage-suggestions \
// RUN:            -fblocks -include %s -verify %s

// RUN: %clang -x c++ -frtti -fsyntax-only -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s
// RUN: %clang_cc1 -std=c++11 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s
// RUN: %clang_cc1 -std=c++20 -fblocks -include %s %s 2>&1 | FileCheck --allow-empty %s
// CHECK-NOT: [-Wunsafe-buffer-usage]

#ifndef INCLUDED
#define INCLUDED
#pragma clang system_header

// no spanification warnings for system headers
#else

typedef __INTPTR_TYPE__ intptr_t;

namespace std {
  class type_info;
  class bad_cast;
  class bad_typeid;
}
using size_t = __typeof(sizeof(int));
void *malloc(size_t);

void foo(int v) {
}

void foo(int *p){}

namespace std{
  template <typename T> class span {

  T *elements;
 
  span(T *, unsigned){}

  public:

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

  constexpr T* data() const noexcept {
    return elements;
  }

 
  constexpr T* hello() const noexcept {
   return elements;
  }
};
 
 template <typename T> class span_duplicate {
  span_duplicate(T *, unsigned){}

  T array[10];

  public:

  T* data() {
    return array;
  }

};
}

using namespace std;

class A {
  int a, b, c;
};

class B {
  int a, b, c;
};

struct Base {
   virtual ~Base() = default;
};

struct Derived: Base {
  int d;
};

void cast_without_data(int *ptr) {
 A *a = (A*) ptr;
 float *p = (float*) ptr;
}

void warned_patterns(std::span<int> span_ptr, std::span<Base> base_span, span<int> span_without_qual) {
    A *a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of span::data}}
    a1 = (A*)span_ptr.data(); // expected-warning{{unsafe invocation of span::data}}

    a1 = (A*)(span_ptr.data()); // expected-warning{{unsafe invocation of span::data}}
    A *a2 = (A*) (span_without_qual.data()); // expected-warning{{unsafe invocation of span::data}}

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

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

    // TODO:: This pattern is safe. We can add special handling for it, if we decide this
    // is the recommended fixit for the unsafe invocations.
    A *a3 = (A*)span_ptr.subspan(0, sizeof(A)).data(); // expected-warning{{unsafe invocation of span::data}}
}

void not_warned_patterns(std::span<A> span_ptr, std::span<Base> base_span) {
    int *p = (int*) span_ptr.data(); // Cast to a smaller type
  
    B *b = (B*) span_ptr.data(); // Cast to a type of same size.

    p = (int*) span_ptr.data();
    A *a = (A*) span_ptr.hello(); // Invoking other methods.
   
     intptr_t k = (intptr_t) span_ptr.data();
    k = (intptr_t) (span_ptr.data());
}

// We do not want to warn about other types
void other_classes(std::span_duplicate<int> span_ptr) {
    int *p;
    A *a = (A*)span_ptr.data();
    a = (A*)span_ptr.data(); 
}

// Potential source for false negatives

A false_negatives(std::span<int> span_pt, span<A> span_A) {
  int *ptr = span_pt.data();

  A *a1 = (A*)ptr; //TODO: We want to warn here eventually.

  A *a2= span_A.data();
  return *a2; // TODO: Can cause OOB if span_pt is empty

}
#endif