• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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