• 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, 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