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
44static 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
58static 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
73static 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
87static 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
101static 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
109static 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
120static 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
138static 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
153static 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
165static 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
177static 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
194static 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
212static 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
230static 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.
239static 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.
250static 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