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