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, ret ? i + 1 : i);
70 return ret;
71 }
72
Replace_strrchr(EXTRA_REPLACE_PARAMS const char * s,int c)73 static NOINLINE char *Replace_strrchr(EXTRA_REPLACE_PARAMS const char *s,
74 int c) {
75 char* ret = 0;
76 size_t i;
77 for (i = 0; ; i++) {
78 if (s[i] == (char)c) {
79 ret = (char*)&s[i];
80 }
81 if (s[i] == 0) break;
82 }
83 REPORT_READ_RANGE(s, i);
84 return ret;
85 }
86
Replace_strlen(EXTRA_REPLACE_PARAMS const char * s)87 static NOINLINE size_t Replace_strlen(EXTRA_REPLACE_PARAMS const char *s) {
88 size_t i = 0;
89 for (i = 0; s[i]; i++) {
90 }
91 REPORT_READ_RANGE(s, i);
92 return i;
93 }
94
Replace_memcpy(EXTRA_REPLACE_PARAMS char * dst,const char * src,size_t len)95 static NOINLINE char *Replace_memcpy(EXTRA_REPLACE_PARAMS char *dst,
96 const char *src, size_t len) {
97 size_t i;
98 for (i = 0; i < len; i++) {
99 dst[i] = src[i];
100 }
101 REPORT_READ_RANGE(src, i);
102 REPORT_WRITE_RANGE(dst, i);
103 return dst;
104 }
105
Replace_memmove(EXTRA_REPLACE_PARAMS char * dst,const char * src,size_t len)106 static NOINLINE char *Replace_memmove(EXTRA_REPLACE_PARAMS char *dst,
107 const char *src, size_t len) {
108
109 size_t i;
110 if (dst < src) {
111 for (i = 0; i < len; i++) {
112 dst[i] = src[i];
113 }
114 } else {
115 for (i = 0; i < len; i++) {
116 dst[len - i - 1] = src[len - i - 1];
117 }
118 }
119 REPORT_READ_RANGE(src, i);
120 REPORT_WRITE_RANGE(dst, i);
121 return dst;
122 }
123
Replace_memcmp(EXTRA_REPLACE_PARAMS const unsigned char * s1,const unsigned char * s2,size_t len)124 static NOINLINE int Replace_memcmp(EXTRA_REPLACE_PARAMS const unsigned char *s1,
125 const unsigned char *s2, size_t len) {
126 size_t i;
127 int res = 0;
128 for (i = 0; i < len; i++) {
129 if (s1[i] != s2[i]) {
130 res = (int)s1[i] - (int)s2[i];
131 i++;
132 break;
133 }
134 }
135 REPORT_READ_RANGE(s1, i);
136 REPORT_READ_RANGE(s2, i);
137 return res;
138 }
139
Replace_strcpy(EXTRA_REPLACE_PARAMS char * dst,const char * src)140 static NOINLINE char *Replace_strcpy(EXTRA_REPLACE_PARAMS char *dst,
141 const char *src) {
142 size_t i;
143 for (i = 0; src[i]; i++) {
144 dst[i] = src[i];
145 }
146 dst[i] = 0;
147 REPORT_READ_RANGE(src, i + 1);
148 REPORT_WRITE_RANGE(dst, i + 1);
149 return dst;
150 }
151
Replace_stpcpy(EXTRA_REPLACE_PARAMS char * dst,const char * src)152 static NOINLINE char *Replace_stpcpy(EXTRA_REPLACE_PARAMS char *dst,
153 const char *src) {
154 size_t i;
155 for (i = 0; src[i]; i++) {
156 dst[i] = src[i];
157 }
158 dst[i] = 0;
159 REPORT_READ_RANGE(src, i + 1);
160 REPORT_WRITE_RANGE(dst, i + 1);
161 return dst + i;
162 }
163
Replace_strncpy(EXTRA_REPLACE_PARAMS char * dst,const char * src,size_t n)164 static NOINLINE char *Replace_strncpy(EXTRA_REPLACE_PARAMS char *dst,
165 const char *src, size_t n) {
166 size_t i;
167 for (i = 0; i < n; i++) {
168 dst[i] = src[i];
169 if (src[i] == 0) break;
170 }
171 REPORT_READ_RANGE(src, i < n ? i+1 : n);
172 REPORT_WRITE_RANGE(dst, i < n ? i+1 : n);
173 return dst;
174 }
175
176
Replace_strcmp(EXTRA_REPLACE_PARAMS const char * s1,const char * s2)177 static NOINLINE int Replace_strcmp(EXTRA_REPLACE_PARAMS const char *s1,
178 const char *s2) {
179 unsigned char c1;
180 unsigned char c2;
181 size_t i;
182 for (i = 0; ; i++) {
183 c1 = (unsigned char)s1[i];
184 c2 = (unsigned char)s2[i];
185 if (c1 != c2) break;
186 if (c1 == 0) break;
187 }
188 REPORT_READ_RANGE(s1, i+1);
189 REPORT_READ_RANGE(s2, i+1);
190 if (c1 < c2) return -1;
191 if (c1 > c2) return 1;
192 return 0;
193 }
194
Replace_strncmp(EXTRA_REPLACE_PARAMS const char * s1,const char * s2,size_t n)195 static NOINLINE int Replace_strncmp(EXTRA_REPLACE_PARAMS const char *s1,
196 const char *s2, size_t n) {
197 unsigned char c1 = 0;
198 unsigned char c2 = 0;
199 size_t i;
200 for (i = 0; i < n; i++) {
201 c1 = (unsigned char)s1[i];
202 c2 = (unsigned char)s2[i];
203 if (c1 != c2) break;
204 if (c1 == 0) break;
205 }
206 REPORT_READ_RANGE(s1, i < n ? i+1 : n);
207 REPORT_READ_RANGE(s2, i < n ? i+1 : n);
208 if (c1 < c2) return -1;
209 if (c1 > c2) return 1;
210 return 0;
211 }
212
Replace_strcat(EXTRA_REPLACE_PARAMS char * dest,const char * src)213 static NOINLINE char *Replace_strcat(EXTRA_REPLACE_PARAMS char *dest,
214 const char *src) {
215 size_t dest_len = Replace_strlen(EXTRA_REPLACE_ARGS dest);
216 Replace_strcpy(EXTRA_REPLACE_ARGS dest + dest_len, src);
217 return dest;
218 }
219
220 #if defined(TS_VALGRIND)
221 // Read every byte in the memory range.
ReadMemory(const void * p,size_t size)222 static NOINLINE void ReadMemory(const void* p, size_t size) {
223 const volatile char* start = (const volatile char*)p;
224 const volatile char* end = start + size;
225 volatile char tmp = 0;
226 for (; start < end; ++start) {
227 // If we just read the bytes, Valgrind will optimize it out.
228 tmp ^= *start;
229 }
230 }
231
232 // Read every byte in the null-terminated string.
ReadString(const char * s)233 static NOINLINE void ReadString(const char* s) {
234 const volatile char* p = (const volatile char*)s;
235 volatile char tmp = 0;
236 char c;
237 for (; (c = *p); ++p) {
238 tmp ^= c;
239 }
240 }
241 #endif // TS_VALGRIND
242
243 #endif // TS_REPLACE_H_
244