Home | History | Annotate | Download | only in tsan
      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, i + 1);
     70   return ret;
     71 }
     72 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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.
    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