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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
/* { dg-additional-options "-Wno-unused-but-set-variable" } */
/* { dg-require-effective-target alloca } */
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
/* Tests with symbolic values. */
void test1 (size_t size)
{
char *buf = __builtin_malloc (size);
if (!buf) return;
buf[size] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
__builtin_free (buf);
}
void test2 (size_t size)
{
char *buf = __builtin_malloc (size);
if (!buf) return;
buf[size + 1] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
__builtin_free (buf);
}
void test3 (size_t size, size_t op)
{
char *buf = __builtin_malloc (size);
if (!buf) return;
buf[size + op] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
__builtin_free (buf);
}
void test4 (size_t size, unsigned short s)
{
char *buf = __builtin_alloca (size);
buf[size + s] = '\0'; /* { dg-warning "stack-based buffer overflow" } */
}
void test5 (size_t size)
{
int32_t *buf = __builtin_alloca (4 * size);
buf[size] = 42; /* { dg-warning "stack-based buffer overflow" } */
}
void test6 (size_t size)
{
int32_t *buf = __builtin_alloca (4 * size);
memset (buf, 0, 4 * size);
int32_t last = *(buf + 4 * size); /* { dg-warning "stack-based buffer over-read" } */
}
void test7 (size_t size)
{
int32_t *buf = __builtin_alloca (4 * size + 3); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
buf[size] = 42; /* { dg-warning "stack-based buffer overflow" } */
}
/* Test where the offset itself is not out-of-bounds
but multiple bytes are read. */
void test8 (size_t size, size_t offset)
{
char src[size];
char dst[size];
memcpy (dst, src, size + offset); /* { dg-line test8 } */
/* { dg-warning "over-read" "warning" { target *-*-* } test8 } */
/* { dg-warning "overflow" "warning" { target *-*-* } test8 } */
}
void test9 (size_t size, size_t offset)
{
int32_t src[size];
int32_t dst[size];
memcpy (dst, src, 4 * size + 1); /* { dg-line test9 } */
/* { dg-warning "over-read" "warning" { target *-*-* } test9 } */
/* { dg-warning "overflow" "warning" { target *-*-* } test9 } */
}
/* Test for no false-positives. */
void test10 (size_t size)
{
int32_t buf[4 * size];
/* 4 * size is smaller than 4 * 4 * size. */
buf[size] = 42;
}
void test11 (size_t size)
{
int32_t *buf = __builtin_alloca (4 * size + 5); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
buf[size] = 42;
}
void test12 (size_t size, size_t offset)
{
int buf[size];
buf[offset] = 42;
}
void test13 (size_t size, int offset)
{
int buf[size];
/* We don't know whether offset is positive or not. */
buf[size + offset] = 42;
}
void test14 (size_t size, size_t offset, size_t offset2)
{
int buf[size];
/* We don't know whether offset > offset2. */
buf[size + offset - offset2] = 42;
}
void test15 (size_t a, size_t b)
{
int buf[a * b];
/* We can't reason about a*b < a+b either. */
buf[a + b] = 42;
}
/* Misc. */
char *test98 (const char *x, const char *y)
{
size_t len_x = __builtin_strlen (x);
size_t len_y = __builtin_strlen (y);
size_t sz = len_x + len_y + 1;
char *result = __builtin_malloc (sz);
if (!result)
return NULL;
__builtin_memcpy (result, x, len_x);
__builtin_memcpy (result + len_x, y, len_y);
result[len_x + len_y] = '\0';
return result;
}
char *test99 (const char *x, const char *y)
{
size_t len_x = __builtin_strlen (x);
size_t len_y = __builtin_strlen (y);
/* BUG (root cause): forgot to add 1 for terminator. */
size_t sz = len_x + len_y;
char *result = __builtin_malloc (sz);
if (!result)
return NULL;
__builtin_memcpy (result, x, len_x);
__builtin_memcpy (result + len_x, y, len_y);
/* BUG (symptom): off-by-one out-of-bounds write to heap. */
result[len_x + len_y] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
return result;
}
|