mc_replace_strmem.c revision 98abfc7bb7798c4ac4580f7e0bc7171de94a0255
1 2/*--------------------------------------------------------------------*/ 3/*--- Replacements for strcpy(), memcpy() et al, which run on the ---*/ 4/*--- simulated CPU. ---*/ 5/*--- mac_replace_strmem.c ---*/ 6/*--------------------------------------------------------------------*/ 7 8/* 9 This file is part of MemCheck, a heavyweight Valgrind tool for 10 detecting memory errors. 11 12 Copyright (C) 2000-2003 Julian Seward 13 jseward@acm.org 14 15 This program is free software; you can redistribute it and/or 16 modify it under the terms of the GNU General Public License as 17 published by the Free Software Foundation; either version 2 of the 18 License, or (at your option) any later version. 19 20 This program is distributed in the hope that it will be useful, but 21 WITHOUT ANY WARRANTY; without even the implied warranty of 22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 General Public License for more details. 24 25 You should have received a copy of the GNU General Public License 26 along with this program; if not, write to the Free Software 27 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 28 02111-1307, USA. 29 30 The GNU General Public License is contained in the file COPYING. 31*/ 32 33#include "mc_include.h" 34#include "memcheck.h" 35#include "valgrind.h" 36 37static Addr record_overlap_error; 38 39static int init_done; 40 41/* Startup hook - called as init section */ 42static void init(void) __attribute__((constructor)); 43static void init(void) 44{ 45 if (init_done) 46 return; 47 48 VALGRIND_MAGIC_SEQUENCE(record_overlap_error, 0, 49 _VG_USERREQ__MEMCHECK_GET_RECORD_OVERLAP, 50 0, 0, 0, 0); 51 init_done = 1; 52} 53 54/* --------------------------------------------------------------------- 55 The normal versions of these functions are hyper-optimised, which fools 56 Memcheck and cause spurious value warnings. So we replace them with 57 simpler versions. THEY RUN ON SIMD CPU! 58 ------------------------------------------------------------------ */ 59 60/* Figure out if [dst .. dst+dstlen-1] overlaps with 61 [src .. src+srclen-1]. 62 We assume that the address ranges do not wrap around 63 (which is safe since on Linux addresses >= 0xC0000000 64 are not accessible and the program will segfault in this 65 circumstance, presumably). 66*/ 67static __inline__ 68Bool is_overlap ( void* dst, const void* src, UInt dstlen, UInt srclen ) 69{ 70 Addr loS, hiS, loD, hiD; 71 72 if (dstlen == 0 || srclen == 0) 73 return False; 74 75 loS = (Addr)src; 76 loD = (Addr)dst; 77 hiS = loS + srclen - 1; 78 hiD = loD + dstlen - 1; 79 80 /* So figure out if [loS .. hiS] overlaps with [loD .. hiD]. */ 81 if (loS < loD) { 82 return !(hiS < loD); 83 } 84 else if (loD < loS) { 85 return !(hiD < loS); 86 } 87 else { 88 /* They start at same place. Since we know neither of them has 89 zero length, they must overlap. */ 90 return True; 91 } 92} 93 94 95static __inline__ 96void complain2 ( Char* s, char* dst, const char* src ) 97{ 98 OverlapExtra extra = { 99 .src = (Addr)src, .dst = (Addr)dst, .len = -1, 100 }; 101 init(); 102 VALGRIND_NON_SIMD_CALL2( record_overlap_error, s, &extra ); 103} 104 105static __inline__ 106void complain3 ( Char* s, void* dst, const void* src, int n ) 107{ 108 /* Must wrap it up here, because we cannot pass 4 args to core */ 109 OverlapExtra extra = { 110 .src = (Addr)src, .dst = (Addr)dst, .len = n, 111 }; 112 init(); 113 VALGRIND_NON_SIMD_CALL2( record_overlap_error, s, &extra ); 114} 115 116char* strrchr ( const char* s, int c ) 117{ 118 UChar ch = (UChar)((UInt)c); 119 UChar* p = (UChar*)s; 120 UChar* last = NULL; 121 while (True) { 122 if (*p == ch) last = p; 123 if (*p == 0) return last; 124 p++; 125 } 126} 127 128char* strchr ( const char* s, int c ) 129{ 130 UChar ch = (UChar)((UInt)c); 131 UChar* p = (UChar*)s; 132 while (True) { 133 if (*p == ch) return p; 134 if (*p == 0) return NULL; 135 p++; 136 } 137} 138 139char* strcat ( char* dst, const char* src ) 140{ 141 const Char* src_orig = src; 142 Char* dst_orig = dst; 143 while (*dst) dst++; 144 while (*src) *dst++ = *src++; 145 *dst = 0; 146 147 /* This is a bit redundant, I think; any overlap and the strcat will 148 go forever... or until a seg fault occurs. */ 149 if (is_overlap(dst_orig, 150 src_orig, 151 (Addr)dst-(Addr)dst_orig+1, 152 (Addr)src-(Addr)src_orig+1)) 153 complain2("strcat", dst_orig, src_orig); 154 155 return dst_orig; 156} 157 158char* strncat ( char* dst, const char* src, int n ) 159{ 160 const Char* src_orig = src; 161 Char* dst_orig = dst; 162 Int m = 0; 163 164 while (*dst) dst++; 165 while (m < n && *src) { m++; *dst++ = *src++; } /* concat <= n chars */ 166 *dst = 0; /* always add null */ 167 168 /* This checks for overlap after copying, unavoidable without 169 pre-counting lengths... should be ok */ 170 if (is_overlap(dst_orig, 171 src_orig, 172 (Addr)dst-(Addr)dst_orig+1, 173 (Addr)src-(Addr)src_orig+1)) 174 complain3("strncat", dst_orig, src_orig, n); 175 176 return dst_orig; 177} 178 179unsigned int strlen ( const char* str ) 180{ 181 UInt i = 0; 182 while (str[i] != 0) i++; 183 return i; 184} 185 186char* strcpy ( char* dst, const char* src ) 187{ 188 const Char* src_orig = src; 189 Char* dst_orig = dst; 190 191 while (*src) *dst++ = *src++; 192 *dst = 0; 193 194 /* This checks for overlap after copying, unavoidable without 195 pre-counting length... should be ok */ 196 if (is_overlap(dst_orig, 197 src_orig, 198 (Addr)dst-(Addr)dst_orig+1, 199 (Addr)src-(Addr)src_orig+1)) 200 complain2("strcpy", dst_orig, src_orig); 201 202 return dst_orig; 203} 204 205char* strncpy ( char* dst, const char* src, int n ) 206{ 207 const Char* src_orig = src; 208 Char* dst_orig = dst; 209 Int m = 0; 210 211 while (m < n && *src) { m++; *dst++ = *src++; } 212 /* Check for overlap after copying; all n bytes of dst are relevant, 213 but only m+1 bytes of src if terminator was found */ 214 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) 215 complain3("strncpy", dst, src, n); 216 while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */ 217 218 return dst_orig; 219} 220 221int strncmp ( const unsigned char* s1, const unsigned char* s2, 222 unsigned int nmax ) 223{ 224 unsigned int n = 0; 225 while (True) { 226 if (n >= nmax) return 0; 227 if (*s1 == 0 && *s2 == 0) return 0; 228 if (*s1 == 0) return -1; 229 if (*s2 == 0) return 1; 230 231 if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1; 232 if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1; 233 234 s1++; s2++; n++; 235 } 236} 237 238int strcmp ( const char* s1, const char* s2 ) 239{ 240 register unsigned char c1; 241 register unsigned char c2; 242 while (True) { 243 c1 = *(unsigned char *)s1; 244 c2 = *(unsigned char *)s2; 245 if (c1 != c2) break; 246 if (c1 == 0) break; 247 s1++; s2++; 248 } 249 if ((unsigned char)c1 < (unsigned char)c2) return -1; 250 if ((unsigned char)c1 > (unsigned char)c2) return 1; 251 return 0; 252} 253 254void* memchr(const void *s, int c, unsigned int n) 255{ 256 unsigned int i; 257 UChar c0 = (UChar)c; 258 UChar* p = (UChar*)s; 259 for (i = 0; i < n; i++) 260 if (p[i] == c0) return (void*)(&p[i]); 261 return NULL; 262} 263 264void* memcpy( void *dst, const void *src, unsigned int len ) 265{ 266 register char *d; 267 register char *s; 268 269 if (is_overlap(dst, src, len, len)) 270 complain3("memcpy", dst, src, len); 271 272 if ( dst > src ) { 273 d = (char *)dst + len - 1; 274 s = (char *)src + len - 1; 275 while ( len >= 4 ) { 276 *d-- = *s--; 277 *d-- = *s--; 278 *d-- = *s--; 279 *d-- = *s--; 280 len -= 4; 281 } 282 while ( len-- ) { 283 *d-- = *s--; 284 } 285 } else if ( dst < src ) { 286 d = (char *)dst; 287 s = (char *)src; 288 while ( len >= 4 ) { 289 *d++ = *s++; 290 *d++ = *s++; 291 *d++ = *s++; 292 *d++ = *s++; 293 len -= 4; 294 } 295 while ( len-- ) { 296 *d++ = *s++; 297 } 298 } 299 return dst; 300} 301 302int memcmp ( const void *s1V, const void *s2V, unsigned int n ) 303{ 304 int res; 305 unsigned char a0; 306 unsigned char b0; 307 unsigned char* s1 = (unsigned char*)s1V; 308 unsigned char* s2 = (unsigned char*)s2V; 309 310 while (n != 0) { 311 a0 = s1[0]; 312 b0 = s2[0]; 313 s1 += 1; 314 s2 += 1; 315 res = ((int)a0) - ((int)b0); 316 if (res != 0) 317 return res; 318 n -= 1; 319 } 320 return 0; 321} 322 323/*--------------------------------------------------------------------*/ 324/*--- end mac_replace_strmem.c ---*/ 325/*--------------------------------------------------------------------*/ 326