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 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 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 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 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 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 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 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 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 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 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 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 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 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. 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. 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