1 /* Copyright (c) 2008-2010, Google Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Neither the name of Google Inc. nor the names of its
11 * contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 // This file is part of ThreadSanitizer, a dynamic data race detector.
28 // Author: Konstantin Serebryany.
29 //
30 // Some libc functions are implemented in a way unfriendly to race detectors
31 // and memcheck-like tools.
32 // E.g. strlen() may read up to 7 bytes past the allocated buffer.
33 // To avoid false positives in these functions, the tool needs to replace these
34 // funcions with simpler implementation.
35 //
36 // The includer must define these macros:
37 // REPORT_WRITE_RANGE, REPORT_READ_RANGE, EXTRA_REPLACE_PARAMS,
38 // EXTRA_REPLACE_ARGS, NOINLINE
39 // See ts_valgrind_intercepts.c and ts_pin.cc.
40
41 #ifndef TS_REPLACE_H_
42 #define TS_REPLACE_H_
43
Replace_memchr(EXTRA_REPLACE_PARAMS const char * s,int c,size_t n)44 static NOINLINE char *Replace_memchr(EXTRA_REPLACE_PARAMS const char *s,
45 int c, size_t n) {
46 size_t i;
47 char *ret = 0;
48 for (i = 0; i < n; i++) {
49 if (s[i] == (char)c) {
50 ret = (char*)(&s[i]);
51 break;
52 }
53 }
54 REPORT_READ_RANGE(s, ret ? i + 1 : n);
55 return ret;
56 }
57
Replace_strchr(EXTRA_REPLACE_PARAMS const char * s,int c)58 static NOINLINE char *Replace_strchr(EXTRA_REPLACE_PARAMS const char *s,
59 int c) {
60 size_t i;
61 char *ret = 0;
62 for (i = 0; ; i++) {
63 if (s[i] == (char)c) {
64 ret = (char*)(&s[i]);
65 break;
66 }
67 if (s[i] == 0) break;
68 }
69 REPORT_READ_RANGE(s, i + 1);
70 return ret;
71 }
72
Replace_strchrnul(EXTRA_REPLACE_PARAMS const char * s,int c)73 static NOINLINE char *Replace_strchrnul(EXTRA_REPLACE_PARAMS const char *s,
74 int c) {
75 size_t i;
76 char *ret;
77 for (i = 0; ; i++) {
78 if (s[i] == (char)c || s[i] == 0) {
79 ret = (char*)(&s[i]);
80 break;
81 }
82 }
83 REPORT_READ_RANGE(s, i + 1);
84 return ret;
85 }
86
Replace_strrchr(EXTRA_REPLACE_PARAMS const char * s,int c)87 static NOINLINE char *Replace_strrchr(EXTRA_REPLACE_PARAMS const char *s,
88 int c) {
89 char* ret = 0;
90 size_t i;
91 for (i = 0; ; i++) {
92 if (s[i] == (char)c) {
93 ret = (char*)&s[i];
94 }
95 if (s[i] == 0) break;
96 }
97 REPORT_READ_RANGE(s, i + 1);
98 return ret;
99 }
100
Replace_strlen(EXTRA_REPLACE_PARAMS const char * s)101 static NOINLINE size_t Replace_strlen(EXTRA_REPLACE_PARAMS const char *s) {
102 size_t i = 0;
103 for (i = 0; s[i]; i++) {
104 }
105 REPORT_READ_RANGE(s, i + 1);
106 return i;
107 }
108
Replace_memcpy(EXTRA_REPLACE_PARAMS char * dst,const char * src,size_t len)109 static NOINLINE char *Replace_memcpy(EXTRA_REPLACE_PARAMS char *dst,
110 const char *src, size_t len) {
111 size_t i;
112 for (i = 0; i < len; i++) {
113 dst[i] = src[i];
114 }
115 REPORT_READ_RANGE(src, i);
116 REPORT_WRITE_RANGE(dst, i);
117 return dst;
118 }
119
Replace_memmove(EXTRA_REPLACE_PARAMS char * dst,const char * src,size_t len)120 static NOINLINE char *Replace_memmove(EXTRA_REPLACE_PARAMS char *dst,
121 const char *src, size_t len) {
122
123 size_t i;
124 if (dst < src) {
125 for (i = 0; i < len; i++) {
126 dst[i] = src[i];
127 }
128 } else {
129 for (i = 0; i < len; i++) {
130 dst[len - i - 1] = src[len - i - 1];
131 }
132 }
133 REPORT_READ_RANGE(src, i);
134 REPORT_WRITE_RANGE(dst, i);
135 return dst;
136 }
137
Replace_memcmp(EXTRA_REPLACE_PARAMS const unsigned char * s1,const unsigned char * s2,size_t len)138 static NOINLINE int Replace_memcmp(EXTRA_REPLACE_PARAMS const unsigned char *s1,
139 const unsigned char *s2, size_t len) {
140 size_t i;
141 int res = 0;
142 for (i = 0; i < len; i++) {
143 if (s1[i] != s2[i]) {
144 res = (int)s1[i] - (int)s2[i];
145 break;
146 }
147 }
148 REPORT_READ_RANGE(s1, min(i + 1, len));
149 REPORT_READ_RANGE(s2, min(i + 1, len));
150 return res;
151 }
152
Replace_strcpy(EXTRA_REPLACE_PARAMS char * dst,const char * src)153 static NOINLINE char *Replace_strcpy(EXTRA_REPLACE_PARAMS char *dst,
154 const char *src) {
155 size_t i;
156 for (i = 0; src[i]; i++) {
157 dst[i] = src[i];
158 }
159 dst[i] = 0;
160 REPORT_READ_RANGE(src, i + 1);
161 REPORT_WRITE_RANGE(dst, i + 1);
162 return dst;
163 }
164
Replace_stpcpy(EXTRA_REPLACE_PARAMS char * dst,const char * src)165 static NOINLINE char *Replace_stpcpy(EXTRA_REPLACE_PARAMS char *dst,
166 const char *src) {
167 size_t i;
168 for (i = 0; src[i]; i++) {
169 dst[i] = src[i];
170 }
171 dst[i] = 0;
172 REPORT_READ_RANGE(src, i + 1);
173 REPORT_WRITE_RANGE(dst, i + 1);
174 return dst + i;
175 }
176
Replace_strncpy(EXTRA_REPLACE_PARAMS char * dst,const char * src,size_t n)177 static NOINLINE char *Replace_strncpy(EXTRA_REPLACE_PARAMS char *dst,
178 const char *src, size_t n) {
179 size_t i;
180 for (i = 0; i < n; i++) {
181 dst[i] = src[i];
182 if (src[i] == 0) break;
183 }
184 REPORT_READ_RANGE(src, min(i + 1, n));
185 while (i < n) {
186 dst[i] = 0;
187 i++;
188 }
189 REPORT_WRITE_RANGE(dst, n);
190 return dst;
191 }
192
193
Replace_strcmp(EXTRA_REPLACE_PARAMS const char * s1,const char * s2)194 static NOINLINE int Replace_strcmp(EXTRA_REPLACE_PARAMS const char *s1,
195 const char *s2) {
196 unsigned char c1;
197 unsigned char c2;
198 size_t i;
199 for (i = 0; ; i++) {
200 c1 = (unsigned char)s1[i];
201 c2 = (unsigned char)s2[i];
202 if (c1 != c2) break;
203 if (c1 == 0) break;
204 }
205 REPORT_READ_RANGE(s1, i+1);
206 REPORT_READ_RANGE(s2, i+1);
207 if (c1 < c2) return -1;
208 if (c1 > c2) return 1;
209 return 0;
210 }
211
Replace_strncmp(EXTRA_REPLACE_PARAMS const char * s1,const char * s2,size_t n)212 static NOINLINE int Replace_strncmp(EXTRA_REPLACE_PARAMS const char *s1,
213 const char *s2, size_t n) {
214 unsigned char c1 = 0;
215 unsigned char c2 = 0;
216 size_t i;
217 for (i = 0; i < n; i++) {
218 c1 = (unsigned char)s1[i];
219 c2 = (unsigned char)s2[i];
220 if (c1 != c2) break;
221 if (c1 == 0) break;
222 }
223 REPORT_READ_RANGE(s1, min(i + 1, n));
224 REPORT_READ_RANGE(s2, min(i + 1, n));
225 if (c1 < c2) return -1;
226 if (c1 > c2) return 1;
227 return 0;
228 }
229
Replace_strcat(EXTRA_REPLACE_PARAMS char * dest,const char * src)230 static NOINLINE char *Replace_strcat(EXTRA_REPLACE_PARAMS char *dest,
231 const char *src) {
232 size_t dest_len = Replace_strlen(EXTRA_REPLACE_ARGS dest);
233 Replace_strcpy(EXTRA_REPLACE_ARGS dest + dest_len, src);
234 return dest;
235 }
236
237 #if defined(TS_VALGRIND)
238 // Read every byte in the memory range.
ReadMemory(const void * p,size_t size)239 static NOINLINE void ReadMemory(const void* p, size_t size) {
240 const volatile char* start = (const volatile char*)p;
241 const volatile char* end = start + size;
242 volatile char tmp = 0;
243 for (; start < end; ++start) {
244 // If we just read the bytes, Valgrind will optimize it out.
245 tmp ^= *start;
246 }
247 }
248
249 // Read every byte in the null-terminated string.
ReadString(const char * s)250 static NOINLINE void ReadString(const char* s) {
251 const volatile char* p = (const volatile char*)s;
252 volatile char tmp = 0;
253 char c;
254 for (; (c = *p); ++p) {
255 tmp ^= c;
256 }
257 }
258 #endif // TS_VALGRIND
259
260 #endif // TS_REPLACE_H_
261