-
Notifications
You must be signed in to change notification settings - Fork 189
Expand file tree
/
Copy pathstring_checked.h
More file actions
183 lines (156 loc) · 7.21 KB
/
Copy pathstring_checked.h
File metadata and controls
183 lines (156 loc) · 7.21 KB
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
//---------------------------------------------------------------------//
// Bounds-safe interfaces for functions in string.h that //
// take pointer arguments. //
// //
// These are listed in the same order that they occur in the C11 //
// specification. //
// //
// TODO: revise string types after support for pointers to //
// null-terminated arrays is added to C. //
// //
// TODO: Better Support for _FORTIFY_SOURCE > 0 //
/////////////////////////////////////////////////////////////////////////
#ifdef __checkedc
#pragma CHECKED_SCOPE push
#pragma CHECKED_SCOPE off
#endif
#include_next <string.h>
#ifdef __checkedc
#pragma CHECKED_SCOPE pop
#endif
#ifdef __checkedc
#ifndef __STRING_CHECKED_H
#define __STRING_CHECKED_H
#pragma TLIB_SCOPE on
#pragma CHECKED_SCOPE push
#pragma CHECKED_SCOPE on
// GCC has macros that it uses as part of its string implementation to optimize cases
// where one or both strings are compile-time constants. I'm not sure
// why they put this logic into macros instead of the compiler because the
// compiler can recognize these cases in more contexts than a macro, but they
// did.
//
// For now, undefine the various macros. GCC has a #define for turning off
// this feature, but that must be set before string.h is included and we don't
// control when that happens (string.h may already have been included before
// this file is ever included).
#if defined(__GNUC__)
#undef strchr
#undef strcmp
#undef strcspn
#undef strncmp
#undef strncmp
#undef strpbrk
#undef strspn
#undef strdup
#endif
// We wrap each definition in a complex conditional, there two boolean values:
// - we are fortifying, or we're not (_FORTIFY_SOURCE==0 is not fortifying)
// - there is or there isn't a macro hash-defining this symbol (defined(symbol))
// Cases:
// - Fortifying, Macro Exists: this is expected, we don't need the definition
// - Not Fortifying, Macro Exists: we need the definition, we need to undef macro
// - Fortifying, No Macro: we need the definition
// - Not Fortifying, No Macro: we need the definition
#if _FORTIFY_SOURCE == 0 || !defined(memcpy)
#undef memcpy
_Itype_for_any(T) void *memcpy(void * restrict dest : itype(restrict _Array_ptr<T>) byte_count(n),
const void * restrict src : itype(restrict _Array_ptr<const T>) byte_count(n),
size_t n) : itype(_Array_ptr<T>) byte_count(n);
#endif
#if _FORTIFY_SOURCE == 0 || !defined(memmove)
#undef memmove
void *memmove(void * dest : byte_count(n),
const void * src : byte_count(n),
size_t n) : bounds(dest, (_Array_ptr<char>)dest + n);
#endif
#if _FORTIFY_SOURCE == 0 || !defined(memset)
#undef memset
void *memset(void * dest : byte_count(n),
int c,
size_t n) : bounds(dest, (_Array_ptr<char>)dest + n);
#endif
#if _FORTIFY_SOURCE == 0 || !defined(strcpy)
#undef strcpy
// Dest is left unchecked intentionally. There is no bound on dest, so this
// is always an unchecked function
_Unchecked
char *strcpy(char * restrict dest,
const char * restrict src : itype(restrict _Nt_array_ptr<const char>));
#endif
#if _FORTIFY_SOURCE == 0 || !defined(strncpy)
#undef strncpy
char *strncpy(char * restrict dest : count(n),
const char * restrict src : count(n),
size_t n) : bounds(dest, (_Array_ptr<char>)dest + n);
#endif
#if _FORTIFY_SOURCE == 0 || !defined(strcat)
#undef strcat
// Dest is left unchecked intentionally. There is no bound on dest, so this
// is always an unchecked function.
_Unchecked
char *strcat(char * restrict dest,
const char * restrict src : itype(restrict _Nt_array_ptr<const char>));
#endif
#if _FORTIFY_SOURCE == 0 || !defined(strncat)
#undef strncat
// TODO: we have no way to express the bounds requirement on dest,
// which needs to be count(strlen(dest) + n).
_Unchecked
char *strncat(char * restrict dest,
const char * restrict src : count(n),
size_t n);
#endif
int memcmp(const void *src1 : byte_count(n), const void *src2 : byte_count(n),
size_t n);
int strcmp(const char *src1 : itype(_Nt_array_ptr<const char>),
const char *src2 : itype(_Nt_array_ptr<const char>));
int strcasecmp(const char *src1 : itype(_Nt_array_ptr<const char>),
const char *src2 : itype(_Nt_array_ptr<const char>));
int strcoll(const char *src1 : itype(_Nt_array_ptr<const char>),
const char *src2 : itype(_Nt_array_ptr<const char>));
// strncmp takes possibly null-terminated strings as arguments and checks
// up to n characters. For a bounds-safe interface, this means each string
// needs to be EITHER null-terminated OR have bounds greater than or equal to
// n. We cannot express them both in a single interface, so this is the
// interface for null-terminated strings (assumed to be the most common case).
// In the checkedc_extensions.h header there is a bounds-safe interface for
// use of _Array_ptr rather than _Nt_array_ptr.
int strncmp(const char *src : itype(_Nt_array_ptr<const char>),
const char *s2 : itype(_Nt_array_ptr<const char>),
size_t n);
int strncasecmp(const char *src : itype(_Nt_array_ptr<const char>),
const char *s2 : itype(_Nt_array_ptr<const char>),
size_t n);
size_t strxfrm(char * restrict dest : count(n),
const char * restrict src :
itype(restrict _Nt_array_ptr<const char>),
size_t n);
void *memchr(const void *s : byte_count(n), int c, size_t n) :
bounds(s, (_Array_ptr<char>) s + n);
char *strchr(const char *s : itype(_Nt_array_ptr<const char>), int c) :
itype(_Nt_array_ptr<char>);
size_t strcspn(const char *s1 : itype(_Nt_array_ptr<const char>),
const char *s2 : itype(_Nt_array_ptr<const char>));
char *strpbrk(const char *s1 : itype(_Nt_array_ptr<const char>),
const char *s2 : itype(_Nt_array_ptr<const char>)) :
itype(_Nt_array_ptr<char>);
char *strrchr(const char *s : itype(_Nt_array_ptr<const char>), int c) :
itype(_Nt_array_ptr<char>);
size_t strspn(const char *s1 : itype(_Nt_array_ptr<const char>),
const char *s2 : itype(_Nt_array_ptr<const char>));
char *strstr(const char *s1 : itype(_Nt_array_ptr<const char>),
const char *s2 : itype(_Nt_array_ptr<const char>)) :
itype(_Nt_array_ptr<char>);
char *strtok(char * restrict s1 : itype(restrict _Nt_array_ptr<char>),
const char * restrict s2 : itype(restrict _Nt_array_ptr<const char>)) :
itype(_Nt_array_ptr<char>);
char *strerror(int errnum) : itype(_Nt_array_ptr<char>);
size_t strlen(const char *s : itype(_Nt_array_ptr<const char>));
char *strdup(const char *s : itype(_Nt_array_ptr<const char>)) : itype(_Nt_array_ptr<char>);
char *strndup(const char *s : itype(_Nt_array_ptr<const char>), size_t n) : itype(_Nt_array_ptr<char>);
#include "_builtin_string_checked.h"
#pragma CHECKED_SCOPE pop
#pragma TLIB_SCOPE off
#endif // guard
#endif // Checked C