xref: /llvm-project/clang/test/Analysis/pointer-sub.c (revision f74f568b29885c3fa63c44e33f91f3bb7281138e)
1 // RUN: %clang_analyze_cc1 -analyzer-checker=security.PointerSub -analyzer-output=text-minimal -verify %s
2 
3 typedef int * Ptr;
4 
5 void f1(void) {
6   int x, y, z[10];
7   int d = &y - &x; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
8   d = z - &y; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
9   d = &x - &x; // no-warning (subtraction of any two identical pointers is allowed)
10   d = (long *)&x - (long *)&x;
11   d = (&x + 1) - &x; // no-warning ('&x' is like a single-element array)
12   d = &x - (&x + 1); // no-warning
13   d = (&x + 0) - &x; // no-warning
14   d = (z + 10) - z; // no-warning
15   d = (long long)&y - (long long)&x; // no-warning
16   long long l = 1;
17   d = l - (long long)&y; // no-warning
18   Ptr p1 = &x;
19   Ptr p2 = &y;
20   d = p1 - p2; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
21 }
22 
23 void f2(void) {
24   int a[10], b[10], c; // expected-note{{Array at the left-hand side of subtraction}} \
25                        // expected-note2{{Array at the right-hand side of subtraction}}
26   int *p = &a[2];
27   int *q = &a[8];
28   int d = q - p; // no-warning (pointers into the same array)
29 
30   q = &b[3];
31   d = q - p; // expected-warning{{Subtraction of two pointers that}}
32 
33   d = &a[4] - a; // no-warning
34   d = &a[2] - p; // no-warning
35   d = &c - p; // expected-warning{{Subtraction of two pointers that}}
36 
37   d = (int *)((char *)(&a[4]) + sizeof(int)) - &a[4]; // no-warning (pointers into the same array data)
38   d = (int *)((char *)(&a[4]) + 1) - &a[4]; // expected-warning{{Subtraction of two pointers that}}
39 
40   long long a1 = (long long)&a[1];
41   long long b1 = (long long)&b[1];
42   d = a1 - b1;
43 }
44 
45 void f3(void) {
46   int a[3][4]; // expected-note{{Array at the left-hand side of subtraction}} \
47                // expected-note2{{Array at the right-hand side of subtraction}}
48   int d;
49 
50   d = &(a[2]) - &(a[1]);
51   d = a[2] - a[1]; // expected-warning{{Subtraction of two pointers that}}
52   d = a[1] - a[1];
53   d = &(a[1][2]) - &(a[1][0]);
54   d = &(a[1][2]) - &(a[0][0]); // expected-warning{{Subtraction of two pointers that}}
55 
56   d = (int *)((char *)(&a[2][2]) + sizeof(int)) - &a[2][2]; // expected-warning{{Subtraction of two pointers that}}
57   d = (int *)((char *)(&a[2][2]) + 1) - &a[2][2]; // expected-warning{{Subtraction of two pointers that}}
58   d = (int (*)[4])((char *)&a[2] + sizeof(int (*)[4])) - &a[2]; // expected-warning{{Subtraction of two pointers that}}
59   d = (int (*)[4])((char *)&a[2] + 1) - &a[2]; // expected-warning{{Subtraction of two pointers that}}
60 }
61 
62 void f4(void) {
63   int n = 4, m = 3;
64   int a[n][m];
65   int (*p)[m] = a; // p == &a[0]
66   p += 1; // p == &a[1]
67 
68   // FIXME: This is a known problem with -Wpointer-arith (https://github.com/llvm/llvm-project/issues/28328)
69   int d = p - a; // d == 1 // expected-warning{{subtraction of pointers to type 'int[m]' of zero size has undefined behavior}}
70 
71   // FIXME: This is a known problem with -Wpointer-arith (https://github.com/llvm/llvm-project/issues/28328)
72   d = &(a[2]) - &(a[1]); // expected-warning{{subtraction of pointers to type 'int[m]' of zero size has undefined behavior}}
73 
74   d = a[2] - a[1]; // expected-warning{{Subtraction of two pointers that}}
75 }
76 
77 struct S {
78   int a;
79   int b;
80   int c[10]; // expected-note2{{Array at the right-hand side of subtraction}}
81   int d[10]; // expected-note2{{Array at the left-hand side of subtraction}}
82 };
83 
84 void f5(void) {
85   struct S s;
86   int y;
87   int d;
88 
89   d = &s.b - &s.a; // expected-warning{{Subtraction of two pointers that}}
90   d = &s.c[0] - &s.a; // expected-warning{{Subtraction of two pointers that}}
91   d = &s.b - &y; // expected-warning{{Subtraction of two pointers that}}
92   d = &s.c[3] - &s.c[2];
93   d = &s.d[3] - &s.c[2]; // expected-warning{{Subtraction of two pointers that}}
94   d = s.d - s.c; // expected-warning{{Subtraction of two pointers that}}
95 
96   struct S sa[10];
97   d = &sa[2] - &sa[1];
98   d = &sa[2].a - &sa[1].b; // expected-warning{{Subtraction of two pointers that}}
99 }
100 
101 void f6(void) {
102   long long l = 2;
103   char *a1 = (char *)&l;
104   int d = a1[3] - l;
105 
106   long long la1[3] = {1}; // expected-note{{Array at the right-hand side of subtraction}}
107   long long la2[3] = {1}; // expected-note{{Array at the left-hand side of subtraction}}
108   char *pla1 = (char *)la1;
109   char *pla2 = (char *)la2;
110   d = pla1[1] - pla1[0];
111   d = (long long *)&pla1[1] - &l; // expected-warning{{Subtraction of two pointers that}}
112   d = &pla2[3] - &pla1[3]; // expected-warning{{Subtraction of two pointers that}}
113 }
114 
115 void f7(int *p) {
116   int a[10];
117   int d = &a[10] - p; // no-warning ('p' is unknown, even if it cannot point into 'a')
118 }
119 
120 void f8(int n) {
121   int a[10] = {1};
122   int d = a[n] - a[0]; // no-warning
123 }
124 
125 int f9(const char *p1) {
126   const char *p2 = p1;
127   --p1;
128   ++p2;
129   return p1 - p2; // no-warning
130 }
131 
132 int f10(struct S *p1, struct S *p2) {
133   return &p1->c[5] - &p2->c[5]; // no-warning
134 }
135 
136 struct S1 {
137   int a;
138   int b; // expected-note{{Object at the right-hand side of subtraction}}
139 };
140 
141 int f11() {
142   struct S1 s; // expected-note{{Object at the left-hand side of subtraction}}
143   return (char *)&s - (char *)&s.b; // expected-warning{{Subtraction of two pointers that}}
144 }
145 
146 struct S2 {
147   char *p1;
148   char *p2;
149 };
150 
151 void init_S2(struct S2 *);
152 
153 int f12() {
154   struct S2 s;
155   init_S2(&s);
156   return s.p1 - s.p2; // no-warning (pointers are unknown)
157 }
158