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