blob: 87f313a3ad5caccb50adad6e9a4a87c95040c519 [file] [log] [blame]
njn3e884182003-04-15 13:03:23 +00001
2/*--------------------------------------------------------------------*/
3/*--- Replacements for strcpy(), memcpy() et al, which run on the ---*/
4/*--- simulated CPU. ---*/
njn66fe05a2003-07-22 09:12:33 +00005/*--- mac_replace_strmem.c ---*/
njn3e884182003-04-15 13:03:23 +00006/*--------------------------------------------------------------------*/
7
8/*
nethercote137bc552003-11-14 17:47:54 +00009 This file is part of MemCheck, a heavyweight Valgrind tool for
njn0e1b5142003-04-15 14:58:06 +000010 detecting memory errors.
njn3e884182003-04-15 13:03:23 +000011
njn53612422005-03-12 16:22:54 +000012 Copyright (C) 2000-2005 Julian Seward
njn3e884182003-04-15 13:03:23 +000013 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
njnc7561b92005-06-19 01:24:32 +000033#include "pub_tool_basics.h"
njnc7561b92005-06-19 01:24:32 +000034#include "pub_tool_hashtable.h"
35#include "pub_tool_profile.h"
36#include "pub_tool_redir.h"
37#include "pub_tool_tooliface.h"
38#include "valgrind.h"
39
njn34419c12003-05-02 17:24:29 +000040#include "mc_include.h"
fitzhardinge98abfc72003-12-16 02:05:15 +000041#include "memcheck.h"
njn3e884182003-04-15 13:03:23 +000042
njn3e884182003-04-15 13:03:23 +000043/* ---------------------------------------------------------------------
njn1f8b3e72005-03-22 04:27:14 +000044 We have our own versions of these functions for two reasons:
45 (a) it allows us to do overlap checking
46 (b) some of the normal versions are hyper-optimised, which fools
47 Memcheck and cause spurious value warnings. Our versions are
48 simpler.
49
njn16eeb4e2005-06-16 03:56:58 +000050 Note that overenthusiastic use of PLT bypassing by the glibc people also
51 means that we need to patch multiple versions of some of the functions to
52 our own implementations.
53
njn1f8b3e72005-03-22 04:27:14 +000054 THEY RUN ON THE SIMD CPU!
njn3e884182003-04-15 13:03:23 +000055 ------------------------------------------------------------------ */
56
sewardjdda830a2003-07-20 22:28:42 +000057/* Figure out if [dst .. dst+dstlen-1] overlaps with
58 [src .. src+srclen-1].
59 We assume that the address ranges do not wrap around
60 (which is safe since on Linux addresses >= 0xC0000000
61 are not accessible and the program will segfault in this
62 circumstance, presumably).
63*/
njn3e884182003-04-15 13:03:23 +000064static __inline__
njnc6168192004-11-29 13:54:10 +000065Bool is_overlap ( void* dst, const void* src, SizeT dstlen, SizeT srclen )
njn3e884182003-04-15 13:03:23 +000066{
sewardjdda830a2003-07-20 22:28:42 +000067 Addr loS, hiS, loD, hiD;
68
69 if (dstlen == 0 || srclen == 0)
70 return False;
71
72 loS = (Addr)src;
73 loD = (Addr)dst;
74 hiS = loS + srclen - 1;
75 hiD = loD + dstlen - 1;
76
77 /* So figure out if [loS .. hiS] overlaps with [loD .. hiD]. */
78 if (loS < loD) {
79 return !(hiS < loD);
80 }
81 else if (loD < loS) {
82 return !(hiD < loS);
83 }
84 else {
85 /* They start at same place. Since we know neither of them has
86 zero length, they must overlap. */
87 return True;
88 }
njn3e884182003-04-15 13:03:23 +000089}
90
njn1f8b3e72005-03-22 04:27:14 +000091// This is a macro rather than a function because we don't want to have an
92// extra function in the stack trace.
93#define RECORD_OVERLAP_ERROR(s, p_extra) \
94{ \
95 Word unused_res; \
96 VALGRIND_MAGIC_SEQUENCE(unused_res, 0, \
97 _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR, \
98 s, p_extra, 0, 0); \
99}
sewardjdda830a2003-07-20 22:28:42 +0000100
njn3e884182003-04-15 13:03:23 +0000101static __inline__
102void complain2 ( Char* s, char* dst, const char* src )
103{
njnb6cae9f2003-09-04 20:50:47 +0000104 OverlapExtra extra = {
105 .src = (Addr)src, .dst = (Addr)dst, .len = -1,
106 };
njn1f8b3e72005-03-22 04:27:14 +0000107 RECORD_OVERLAP_ERROR( s, &extra );
njn3e884182003-04-15 13:03:23 +0000108}
109
110static __inline__
111void complain3 ( Char* s, void* dst, const void* src, int n )
112{
njnb6cae9f2003-09-04 20:50:47 +0000113 /* Must wrap it up here, because we cannot pass 4 args to core */
114 OverlapExtra extra = {
115 .src = (Addr)src, .dst = (Addr)dst, .len = n,
116 };
njn1f8b3e72005-03-22 04:27:14 +0000117 RECORD_OVERLAP_ERROR( s, &extra );
njn3e884182003-04-15 13:03:23 +0000118}
119
njn16eeb4e2005-06-16 03:56:58 +0000120// Some handy Z-encoded names
121#define m_libc_so_6 libcZdsoZd6 // libc.so.6
122#define m_ld_linux_so_2 ldZhlinuxZdsoZd2 // ld-linux.so.2
123#define m_ld_linux_x86_64_so_2 ldZhlinuxZhx86Zh64ZdsoZd2 // ld-linux-x86-64.so.2
njn46275862005-03-24 04:00:03 +0000124
njn16eeb4e2005-06-16 03:56:58 +0000125
126#define STRRCHR(soname, fnname) \
127 char* VG_REPLACE_FUNCTION(soname,fnname)( const char* s, int c ); \
128 char* VG_REPLACE_FUNCTION(soname,fnname)( const char* s, int c ) \
129 { \
130 UChar ch = (UChar)((UInt)c); \
131 UChar* p = (UChar*)s; \
132 UChar* last = NULL; \
133 while (True) { \
134 if (*p == ch) last = p; \
135 if (*p == 0) return last; \
136 p++; \
137 } \
njn3e884182003-04-15 13:03:23 +0000138 }
njn3e884182003-04-15 13:03:23 +0000139
njn16eeb4e2005-06-16 03:56:58 +0000140// Apparently rindex() is the same thing as strrchr()
141STRRCHR(m_libc_so_6, strrchr)
142STRRCHR(m_libc_so_6, rindex)
143STRRCHR(m_ld_linux_so_2, rindex)
144
145
146#define STRCHR(soname, fnname) \
147 char* VG_REPLACE_FUNCTION(soname,fnname) ( const char* s, int c ); \
148 char* VG_REPLACE_FUNCTION(soname,fnname) ( const char* s, int c ) \
149 { \
150 UChar ch = (UChar)((UInt)c); \
151 UChar* p = (UChar*)s; \
152 while (True) { \
153 if (*p == ch) return p; \
154 if (*p == 0) return NULL; \
155 p++; \
156 } \
njn3e884182003-04-15 13:03:23 +0000157 }
njn3e884182003-04-15 13:03:23 +0000158
njn16eeb4e2005-06-16 03:56:58 +0000159// Apparently index() is the same thing as strchr()
160STRCHR(m_libc_so_6, strchr)
161STRCHR(m_ld_linux_so_2, strchr)
tom10e1beb2005-07-21 15:25:04 +0000162STRCHR(m_ld_linux_x86_64_so_2, strchr)
njn16eeb4e2005-06-16 03:56:58 +0000163STRCHR(m_libc_so_6, index)
164STRCHR(m_ld_linux_so_2, index)
165STRCHR(m_ld_linux_x86_64_so_2, index)
njn3e884182003-04-15 13:03:23 +0000166
njn3e884182003-04-15 13:03:23 +0000167
njn16eeb4e2005-06-16 03:56:58 +0000168#define STRCAT(soname, fnname) \
169 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src ); \
170 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src ) \
171 { \
172 const Char* src_orig = src; \
173 Char* dst_orig = dst; \
174 while (*dst) dst++; \
175 while (*src) *dst++ = *src++; \
176 *dst = 0; \
177 \
178 /* This is a bit redundant, I think; any overlap and the strcat will */ \
179 /* go forever... or until a seg fault occurs. */ \
180 if (is_overlap(dst_orig, \
181 src_orig, \
182 (Addr)dst-(Addr)dst_orig+1, \
183 (Addr)src-(Addr)src_orig+1)) \
184 complain2("strcat", dst_orig, src_orig); \
185 \
186 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000187 }
njn3e884182003-04-15 13:03:23 +0000188
njn16eeb4e2005-06-16 03:56:58 +0000189STRCAT(m_libc_so_6, strcat)
190
191
192#define STRNCAT(soname, fnname) \
193 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src, SizeT n ); \
194 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src, SizeT n ) \
195 { \
196 const Char* src_orig = src; \
197 Char* dst_orig = dst; \
198 SizeT m = 0; \
199 \
200 while (*dst) dst++; \
201 while (m < n && *src) { m++; *dst++ = *src++; } /* concat <= n chars */ \
202 *dst = 0; /* always add null */ \
203 \
204 /* This checks for overlap after copying, unavoidable without */ \
205 /* pre-counting lengths... should be ok */ \
206 if (is_overlap(dst_orig, \
207 src_orig, \
208 (Addr)dst-(Addr)dst_orig+1, \
209 (Addr)src-(Addr)src_orig+1)) \
210 complain3("strncat", dst_orig, src_orig, n); \
211 \
212 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000213 }
njn3e884182003-04-15 13:03:23 +0000214
njn16eeb4e2005-06-16 03:56:58 +0000215STRNCAT(m_libc_so_6, strncat)
216
njn3e884182003-04-15 13:03:23 +0000217
njn16eeb4e2005-06-16 03:56:58 +0000218#define STRNLEN(soname, fnname) \
219 SizeT VG_REPLACE_FUNCTION(soname,fnname) ( const char* str, SizeT n ); \
220 SizeT VG_REPLACE_FUNCTION(soname,fnname) ( const char* str, SizeT n ) \
221 { \
222 SizeT i = 0; \
223 while (i < n && str[i] != 0) i++; \
224 return i; \
njn3e884182003-04-15 13:03:23 +0000225 }
njn3e884182003-04-15 13:03:23 +0000226
njn16eeb4e2005-06-16 03:56:58 +0000227STRNLEN(m_libc_so_6, strnlen)
228
sewardj3ceec242003-07-30 21:24:25 +0000229
njn5ec15ed2005-08-24 19:55:51 +0000230// Note that this replacement often doesn't get used because gcc inlines
231// calls to strlen() with its own built-in version. This can be very
232// confusing if you aren't expecting it. Other small functions in this file
233// may also be inline by gcc.
njn16eeb4e2005-06-16 03:56:58 +0000234#define STRLEN(soname, fnname) \
235 SizeT VG_REPLACE_FUNCTION(soname,fnname)( const char* str ); \
236 SizeT VG_REPLACE_FUNCTION(soname,fnname)( const char* str ) \
237 { \
238 SizeT i = 0; \
239 while (str[i] != 0) i++; \
240 return i; \
sewardj3ceec242003-07-30 21:24:25 +0000241 }
njn16eeb4e2005-06-16 03:56:58 +0000242
243STRLEN(m_libc_so_6, strlen)
244STRLEN(m_ld_linux_so_2, strlen)
245STRLEN(m_ld_linux_x86_64_so_2, strlen)
246
247
248#define STRCPY(soname, fnname) \
249 char* VG_REPLACE_FUNCTION(soname, fnname) ( char* dst, const char* src ); \
250 char* VG_REPLACE_FUNCTION(soname, fnname) ( char* dst, const char* src ) \
251 { \
252 const Char* src_orig = src; \
253 Char* dst_orig = dst; \
254 \
255 while (*src) *dst++ = *src++; \
256 *dst = 0; \
257 \
258 /* This checks for overlap after copying, unavoidable without */ \
259 /* pre-counting length... should be ok */ \
260 if (is_overlap(dst_orig, \
261 src_orig, \
262 (Addr)dst-(Addr)dst_orig+1, \
263 (Addr)src-(Addr)src_orig+1)) \
264 complain2("strcpy", dst_orig, src_orig); \
265 \
266 return dst_orig; \
267 }
268
269STRCPY(m_libc_so_6, strcpy)
270
271
272#define STRNCPY(soname, fnname) \
273 char* VG_REPLACE_FUNCTION(soname, fnname) ( char* dst, const char* src, SizeT n ); \
274 char* VG_REPLACE_FUNCTION(soname, fnname) ( char* dst, const char* src, SizeT n ) \
275 { \
276 const Char* src_orig = src; \
277 Char* dst_orig = dst; \
278 SizeT m = 0; \
279 \
280 while (m < n && *src) { m++; *dst++ = *src++; } \
281 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
282 /* but only m+1 bytes of src if terminator was found */ \
283 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
284 complain3("strncpy", dst, src, n); \
285 while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */ \
286 \
287 return dst_orig; \
288 }
289
290STRNCPY(m_libc_so_6, strncpy)
291
292
293#define STRNCMP(soname, fnname) \
294 int VG_REPLACE_FUNCTION(soname,fnname) ( const char* s1, const char* s2, SizeT nmax ); \
295 int VG_REPLACE_FUNCTION(soname,fnname) ( const char* s1, const char* s2, SizeT nmax ) \
296 { \
297 SizeT n = 0; \
298 while (True) { \
299 if (n >= nmax) return 0; \
300 if (*s1 == 0 && *s2 == 0) return 0; \
301 if (*s1 == 0) return -1; \
302 if (*s2 == 0) return 1; \
303 \
304 if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1; \
305 if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1; \
306 \
307 s1++; s2++; n++; \
308 } \
309 }
310
311STRNCMP(m_libc_so_6, strncmp)
312
313
314#define STRCMP(soname, fnname) \
315 int VG_REPLACE_FUNCTION(soname,fnname) ( const char* s1, const char* s2 ); \
316 int VG_REPLACE_FUNCTION(soname,fnname) ( const char* s1, const char* s2 ) \
317 { \
318 register unsigned char c1; \
319 register unsigned char c2; \
320 while (True) { \
321 c1 = *(unsigned char *)s1; \
322 c2 = *(unsigned char *)s2; \
323 if (c1 != c2) break; \
324 if (c1 == 0) break; \
325 s1++; s2++; \
326 } \
327 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
328 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
329 return 0; \
330 }
331
332STRCMP(m_libc_so_6, strcmp)
333STRCMP(m_ld_linux_x86_64_so_2, strcmp)
334
335
336#define MEMCHR(soname, fnname) \
337 void* VG_REPLACE_FUNCTION(soname,fnname) (const void *s, int c, SizeT n); \
338 void* VG_REPLACE_FUNCTION(soname,fnname) (const void *s, int c, SizeT n) \
339 { \
340 SizeT i; \
341 UChar c0 = (UChar)c; \
342 UChar* p = (UChar*)s; \
343 for (i = 0; i < n; i++) \
344 if (p[i] == c0) return (void*)(&p[i]); \
345 return NULL; \
346 }
347
348MEMCHR(m_libc_so_6, memchr)
349
350
351#define MEMCPY(soname, fnname) \
352 void* VG_REPLACE_FUNCTION(soname,fnname)( void *dst, const void *src, SizeT len ); \
353 void* VG_REPLACE_FUNCTION(soname,fnname)( void *dst, const void *src, SizeT len ) \
354 { \
355 register char *d; \
356 register char *s; \
357 \
358 if (len == 0) \
359 return dst; \
360 \
361 if (is_overlap(dst, src, len, len)) \
362 complain3("memcpy", dst, src, len); \
363 \
364 if ( dst > src ) { \
365 d = (char *)dst + len - 1; \
366 s = (char *)src + len - 1; \
367 while ( len >= 4 ) { \
368 *d-- = *s--; \
369 *d-- = *s--; \
370 *d-- = *s--; \
371 *d-- = *s--; \
372 len -= 4; \
373 } \
374 while ( len-- ) { \
375 *d-- = *s--; \
376 } \
377 } else if ( dst < src ) { \
378 d = (char *)dst; \
379 s = (char *)src; \
380 while ( len >= 4 ) { \
381 *d++ = *s++; \
382 *d++ = *s++; \
383 *d++ = *s++; \
384 *d++ = *s++; \
385 len -= 4; \
386 } \
387 while ( len-- ) { \
388 *d++ = *s++; \
389 } \
390 } \
391 return dst; \
392 }
393
394MEMCPY(m_libc_so_6, memcpy)
395
396
397#define MEMCMP(soname, fnname) \
398 int VG_REPLACE_FUNCTION(soname,fnname)( const void *s1V, const void *s2V, SizeT n ); \
399 int VG_REPLACE_FUNCTION(soname,fnname)( const void *s1V, const void *s2V, SizeT n ) \
400 { \
401 int res; \
402 unsigned char a0; \
403 unsigned char b0; \
404 unsigned char* s1 = (unsigned char*)s1V; \
405 unsigned char* s2 = (unsigned char*)s2V; \
406 \
407 while (n != 0) { \
408 a0 = s1[0]; \
409 b0 = s2[0]; \
410 s1 += 1; \
411 s2 += 1; \
412 res = ((int)a0) - ((int)b0); \
413 if (res != 0) \
414 return res; \
415 n -= 1; \
416 } \
417 return 0; \
418 }
419
420MEMCMP(m_libc_so_6, memcmp)
421MEMCMP(m_libc_so_6, bcmp)
njn3e884182003-04-15 13:03:23 +0000422
jseward0845ef82003-12-22 22:31:27 +0000423
424/* Copy SRC to DEST, returning the address of the terminating '\0' in
425 DEST. (minor variant of strcpy) */
njn16eeb4e2005-06-16 03:56:58 +0000426#define STPCPY(soname, fnname) \
427 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src ); \
428 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src ) \
429 { \
430 const Char* src_orig = src; \
431 Char* dst_orig = dst; \
432 \
433 while (*src) *dst++ = *src++; \
434 *dst = 0; \
435 \
436 /* This checks for overlap after copying, unavoidable without */ \
437 /* pre-counting length... should be ok */ \
438 if (is_overlap(dst_orig, \
439 src_orig, \
440 (Addr)dst-(Addr)dst_orig+1, \
441 (Addr)src-(Addr)src_orig+1)) \
442 complain2("stpcpy", dst_orig, src_orig); \
443 \
444 return dst; \
sewardj44e495f2005-05-12 17:58:28 +0000445 }
njn16eeb4e2005-06-16 03:56:58 +0000446
tom10e1beb2005-07-21 15:25:04 +0000447STPCPY(m_libc_so_6, stpcpy)
448STPCPY(m_ld_linux_so_2, stpcpy)
449STPCPY(m_ld_linux_x86_64_so_2, stpcpy)
njn16eeb4e2005-06-16 03:56:58 +0000450
451
452#define MEMSET(soname, fnname) \
453 void* VG_REPLACE_FUNCTION(soname,fnname)(void *s, Int c, SizeT n); \
454 void* VG_REPLACE_FUNCTION(soname,fnname)(void *s, Int c, SizeT n) \
455 { \
456 unsigned char *cp = s; \
457 \
458 while(n--) \
459 *cp++ = c; \
460 \
461 return s; \
sewardj44e495f2005-05-12 17:58:28 +0000462 }
njn16eeb4e2005-06-16 03:56:58 +0000463
464MEMSET(m_libc_so_6, memset)
465
466
467#define MEMMOVE(soname, fnname) \
468 void* VG_REPLACE_FUNCTION(soname,fnname)(void *dstV, const void *srcV, SizeT n); \
469 void* VG_REPLACE_FUNCTION(soname,fnname)(void *dstV, const void *srcV, SizeT n) \
470 { \
471 SizeT i; \
472 Char* dst = (Char*)dstV; \
473 Char* src = (Char*)srcV; \
474 if (dst < src) { \
475 for (i = 0; i < n; i++) \
476 dst[i] = src[i]; \
477 } \
478 else \
479 if (dst > src) { \
480 for (i = 0; i < n; i++) \
481 dst[n-i-1] = src[n-i-1]; \
482 } \
483 return dst; \
484 }
485
486MEMMOVE(m_libc_so_6, memmove)
sewardj44e495f2005-05-12 17:58:28 +0000487
jseward0845ef82003-12-22 22:31:27 +0000488
sewardj4e9a4b62004-11-23 00:20:17 +0000489/* Find the first occurrence of C in S or the final NUL byte. */
njn16eeb4e2005-06-16 03:56:58 +0000490#define GLIBC232_STRCHRNUL(soname, fnname) \
491 char* VG_REPLACE_FUNCTION(soname,fnname) (const char* s, int c_in); \
492 char* VG_REPLACE_FUNCTION(soname,fnname) (const char* s, int c_in) \
493 { \
494 unsigned char c = (unsigned char) c_in; \
495 unsigned char* char_ptr = (unsigned char *)s; \
496 while (1) { \
497 if (*char_ptr == 0) return char_ptr; \
498 if (*char_ptr == c) return char_ptr; \
499 char_ptr++; \
500 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000501 }
njn16eeb4e2005-06-16 03:56:58 +0000502
503GLIBC232_STRCHRNUL(m_libc_so_6, strchrnul)
sewardj4e9a4b62004-11-23 00:20:17 +0000504
505
506/* Find the first occurrence of C in S. */
njn16eeb4e2005-06-16 03:56:58 +0000507#define GLIBC232_RAWMEMCHR(soname, fnname) \
508 char* VG_REPLACE_FUNCTION(soname,fnname) (const char* s, int c_in); \
509 char* VG_REPLACE_FUNCTION(soname,fnname) (const char* s, int c_in) \
510 { \
511 unsigned char c = (unsigned char) c_in; \
512 unsigned char* char_ptr = (unsigned char *)s; \
513 while (1) { \
514 if (*char_ptr == c) return char_ptr; \
515 char_ptr++; \
516 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000517 }
njn16eeb4e2005-06-16 03:56:58 +0000518
519GLIBC232_RAWMEMCHR(m_libc_so_6, rawmemchr)
sewardj4e9a4b62004-11-23 00:20:17 +0000520
521
njn3e884182003-04-15 13:03:23 +0000522/*--------------------------------------------------------------------*/
njn46275862005-03-24 04:00:03 +0000523/*--- end ---*/
njn3e884182003-04-15 13:03:23 +0000524/*--------------------------------------------------------------------*/