blob: 1570de36e021077e80d8e844013b51201acabd5d [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. ---*/
njn1d0825f2006-03-27 11:37:07 +00005/*--- mc_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
sewardj9eecbbb2010-05-03 21:37:12 +000012 Copyright (C) 2000-2010 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"
njnc7561b92005-06-19 01:24:32 +000035#include "pub_tool_redir.h"
36#include "pub_tool_tooliface.h"
37#include "valgrind.h"
38
njn34419c12003-05-02 17:24:29 +000039#include "mc_include.h"
fitzhardinge98abfc72003-12-16 02:05:15 +000040#include "memcheck.h"
njn3e884182003-04-15 13:03:23 +000041
njn3e884182003-04-15 13:03:23 +000042/* ---------------------------------------------------------------------
njn1f8b3e72005-03-22 04:27:14 +000043 We have our own versions of these functions for two reasons:
44 (a) it allows us to do overlap checking
45 (b) some of the normal versions are hyper-optimised, which fools
46 Memcheck and cause spurious value warnings. Our versions are
47 simpler.
48
njn16eeb4e2005-06-16 03:56:58 +000049 Note that overenthusiastic use of PLT bypassing by the glibc people also
50 means that we need to patch multiple versions of some of the functions to
51 our own implementations.
52
njn1f8b3e72005-03-22 04:27:14 +000053 THEY RUN ON THE SIMD CPU!
njn3e884182003-04-15 13:03:23 +000054 ------------------------------------------------------------------ */
55
sewardjbd2cff22011-08-16 21:45:28 +000056/* Assignment of behavioural equivalence class tags: 2NNN is intended
57 to be reserved for Memcheck. Current usage:
58
59 2001 STRRCHR
60 2002 STRCHR
61 2003 STRCAT
62 2004 STRNCAT
63 2005 STRLCAT
64 2006 STRNLEN
65 2007 STRLEN
66 2008 STRCPY
67 2009 STRNCPY
68 2010 STRLCPY
69 2011 STRNCMP
70 2012 STRCASECMP
71 2013 STRNCASECMP
72 2014 STRCASECMP_L
73 2015 STRNCASECMP_L
74 2016 STRCMP
75 2017 MEMCHR
76 2018 MEMMOVE
77 2019 MEMCMP
78 2020 STPCPY
79 2021 MEMSET
80 2022 MEMCPY
81 2023 BCOPY
82 2024 GLIBC25___MEMMOVE_CHK
83 2025 GLIBC232_STRCHRNUL
84 2026 GLIBC232_RAWMEMCHR
85 2027 GLIBC25___STRCPY_CHK
86 2028 GLIBC25___STPCPY_CHK
87 2029 GLIBC25_MEMPCPY
88 2030 GLIBC26___MEMCPY_CHK
89 2031 STRSTR
90 2032 STRPBRK
91 2033 STRCSPN
92 2034 STRSPN
93*/
94
sewardj126e82d2011-07-12 13:33:00 +000095
sewardjdda830a2003-07-20 22:28:42 +000096/* Figure out if [dst .. dst+dstlen-1] overlaps with
97 [src .. src+srclen-1].
98 We assume that the address ranges do not wrap around
99 (which is safe since on Linux addresses >= 0xC0000000
100 are not accessible and the program will segfault in this
101 circumstance, presumably).
102*/
sewardj126e82d2011-07-12 13:33:00 +0000103static inline
njnc6168192004-11-29 13:54:10 +0000104Bool is_overlap ( void* dst, const void* src, SizeT dstlen, SizeT srclen )
njn3e884182003-04-15 13:03:23 +0000105{
sewardjdda830a2003-07-20 22:28:42 +0000106 Addr loS, hiS, loD, hiD;
107
108 if (dstlen == 0 || srclen == 0)
109 return False;
110
111 loS = (Addr)src;
112 loD = (Addr)dst;
113 hiS = loS + srclen - 1;
114 hiD = loD + dstlen - 1;
115
116 /* So figure out if [loS .. hiS] overlaps with [loD .. hiD]. */
117 if (loS < loD) {
118 return !(hiS < loD);
119 }
120 else if (loD < loS) {
121 return !(hiD < loS);
122 }
123 else {
124 /* They start at same place. Since we know neither of them has
125 zero length, they must overlap. */
126 return True;
127 }
njn3e884182003-04-15 13:03:23 +0000128}
129
sewardj126e82d2011-07-12 13:33:00 +0000130
131/* Call here to exit if we can't continue. On Android we can't call
132 _exit for some reason, so we have to blunt-instrument it. */
133__attribute__ ((__noreturn__))
134static inline void my_exit ( int x )
135{
136# if defined(VGPV_arm_linux_android)
137 __asm__ __volatile__(".word 0xFFFFFFFF");
138 while (1) {}
139# else
140 extern void _exit(int status);
sewardj49665422011-07-12 13:50:59 +0000141 _exit(x);
sewardj126e82d2011-07-12 13:33:00 +0000142# endif
143}
144
145
njn1f8b3e72005-03-22 04:27:14 +0000146// This is a macro rather than a function because we don't want to have an
147// extra function in the stack trace.
bart575ce8e2011-05-15 07:04:03 +0000148#define RECORD_OVERLAP_ERROR(s, src, dst, len) \
149 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
150 _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR, \
151 s, src, dst, len, 0)
njn3e884182003-04-15 13:03:23 +0000152
njn16eeb4e2005-06-16 03:56:58 +0000153
154#define STRRCHR(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000155 char* VG_REPLACE_FUNCTION_EZU(2001,soname,fnname)( const char* s, int c ); \
156 char* VG_REPLACE_FUNCTION_EZU(2001,soname,fnname)( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000157 { \
158 UChar ch = (UChar)((UInt)c); \
159 UChar* p = (UChar*)s; \
160 UChar* last = NULL; \
161 while (True) { \
162 if (*p == ch) last = p; \
163 if (*p == 0) return last; \
164 p++; \
165 } \
njn3e884182003-04-15 13:03:23 +0000166 }
njn3e884182003-04-15 13:03:23 +0000167
njn16eeb4e2005-06-16 03:56:58 +0000168// Apparently rindex() is the same thing as strrchr()
njne6154662009-02-10 04:23:41 +0000169STRRCHR(VG_Z_LIBC_SONAME, strrchr)
170STRRCHR(VG_Z_LIBC_SONAME, rindex)
njnb4cfbc42009-05-04 04:20:02 +0000171#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000172STRRCHR(VG_Z_LIBC_SONAME, __GI_strrchr)
njne6154662009-02-10 04:23:41 +0000173STRRCHR(VG_Z_LD_LINUX_SO_2, rindex)
njnf76d27a2009-05-28 01:53:07 +0000174#elif defined(VGO_darwin)
175STRRCHR(VG_Z_DYLD, strrchr)
176STRRCHR(VG_Z_DYLD, rindex)
njnb4cfbc42009-05-04 04:20:02 +0000177#endif
njn16eeb4e2005-06-16 03:56:58 +0000178
179
180#define STRCHR(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000181 char* VG_REPLACE_FUNCTION_EZU(2002,soname,fnname) ( const char* s, int c ); \
182 char* VG_REPLACE_FUNCTION_EZU(2002,soname,fnname) ( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000183 { \
184 UChar ch = (UChar)((UInt)c); \
185 UChar* p = (UChar*)s; \
186 while (True) { \
187 if (*p == ch) return p; \
188 if (*p == 0) return NULL; \
189 p++; \
190 } \
njn3e884182003-04-15 13:03:23 +0000191 }
njn3e884182003-04-15 13:03:23 +0000192
njn16eeb4e2005-06-16 03:56:58 +0000193// Apparently index() is the same thing as strchr()
njne6154662009-02-10 04:23:41 +0000194STRCHR(VG_Z_LIBC_SONAME, strchr)
njne6154662009-02-10 04:23:41 +0000195STRCHR(VG_Z_LIBC_SONAME, index)
njnb4cfbc42009-05-04 04:20:02 +0000196#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000197STRCHR(VG_Z_LIBC_SONAME, __GI_strchr)
njnb4cfbc42009-05-04 04:20:02 +0000198STRCHR(VG_Z_LD_LINUX_SO_2, strchr)
njne6154662009-02-10 04:23:41 +0000199STRCHR(VG_Z_LD_LINUX_SO_2, index)
njnb4cfbc42009-05-04 04:20:02 +0000200STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr)
njne6154662009-02-10 04:23:41 +0000201STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index)
njnf76d27a2009-05-28 01:53:07 +0000202#elif defined(VGO_darwin)
203STRCHR(VG_Z_DYLD, strchr)
204STRCHR(VG_Z_DYLD, index)
njnb4cfbc42009-05-04 04:20:02 +0000205#endif
njn3e884182003-04-15 13:03:23 +0000206
njn3e884182003-04-15 13:03:23 +0000207
njn16eeb4e2005-06-16 03:56:58 +0000208#define STRCAT(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000209 char* VG_REPLACE_FUNCTION_EZU(2003,soname,fnname) \
210 ( char* dst, const char* src ); \
211 char* VG_REPLACE_FUNCTION_EZU(2003,soname,fnname) \
212 ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000213 { \
214 const Char* src_orig = src; \
215 Char* dst_orig = dst; \
216 while (*dst) dst++; \
217 while (*src) *dst++ = *src++; \
218 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000219 \
njn16eeb4e2005-06-16 03:56:58 +0000220 /* This is a bit redundant, I think; any overlap and the strcat will */ \
221 /* go forever... or until a seg fault occurs. */ \
222 if (is_overlap(dst_orig, \
223 src_orig, \
224 (Addr)dst-(Addr)dst_orig+1, \
225 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000226 RECORD_OVERLAP_ERROR("strcat", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000227 \
njn16eeb4e2005-06-16 03:56:58 +0000228 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000229 }
njn3e884182003-04-15 13:03:23 +0000230
njne6154662009-02-10 04:23:41 +0000231STRCAT(VG_Z_LIBC_SONAME, strcat)
tomd2645142009-10-29 09:27:11 +0000232#if defined(VGO_linux)
233STRCAT(VG_Z_LIBC_SONAME, __GI_strcat)
234#endif
njn16eeb4e2005-06-16 03:56:58 +0000235
236#define STRNCAT(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000237 char* VG_REPLACE_FUNCTION_EZU(2004,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000238 ( char* dst, const char* src, SizeT n ); \
sewardjbd2cff22011-08-16 21:45:28 +0000239 char* VG_REPLACE_FUNCTION_EZU(2004,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000240 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000241 { \
242 const Char* src_orig = src; \
243 Char* dst_orig = dst; \
244 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000245 \
njn16eeb4e2005-06-16 03:56:58 +0000246 while (*dst) dst++; \
247 while (m < n && *src) { m++; *dst++ = *src++; } /* concat <= n chars */ \
248 *dst = 0; /* always add null */ \
sewardjb6c04032007-11-13 20:52:29 +0000249 \
njn16eeb4e2005-06-16 03:56:58 +0000250 /* This checks for overlap after copying, unavoidable without */ \
251 /* pre-counting lengths... should be ok */ \
252 if (is_overlap(dst_orig, \
253 src_orig, \
sewardjbd2cff22011-08-16 21:45:28 +0000254 (Addr)dst-(Addr)dst_orig+1, \
njn16eeb4e2005-06-16 03:56:58 +0000255 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000256 RECORD_OVERLAP_ERROR("strncat", dst_orig, src_orig, n); \
sewardjb6c04032007-11-13 20:52:29 +0000257 \
njn16eeb4e2005-06-16 03:56:58 +0000258 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000259 }
njn3e884182003-04-15 13:03:23 +0000260
njne6154662009-02-10 04:23:41 +0000261STRNCAT(VG_Z_LIBC_SONAME, strncat)
njnf76d27a2009-05-28 01:53:07 +0000262#if defined(VGO_darwin)
263STRNCAT(VG_Z_DYLD, strncat)
264#endif
265
266
267/* Append src to dst. n is the size of dst's buffer. dst is guaranteed
268 to be nul-terminated after the copy, unless n <= strlen(dst_orig).
269 Returns min(n, strlen(dst_orig)) + strlen(src_orig).
270 Truncation occurred if retval >= n.
271*/
272#define STRLCAT(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000273 SizeT VG_REPLACE_FUNCTION_EZU(2005,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000274 ( char* dst, const char* src, SizeT n ); \
sewardjbd2cff22011-08-16 21:45:28 +0000275 SizeT VG_REPLACE_FUNCTION_EZU(2005,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000276 ( char* dst, const char* src, SizeT n ) \
277 { \
278 const Char* src_orig = src; \
279 Char* dst_orig = dst; \
280 SizeT m = 0; \
sewardjbd2cff22011-08-16 21:45:28 +0000281 \
njnf76d27a2009-05-28 01:53:07 +0000282 while (m < n && *dst) { m++; dst++; } \
283 if (m < n) { \
284 /* Fill as far as dst_orig[n-2], then nul-terminate. */ \
285 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
286 *dst = 0; \
287 } else { \
288 /* No space to copy anything to dst. m == n */ \
289 } \
290 /* Finish counting min(n, strlen(dst_orig)) + strlen(src_orig) */ \
291 while (*src) { m++; src++; } \
292 /* This checks for overlap after copying, unavoidable without */ \
293 /* pre-counting lengths... should be ok */ \
294 if (is_overlap(dst_orig, \
295 src_orig, \
296 (Addr)dst-(Addr)dst_orig+1, \
297 (Addr)src-(Addr)src_orig+1)) \
298 RECORD_OVERLAP_ERROR("strlcat", dst_orig, src_orig, n); \
sewardjbd2cff22011-08-16 21:45:28 +0000299 \
njnf76d27a2009-05-28 01:53:07 +0000300 return m; \
301 }
302
303#if defined(VGO_darwin)
304STRLCAT(VG_Z_LIBC_SONAME, strlcat)
305STRLCAT(VG_Z_DYLD, strlcat)
306#endif
sewardj31b9ce12006-10-17 01:27:13 +0000307
njn3e884182003-04-15 13:03:23 +0000308
njn16eeb4e2005-06-16 03:56:58 +0000309#define STRNLEN(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000310 SizeT VG_REPLACE_FUNCTION_EZU(2006,soname,fnname) \
311 ( const char* str, SizeT n ); \
312 SizeT VG_REPLACE_FUNCTION_EZU(2006,soname,fnname) \
313 ( const char* str, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000314 { \
315 SizeT i = 0; \
316 while (i < n && str[i] != 0) i++; \
317 return i; \
njn3e884182003-04-15 13:03:23 +0000318 }
njn3e884182003-04-15 13:03:23 +0000319
njne6154662009-02-10 04:23:41 +0000320STRNLEN(VG_Z_LIBC_SONAME, strnlen)
tomd2645142009-10-29 09:27:11 +0000321#if defined(VGO_linux)
322STRNLEN(VG_Z_LIBC_SONAME, __GI_strnlen)
323#endif
njn16eeb4e2005-06-16 03:56:58 +0000324
sewardj3ceec242003-07-30 21:24:25 +0000325
njn5ec15ed2005-08-24 19:55:51 +0000326// Note that this replacement often doesn't get used because gcc inlines
327// calls to strlen() with its own built-in version. This can be very
328// confusing if you aren't expecting it. Other small functions in this file
329// may also be inline by gcc.
njn16eeb4e2005-06-16 03:56:58 +0000330#define STRLEN(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000331 SizeT VG_REPLACE_FUNCTION_EZU(2007,soname,fnname) \
332 ( const char* str ); \
333 SizeT VG_REPLACE_FUNCTION_EZU(2007,soname,fnname) \
334 ( const char* str ) \
njn16eeb4e2005-06-16 03:56:58 +0000335 { \
336 SizeT i = 0; \
337 while (str[i] != 0) i++; \
338 return i; \
sewardj3ceec242003-07-30 21:24:25 +0000339 }
njn16eeb4e2005-06-16 03:56:58 +0000340
njnb4cfbc42009-05-04 04:20:02 +0000341STRLEN(VG_Z_LIBC_SONAME, strlen)
342#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000343STRLEN(VG_Z_LIBC_SONAME, __GI_strlen)
njnb4cfbc42009-05-04 04:20:02 +0000344#endif
sewardj31b9ce12006-10-17 01:27:13 +0000345
njn16eeb4e2005-06-16 03:56:58 +0000346
347#define STRCPY(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000348 char* VG_REPLACE_FUNCTION_EZU(2008,soname,fnname) \
349 ( char* dst, const char* src ); \
350 char* VG_REPLACE_FUNCTION_EZU(2008,soname,fnname) \
351 ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000352 { \
353 const Char* src_orig = src; \
354 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000355 \
njn16eeb4e2005-06-16 03:56:58 +0000356 while (*src) *dst++ = *src++; \
357 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000358 \
njn16eeb4e2005-06-16 03:56:58 +0000359 /* This checks for overlap after copying, unavoidable without */ \
360 /* pre-counting length... should be ok */ \
361 if (is_overlap(dst_orig, \
362 src_orig, \
sewardjbd2cff22011-08-16 21:45:28 +0000363 (Addr)dst-(Addr)dst_orig+1, \
njn16eeb4e2005-06-16 03:56:58 +0000364 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000365 RECORD_OVERLAP_ERROR("strcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000366 \
njn16eeb4e2005-06-16 03:56:58 +0000367 return dst_orig; \
368 }
369
njne6154662009-02-10 04:23:41 +0000370STRCPY(VG_Z_LIBC_SONAME, strcpy)
tomd2645142009-10-29 09:27:11 +0000371#if defined(VGO_linux)
372STRCPY(VG_Z_LIBC_SONAME, __GI_strcpy)
373#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000374STRCPY(VG_Z_DYLD, strcpy)
375#endif
njn16eeb4e2005-06-16 03:56:58 +0000376
377
378#define STRNCPY(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000379 char* VG_REPLACE_FUNCTION_EZU(2009,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000380 ( char* dst, const char* src, SizeT n ); \
sewardjbd2cff22011-08-16 21:45:28 +0000381 char* VG_REPLACE_FUNCTION_EZU(2009,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000382 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000383 { \
384 const Char* src_orig = src; \
385 Char* dst_orig = dst; \
386 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000387 \
njn16eeb4e2005-06-16 03:56:58 +0000388 while (m < n && *src) { m++; *dst++ = *src++; } \
389 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
390 /* but only m+1 bytes of src if terminator was found */ \
391 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
njn718d3b12006-12-16 00:54:12 +0000392 RECORD_OVERLAP_ERROR("strncpy", dst, src, n); \
njn16eeb4e2005-06-16 03:56:58 +0000393 while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */ \
394 \
395 return dst_orig; \
396 }
397
njne6154662009-02-10 04:23:41 +0000398STRNCPY(VG_Z_LIBC_SONAME, strncpy)
tomd2645142009-10-29 09:27:11 +0000399#if defined(VGO_linux)
400STRNCPY(VG_Z_LIBC_SONAME, __GI_strncpy)
401#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000402STRNCPY(VG_Z_DYLD, strncpy)
403#endif
404
405
406/* Copy up to n-1 bytes from src to dst. Then nul-terminate dst if n > 0.
407 Returns strlen(src). Does not zero-fill the remainder of dst. */
408#define STRLCPY(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000409 SizeT VG_REPLACE_FUNCTION_EZU(2010,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000410 ( char* dst, const char* src, SizeT n ); \
sewardjbd2cff22011-08-16 21:45:28 +0000411 SizeT VG_REPLACE_FUNCTION_EZU(2010,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000412 ( char* dst, const char* src, SizeT n ) \
413 { \
414 const char* src_orig = src; \
415 char* dst_orig = dst; \
416 SizeT m = 0; \
sewardjbd2cff22011-08-16 21:45:28 +0000417 \
njnf76d27a2009-05-28 01:53:07 +0000418 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
419 /* m non-nul bytes have now been copied, and m <= n-1. */ \
420 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
421 /* but only m+1 bytes of src if terminator was found */ \
422 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
423 RECORD_OVERLAP_ERROR("strlcpy", dst, src, n); \
424 /* Nul-terminate dst. */ \
425 if (n > 0) *dst = 0; \
426 /* Finish counting strlen(src). */ \
427 while (*src) src++; \
428 return src - src_orig; \
429 }
430
431#if defined(VGO_darwin)
432STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
433STRLCPY(VG_Z_DYLD, strlcpy)
434#endif
njn16eeb4e2005-06-16 03:56:58 +0000435
436
437#define STRNCMP(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000438 int VG_REPLACE_FUNCTION_EZU(2011,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000439 ( const char* s1, const char* s2, SizeT nmax ); \
sewardjbd2cff22011-08-16 21:45:28 +0000440 int VG_REPLACE_FUNCTION_EZU(2011,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000441 ( const char* s1, const char* s2, SizeT nmax ) \
njn16eeb4e2005-06-16 03:56:58 +0000442 { \
443 SizeT n = 0; \
444 while (True) { \
445 if (n >= nmax) return 0; \
446 if (*s1 == 0 && *s2 == 0) return 0; \
447 if (*s1 == 0) return -1; \
448 if (*s2 == 0) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000449 \
njn16eeb4e2005-06-16 03:56:58 +0000450 if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1; \
451 if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000452 \
njn16eeb4e2005-06-16 03:56:58 +0000453 s1++; s2++; n++; \
454 } \
455 }
456
njne6154662009-02-10 04:23:41 +0000457STRNCMP(VG_Z_LIBC_SONAME, strncmp)
tomd2645142009-10-29 09:27:11 +0000458#if defined(VGO_linux)
459STRNCMP(VG_Z_LIBC_SONAME, __GI_strncmp)
460#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000461STRNCMP(VG_Z_DYLD, strncmp)
462#endif
njn16eeb4e2005-06-16 03:56:58 +0000463
464
tomce6d0ac2010-11-12 10:03:13 +0000465#define STRCASECMP(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000466 int VG_REPLACE_FUNCTION_EZU(2012,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000467 ( const char* s1, const char* s2 ); \
sewardjbd2cff22011-08-16 21:45:28 +0000468 int VG_REPLACE_FUNCTION_EZU(2012,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000469 ( const char* s1, const char* s2 ) \
470 { \
tome03c8c42010-11-12 10:40:20 +0000471 extern int tolower(int); \
tomce6d0ac2010-11-12 10:03:13 +0000472 register unsigned char c1; \
473 register unsigned char c2; \
474 while (True) { \
475 c1 = tolower(*(unsigned char *)s1); \
476 c2 = tolower(*(unsigned char *)s2); \
477 if (c1 != c2) break; \
478 if (c1 == 0) break; \
479 s1++; s2++; \
480 } \
481 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
482 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
483 return 0; \
484 }
485
sewardj126e82d2011-07-12 13:33:00 +0000486#if !defined(VGPV_arm_linux_android)
tomce6d0ac2010-11-12 10:03:13 +0000487STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp)
sewardj126e82d2011-07-12 13:33:00 +0000488#endif
489#if defined(VGO_linux) && !defined(VGPV_arm_linux_android)
tomce6d0ac2010-11-12 10:03:13 +0000490STRCASECMP(VG_Z_LIBC_SONAME, __GI_strcasecmp)
491#endif
492
493
494#define STRNCASECMP(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000495 int VG_REPLACE_FUNCTION_EZU(2013,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000496 ( const char* s1, const char* s2, SizeT nmax ); \
sewardjbd2cff22011-08-16 21:45:28 +0000497 int VG_REPLACE_FUNCTION_EZU(2013,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000498 ( const char* s1, const char* s2, SizeT nmax ) \
499 { \
tome03c8c42010-11-12 10:40:20 +0000500 extern int tolower(int); \
tomce6d0ac2010-11-12 10:03:13 +0000501 SizeT n = 0; \
502 while (True) { \
503 if (n >= nmax) return 0; \
504 if (*s1 == 0 && *s2 == 0) return 0; \
505 if (*s1 == 0) return -1; \
506 if (*s2 == 0) return 1; \
507 \
sewardjbd2cff22011-08-16 21:45:28 +0000508 if (tolower(*(unsigned char*)s1) \
509 < tolower(*(unsigned char*)s2)) return -1; \
510 if (tolower(*(unsigned char*)s1) \
511 > tolower(*(unsigned char*)s2)) return 1; \
tomce6d0ac2010-11-12 10:03:13 +0000512 \
513 s1++; s2++; n++; \
514 } \
515 }
516
sewardj126e82d2011-07-12 13:33:00 +0000517#if !defined(VGPV_arm_linux_android)
tomce6d0ac2010-11-12 10:03:13 +0000518STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp)
sewardj126e82d2011-07-12 13:33:00 +0000519#endif
520#if defined(VGO_linux) && !defined(VGPV_arm_linux_android)
tomce6d0ac2010-11-12 10:03:13 +0000521STRNCASECMP(VG_Z_LIBC_SONAME, __GI_strncasecmp)
522#elif defined(VGO_darwin)
523STRNCASECMP(VG_Z_DYLD, strncasecmp)
524#endif
525
526
tomce6d0ac2010-11-12 10:03:13 +0000527#define STRCASECMP_L(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000528 int VG_REPLACE_FUNCTION_EZU(2014,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000529 ( const char* s1, const char* s2, void* locale ); \
sewardjbd2cff22011-08-16 21:45:28 +0000530 int VG_REPLACE_FUNCTION_EZU(2014,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000531 ( const char* s1, const char* s2, void* locale ) \
tomce6d0ac2010-11-12 10:03:13 +0000532 { \
tome03c8c42010-11-12 10:40:20 +0000533 extern int tolower_l(int, void*) __attribute__((weak)); \
tomce6d0ac2010-11-12 10:03:13 +0000534 register unsigned char c1; \
535 register unsigned char c2; \
536 while (True) { \
537 c1 = tolower_l(*(unsigned char *)s1, locale); \
538 c2 = tolower_l(*(unsigned char *)s2, locale); \
539 if (c1 != c2) break; \
540 if (c1 == 0) break; \
541 s1++; s2++; \
542 } \
543 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
544 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
545 return 0; \
546 }
547
548STRCASECMP_L(VG_Z_LIBC_SONAME, strcasecmp_l)
549#if defined(VGO_linux)
550STRCASECMP_L(VG_Z_LIBC_SONAME, __GI_strcasecmp_l)
sewardjbd2cff22011-08-16 21:45:28 +0000551STRCASECMP_L(VG_Z_LIBC_SONAME, __GI___strcasecmp_l)
tomce6d0ac2010-11-12 10:03:13 +0000552#endif
553
554
555#define STRNCASECMP_L(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000556 int VG_REPLACE_FUNCTION_EZU(2015,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000557 ( const char* s1, const char* s2, SizeT nmax, void* locale ); \
sewardjbd2cff22011-08-16 21:45:28 +0000558 int VG_REPLACE_FUNCTION_EZU(2015,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000559 ( const char* s1, const char* s2, SizeT nmax, void* locale ) \
tomce6d0ac2010-11-12 10:03:13 +0000560 { \
tome03c8c42010-11-12 10:40:20 +0000561 extern int tolower_l(int, void*) __attribute__((weak)); \
tomce6d0ac2010-11-12 10:03:13 +0000562 SizeT n = 0; \
563 while (True) { \
564 if (n >= nmax) return 0; \
565 if (*s1 == 0 && *s2 == 0) return 0; \
566 if (*s1 == 0) return -1; \
567 if (*s2 == 0) return 1; \
568 \
sewardjbd2cff22011-08-16 21:45:28 +0000569 if (tolower_l(*(unsigned char*)s1, locale) \
570 < tolower_l(*(unsigned char*)s2, locale)) return -1; \
571 if (tolower_l(*(unsigned char*)s1, locale) \
572 > tolower_l(*(unsigned char*)s2, locale)) return 1; \
tomce6d0ac2010-11-12 10:03:13 +0000573 \
574 s1++; s2++; n++; \
575 } \
576 }
577
578STRNCASECMP_L(VG_Z_LIBC_SONAME, strncasecmp_l)
579#if defined(VGO_linux)
580STRNCASECMP_L(VG_Z_LIBC_SONAME, __GI_strncasecmp_l)
581#elif defined(VGO_darwin)
582STRNCASECMP_L(VG_Z_DYLD, strncasecmp_l)
583#endif
584
585
njn16eeb4e2005-06-16 03:56:58 +0000586#define STRCMP(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000587 int VG_REPLACE_FUNCTION_EZU(2016,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000588 ( const char* s1, const char* s2 ); \
sewardjbd2cff22011-08-16 21:45:28 +0000589 int VG_REPLACE_FUNCTION_EZU(2016,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000590 ( const char* s1, const char* s2 ) \
njn16eeb4e2005-06-16 03:56:58 +0000591 { \
592 register unsigned char c1; \
593 register unsigned char c2; \
594 while (True) { \
595 c1 = *(unsigned char *)s1; \
596 c2 = *(unsigned char *)s2; \
597 if (c1 != c2) break; \
598 if (c1 == 0) break; \
599 s1++; s2++; \
600 } \
601 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
602 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
603 return 0; \
604 }
605
njne6154662009-02-10 04:23:41 +0000606STRCMP(VG_Z_LIBC_SONAME, strcmp)
njnb4cfbc42009-05-04 04:20:02 +0000607#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000608STRCMP(VG_Z_LIBC_SONAME, __GI_strcmp)
njne6154662009-02-10 04:23:41 +0000609STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp)
610STRCMP(VG_Z_LD64_SO_1, strcmp)
njnb4cfbc42009-05-04 04:20:02 +0000611#endif
njn16eeb4e2005-06-16 03:56:58 +0000612
613
614#define MEMCHR(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000615 void* VG_REPLACE_FUNCTION_EZU(2017,soname,fnname) \
616 (const void *s, int c, SizeT n); \
617 void* VG_REPLACE_FUNCTION_EZU(2017,soname,fnname) \
618 (const void *s, int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000619 { \
620 SizeT i; \
621 UChar c0 = (UChar)c; \
622 UChar* p = (UChar*)s; \
623 for (i = 0; i < n; i++) \
624 if (p[i] == c0) return (void*)(&p[i]); \
625 return NULL; \
626 }
627
njne6154662009-02-10 04:23:41 +0000628MEMCHR(VG_Z_LIBC_SONAME, memchr)
njnf76d27a2009-05-28 01:53:07 +0000629#if defined(VGO_darwin)
630MEMCHR(VG_Z_DYLD, memchr)
631#endif
njn16eeb4e2005-06-16 03:56:58 +0000632
633
sewardjbd2cff22011-08-16 21:45:28 +0000634#define MEMMOVE_OR_MEMCPY(becTag, soname, fnname, do_ol_check) \
sewardjd88797f2011-08-17 21:25:50 +0000635 void* VG_REPLACE_FUNCTION_EZZ(becTag,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000636 ( void *dst, const void *src, SizeT len ); \
sewardjd88797f2011-08-17 21:25:50 +0000637 void* VG_REPLACE_FUNCTION_EZZ(becTag,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000638 ( void *dst, const void *src, SizeT len ) \
njn16eeb4e2005-06-16 03:56:58 +0000639 { \
sewardjbd2cff22011-08-16 21:45:28 +0000640 if (do_ol_check && is_overlap(dst, src, len, len)) \
njn718d3b12006-12-16 00:54:12 +0000641 RECORD_OVERLAP_ERROR("memcpy", dst, src, len); \
sewardjb6c04032007-11-13 20:52:29 +0000642 \
sewardj7b4e00b2010-08-24 09:05:52 +0000643 const Addr WS = sizeof(UWord); /* 8 or 4 */ \
644 const Addr WM = WS - 1; /* 7 or 3 */ \
645 \
tom863ab7c2011-08-18 08:10:20 +0000646 if (len > 0) { \
647 if (dst < src) { \
sewardj7b4e00b2010-08-24 09:05:52 +0000648 \
tom863ab7c2011-08-18 08:10:20 +0000649 /* Copying backwards. */ \
650 SizeT n = len; \
651 Addr d = (Addr)dst; \
652 Addr s = (Addr)src; \
653 \
654 if (((s^d) & WM) == 0) { \
655 /* s and d have same UWord alignment. */ \
656 /* Pull up to a UWord boundary. */ \
657 while ((s & WM) != 0 && n >= 1) \
658 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
659 /* Copy UWords. */ \
660 while (n >= WS) \
661 { *(UWord*)d = *(UWord*)s; s += WS; d += WS; n -= WS; } \
662 if (n == 0) \
663 return dst; \
664 } \
665 if (((s|d) & 1) == 0) { \
666 /* Both are 16-aligned; copy what we can thusly. */ \
667 while (n >= 2) \
668 { *(UShort*)d = *(UShort*)s; s += 2; d += 2; n -= 2; } \
669 } \
670 /* Copy leftovers, or everything if misaligned. */ \
671 while (n >= 1) \
sewardj7b4e00b2010-08-24 09:05:52 +0000672 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
sewardj7b4e00b2010-08-24 09:05:52 +0000673 \
tom863ab7c2011-08-18 08:10:20 +0000674 } else if (dst > src) { \
675 \
676 SizeT n = len; \
677 Addr d = ((Addr)dst) + n; \
678 Addr s = ((Addr)src) + n; \
679 \
680 /* Copying forwards. */ \
681 if (((s^d) & WM) == 0) { \
682 /* s and d have same UWord alignment. */ \
683 /* Back down to a UWord boundary. */ \
684 while ((s & WM) != 0 && n >= 1) \
685 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
686 /* Copy UWords. */ \
687 while (n >= WS) \
688 { s -= WS; d -= WS; *(UWord*)d = *(UWord*)s; n -= WS; } \
689 if (n == 0) \
690 return dst; \
691 } \
692 if (((s|d) & 1) == 0) { \
693 /* Both are 16-aligned; copy what we can thusly. */ \
694 while (n >= 2) \
695 { s -= 2; d -= 2; *(UShort*)d = *(UShort*)s; n -= 2; } \
696 } \
697 /* Copy leftovers, or everything if misaligned. */ \
698 while (n >= 1) \
sewardj7b4e00b2010-08-24 09:05:52 +0000699 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
tom863ab7c2011-08-18 08:10:20 +0000700 \
njn16eeb4e2005-06-16 03:56:58 +0000701 } \
njn16eeb4e2005-06-16 03:56:58 +0000702 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000703 \
njn16eeb4e2005-06-16 03:56:58 +0000704 return dst; \
705 }
706
sewardjbd2cff22011-08-16 21:45:28 +0000707#define MEMMOVE(soname, fnname) \
708 MEMMOVE_OR_MEMCPY(2018, soname, fnname, 0)
709
710#define MEMCPY(soname, fnname) \
711 MEMMOVE_OR_MEMCPY(2022, soname, fnname, 1)
712
njnb4cfbc42009-05-04 04:20:02 +0000713#if defined(VGO_linux)
sewardjbd2cff22011-08-16 21:45:28 +0000714/* For older memcpy we have to use memmove-like semantics and skip the
715 overlap check; sigh; see #275284. */
sewardjd88797f2011-08-17 21:25:50 +0000716MEMMOVE(VG_Z_LIBC_SONAME, memcpyZAGLIBCZu2Zd2Zd5) /* memcpy@GLIBC_2.2.5 */
717MEMCPY(VG_Z_LIBC_SONAME, memcpyZAZAGLIBCZu2Zd14) /* memcpy@@GLIBC_2.14 */
718MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */
719MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */
njnf76d27a2009-05-28 01:53:07 +0000720#elif defined(VGO_darwin)
sewardjd88797f2011-08-17 21:25:50 +0000721MEMCPY(VG_Z_LIBC_SONAME, memcpy)
722MEMCPY(VG_Z_DYLD, memcpy)
njnb4cfbc42009-05-04 04:20:02 +0000723#endif
sewardjf0b34322007-01-16 21:42:28 +0000724/* icc9 blats these around all over the place. Not only in the main
725 executable but various .so's. They are highly tuned and read
726 memory beyond the source boundary (although work correctly and
727 never go across page boundaries), so give errors when run natively,
728 at least for misaligned source arg. Just intercepting in the exe
729 only until we understand more about the problem. See
730 http://bugs.kde.org/show_bug.cgi?id=139776
731 */
sewardjd88797f2011-08-17 21:25:50 +0000732MEMCPY(NONE, ZuintelZufastZumemcpy)
sewardj31b9ce12006-10-17 01:27:13 +0000733
njn16eeb4e2005-06-16 03:56:58 +0000734
735#define MEMCMP(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000736 int VG_REPLACE_FUNCTION_EZU(2019,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000737 ( const void *s1V, const void *s2V, SizeT n ); \
sewardjbd2cff22011-08-16 21:45:28 +0000738 int VG_REPLACE_FUNCTION_EZU(2019,soname,fnname) \
739 ( const void *s1V, const void *s2V, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000740 { \
741 int res; \
742 unsigned char a0; \
743 unsigned char b0; \
744 unsigned char* s1 = (unsigned char*)s1V; \
745 unsigned char* s2 = (unsigned char*)s2V; \
sewardjb6c04032007-11-13 20:52:29 +0000746 \
njn16eeb4e2005-06-16 03:56:58 +0000747 while (n != 0) { \
748 a0 = s1[0]; \
749 b0 = s2[0]; \
750 s1 += 1; \
751 s2 += 1; \
752 res = ((int)a0) - ((int)b0); \
753 if (res != 0) \
754 return res; \
755 n -= 1; \
756 } \
757 return 0; \
758 }
759
njne6154662009-02-10 04:23:41 +0000760MEMCMP(VG_Z_LIBC_SONAME, memcmp)
761MEMCMP(VG_Z_LIBC_SONAME, bcmp)
njnb4cfbc42009-05-04 04:20:02 +0000762#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +0000763MEMCMP(VG_Z_LD_SO_1, bcmp)
njnf76d27a2009-05-28 01:53:07 +0000764#elif defined(VGO_darwin)
765MEMCMP(VG_Z_DYLD, memcmp)
766MEMCMP(VG_Z_DYLD, bcmp)
njnb4cfbc42009-05-04 04:20:02 +0000767#endif
njn3e884182003-04-15 13:03:23 +0000768
jseward0845ef82003-12-22 22:31:27 +0000769
770/* Copy SRC to DEST, returning the address of the terminating '\0' in
771 DEST. (minor variant of strcpy) */
njn16eeb4e2005-06-16 03:56:58 +0000772#define STPCPY(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000773 char* VG_REPLACE_FUNCTION_EZU(2020,soname,fnname) \
774 ( char* dst, const char* src ); \
775 char* VG_REPLACE_FUNCTION_EZU(2020,soname,fnname) \
776 ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000777 { \
778 const Char* src_orig = src; \
779 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000780 \
njn16eeb4e2005-06-16 03:56:58 +0000781 while (*src) *dst++ = *src++; \
782 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000783 \
njn16eeb4e2005-06-16 03:56:58 +0000784 /* This checks for overlap after copying, unavoidable without */ \
785 /* pre-counting length... should be ok */ \
786 if (is_overlap(dst_orig, \
787 src_orig, \
788 (Addr)dst-(Addr)dst_orig+1, \
789 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000790 RECORD_OVERLAP_ERROR("stpcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000791 \
njn16eeb4e2005-06-16 03:56:58 +0000792 return dst; \
sewardj44e495f2005-05-12 17:58:28 +0000793 }
njn16eeb4e2005-06-16 03:56:58 +0000794
njne6154662009-02-10 04:23:41 +0000795STPCPY(VG_Z_LIBC_SONAME, stpcpy)
njnb4cfbc42009-05-04 04:20:02 +0000796#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000797STPCPY(VG_Z_LIBC_SONAME, __GI_stpcpy)
njne6154662009-02-10 04:23:41 +0000798STPCPY(VG_Z_LD_LINUX_SO_2, stpcpy)
799STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy)
njnf76d27a2009-05-28 01:53:07 +0000800#elif defined(VGO_darwin)
801STPCPY(VG_Z_DYLD, stpcpy)
njnb4cfbc42009-05-04 04:20:02 +0000802#endif
803
njn16eeb4e2005-06-16 03:56:58 +0000804
805#define MEMSET(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000806 void* VG_REPLACE_FUNCTION_EZU(2021,soname,fnname) \
807 (void *s, Int c, SizeT n); \
808 void* VG_REPLACE_FUNCTION_EZU(2021,soname,fnname) \
809 (void *s, Int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000810 { \
sewardj7b4e00b2010-08-24 09:05:52 +0000811 Addr a = (Addr)s; \
812 UInt c4 = (c & 0xFF); \
813 c4 = (c4 << 8) | c4; \
814 c4 = (c4 << 16) | c4; \
815 while ((a & 3) != 0 && n >= 1) \
816 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
817 while (n >= 4) \
818 { *(UInt*)a = c4; a += 4; n -= 4; } \
819 while (n >= 1) \
820 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
njn16eeb4e2005-06-16 03:56:58 +0000821 return s; \
sewardj44e495f2005-05-12 17:58:28 +0000822 }
njn16eeb4e2005-06-16 03:56:58 +0000823
njne6154662009-02-10 04:23:41 +0000824MEMSET(VG_Z_LIBC_SONAME, memset)
njnf76d27a2009-05-28 01:53:07 +0000825#if defined(VGO_darwin)
826MEMSET(VG_Z_DYLD, memset)
827#endif
njn16eeb4e2005-06-16 03:56:58 +0000828
829
sewardjbd2cff22011-08-16 21:45:28 +0000830/* memmove -- use the MEMMOVE defn which also serves for memcpy. */
njne6154662009-02-10 04:23:41 +0000831MEMMOVE(VG_Z_LIBC_SONAME, memmove)
njnf76d27a2009-05-28 01:53:07 +0000832#if defined(VGO_darwin)
833MEMMOVE(VG_Z_DYLD, memmove)
834#endif
835
836
837#define BCOPY(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000838 void VG_REPLACE_FUNCTION_EZU(2023,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000839 (const void *srcV, void *dstV, SizeT n); \
sewardjbd2cff22011-08-16 21:45:28 +0000840 void VG_REPLACE_FUNCTION_EZU(2023,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000841 (const void *srcV, void *dstV, SizeT n) \
842 { \
843 SizeT i; \
844 Char* dst = (Char*)dstV; \
845 Char* src = (Char*)srcV; \
846 if (dst < src) { \
847 for (i = 0; i < n; i++) \
848 dst[i] = src[i]; \
849 } \
850 else \
851 if (dst > src) { \
852 for (i = 0; i < n; i++) \
853 dst[n-i-1] = src[n-i-1]; \
854 } \
855 }
856
857#if defined(VGO_darwin)
858BCOPY(VG_Z_LIBC_SONAME, bcopy)
859BCOPY(VG_Z_DYLD, bcopy)
860#endif
sewardj44e495f2005-05-12 17:58:28 +0000861
jseward0845ef82003-12-22 22:31:27 +0000862
sewardj24cb2172007-02-23 09:03:26 +0000863/* glibc 2.5 variant of memmove which checks the dest is big enough.
864 There is no specific part of glibc that this is copied from. */
865#define GLIBC25___MEMMOVE_CHK(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000866 void* VG_REPLACE_FUNCTION_EZU(2024,soname,fnname) \
sewardj24cb2172007-02-23 09:03:26 +0000867 (void *dstV, const void *srcV, SizeT n, SizeT destlen); \
sewardjbd2cff22011-08-16 21:45:28 +0000868 void* VG_REPLACE_FUNCTION_EZU(2024,soname,fnname) \
sewardj24cb2172007-02-23 09:03:26 +0000869 (void *dstV, const void *srcV, SizeT n, SizeT destlen) \
870 { \
sewardj24cb2172007-02-23 09:03:26 +0000871 SizeT i; \
872 Char* dst = (Char*)dstV; \
873 Char* src = (Char*)srcV; \
874 if (destlen < n) \
875 goto badness; \
876 if (dst < src) { \
877 for (i = 0; i < n; i++) \
878 dst[i] = src[i]; \
879 } \
880 else \
881 if (dst > src) { \
882 for (i = 0; i < n; i++) \
883 dst[n-i-1] = src[n-i-1]; \
884 } \
885 return dst; \
886 badness: \
887 VALGRIND_PRINTF_BACKTRACE( \
888 "*** memmove_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000889 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +0000890 my_exit(127); \
sewardjc271ec82007-02-27 22:36:14 +0000891 /*NOTREACHED*/ \
892 return NULL; \
sewardj24cb2172007-02-23 09:03:26 +0000893 }
894
njne6154662009-02-10 04:23:41 +0000895GLIBC25___MEMMOVE_CHK(VG_Z_LIBC_SONAME, __memmove_chk)
sewardj24cb2172007-02-23 09:03:26 +0000896
897
sewardj4e9a4b62004-11-23 00:20:17 +0000898/* Find the first occurrence of C in S or the final NUL byte. */
njn16eeb4e2005-06-16 03:56:58 +0000899#define GLIBC232_STRCHRNUL(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000900 char* VG_REPLACE_FUNCTION_EZU(2025,soname,fnname) \
901 (const char* s, int c_in); \
902 char* VG_REPLACE_FUNCTION_EZU(2025,soname,fnname) \
903 (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +0000904 { \
905 unsigned char c = (unsigned char) c_in; \
906 unsigned char* char_ptr = (unsigned char *)s; \
907 while (1) { \
908 if (*char_ptr == 0) return char_ptr; \
909 if (*char_ptr == c) return char_ptr; \
910 char_ptr++; \
911 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000912 }
njn16eeb4e2005-06-16 03:56:58 +0000913
njne6154662009-02-10 04:23:41 +0000914GLIBC232_STRCHRNUL(VG_Z_LIBC_SONAME, strchrnul)
sewardj4e9a4b62004-11-23 00:20:17 +0000915
916
917/* Find the first occurrence of C in S. */
njn16eeb4e2005-06-16 03:56:58 +0000918#define GLIBC232_RAWMEMCHR(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000919 char* VG_REPLACE_FUNCTION_EZU(2026,soname,fnname) \
920 (const char* s, int c_in); \
921 char* VG_REPLACE_FUNCTION_EZU(2026,soname,fnname) \
922 (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +0000923 { \
924 unsigned char c = (unsigned char) c_in; \
925 unsigned char* char_ptr = (unsigned char *)s; \
926 while (1) { \
927 if (*char_ptr == c) return char_ptr; \
928 char_ptr++; \
929 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000930 }
njn16eeb4e2005-06-16 03:56:58 +0000931
njne6154662009-02-10 04:23:41 +0000932GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, rawmemchr)
tomd2645142009-10-29 09:27:11 +0000933#if defined (VGO_linux)
934GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, __GI___rawmemchr)
935#endif
sewardj4e9a4b62004-11-23 00:20:17 +0000936
sewardjdc5d8322007-01-28 06:32:01 +0000937/* glibc variant of strcpy that checks the dest is big enough.
938 Copied from glibc-2.5/debug/test-strcpy_chk.c. */
sewardj620e5262006-12-31 00:22:30 +0000939#define GLIBC25___STRCPY_CHK(soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000940 char* VG_REPLACE_FUNCTION_EZU(2027,soname,fnname) \
941 (char* dst, const char* src, SizeT len); \
942 char* VG_REPLACE_FUNCTION_EZU(2027,soname,fnname) \
943 (char* dst, const char* src, SizeT len) \
sewardj620e5262006-12-31 00:22:30 +0000944 { \
sewardj620e5262006-12-31 00:22:30 +0000945 char* ret = dst; \
946 if (! len) \
947 goto badness; \
948 while ((*dst++ = *src++) != '\0') \
949 if (--len == 0) \
950 goto badness; \
951 return ret; \
952 badness: \
953 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +0000954 "*** strcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000955 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +0000956 my_exit(127); \
sewardj620e5262006-12-31 00:22:30 +0000957 /*NOTREACHED*/ \
958 return NULL; \
959 }
960
njne6154662009-02-10 04:23:41 +0000961GLIBC25___STRCPY_CHK(VG_Z_LIBC_SONAME, __strcpy_chk)
sewardj620e5262006-12-31 00:22:30 +0000962
963
sewardjdc5d8322007-01-28 06:32:01 +0000964/* glibc variant of stpcpy that checks the dest is big enough.
965 Copied from glibc-2.5/debug/test-stpcpy_chk.c. */
sewardjb8d03852007-01-27 00:49:44 +0000966#define GLIBC25___STPCPY_CHK(soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000967 char* VG_REPLACE_FUNCTION_EZU(2028,soname,fnname) \
968 (char* dst, const char* src, SizeT len); \
969 char* VG_REPLACE_FUNCTION_EZU(2028,soname,fnname) \
970 (char* dst, const char* src, SizeT len) \
sewardjb8d03852007-01-27 00:49:44 +0000971 { \
sewardjdc5d8322007-01-28 06:32:01 +0000972 if (! len) \
973 goto badness; \
974 while ((*dst++ = *src++) != '\0') \
975 if (--len == 0) \
sewardjb8d03852007-01-27 00:49:44 +0000976 goto badness; \
sewardjb8d03852007-01-27 00:49:44 +0000977 return dst - 1; \
978 badness: \
979 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +0000980 "*** stpcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000981 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +0000982 my_exit(127); \
sewardjb8d03852007-01-27 00:49:44 +0000983 /*NOTREACHED*/ \
984 return NULL; \
985 }
986
njne6154662009-02-10 04:23:41 +0000987GLIBC25___STPCPY_CHK(VG_Z_LIBC_SONAME, __stpcpy_chk)
sewardjb8d03852007-01-27 00:49:44 +0000988
989
sewardj841b72d2006-12-31 18:55:56 +0000990/* mempcpy */
991#define GLIBC25_MEMPCPY(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000992 void* VG_REPLACE_FUNCTION_EZU(2029,soname,fnname) \
sewardj841b72d2006-12-31 18:55:56 +0000993 ( void *dst, const void *src, SizeT len ); \
sewardjbd2cff22011-08-16 21:45:28 +0000994 void* VG_REPLACE_FUNCTION_EZU(2029,soname,fnname) \
sewardj841b72d2006-12-31 18:55:56 +0000995 ( void *dst, const void *src, SizeT len ) \
996 { \
997 register char *d; \
998 register char *s; \
999 SizeT len_saved = len; \
1000 \
1001 if (len == 0) \
1002 return dst; \
1003 \
1004 if (is_overlap(dst, src, len, len)) \
1005 RECORD_OVERLAP_ERROR("mempcpy", dst, src, len); \
1006 \
1007 if ( dst > src ) { \
1008 d = (char *)dst + len - 1; \
1009 s = (char *)src + len - 1; \
1010 while ( len-- ) { \
1011 *d-- = *s--; \
1012 } \
1013 } else if ( dst < src ) { \
1014 d = (char *)dst; \
1015 s = (char *)src; \
1016 while ( len-- ) { \
1017 *d++ = *s++; \
1018 } \
1019 } \
1020 return (void*)( ((char*)dst) + len_saved ); \
1021 }
1022
njne6154662009-02-10 04:23:41 +00001023GLIBC25_MEMPCPY(VG_Z_LIBC_SONAME, mempcpy)
njnb4cfbc42009-05-04 04:20:02 +00001024#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +00001025GLIBC25_MEMPCPY(VG_Z_LD_SO_1, mempcpy) /* ld.so.1 */
njnb4cfbc42009-05-04 04:20:02 +00001026#endif
sewardj841b72d2006-12-31 18:55:56 +00001027
1028
sewardjb6c04032007-11-13 20:52:29 +00001029#define GLIBC26___MEMCPY_CHK(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001030 void* VG_REPLACE_FUNCTION_EZU(2030,soname,fnname) \
sewardjb6c04032007-11-13 20:52:29 +00001031 (void* dst, const void* src, SizeT len, SizeT dstlen ); \
sewardjbd2cff22011-08-16 21:45:28 +00001032 void* VG_REPLACE_FUNCTION_EZU(2030,soname,fnname) \
sewardjb6c04032007-11-13 20:52:29 +00001033 (void* dst, const void* src, SizeT len, SizeT dstlen ) \
1034 { \
sewardjb6c04032007-11-13 20:52:29 +00001035 register char *d; \
1036 register char *s; \
1037 \
1038 if (dstlen < len) goto badness; \
1039 \
1040 if (len == 0) \
1041 return dst; \
1042 \
1043 if (is_overlap(dst, src, len, len)) \
1044 RECORD_OVERLAP_ERROR("memcpy_chk", dst, src, len); \
1045 \
1046 if ( dst > src ) { \
1047 d = (char *)dst + len - 1; \
1048 s = (char *)src + len - 1; \
1049 while ( len-- ) { \
1050 *d-- = *s--; \
1051 } \
1052 } else if ( dst < src ) { \
1053 d = (char *)dst; \
1054 s = (char *)src; \
1055 while ( len-- ) { \
1056 *d++ = *s++; \
1057 } \
1058 } \
1059 return dst; \
1060 badness: \
1061 VALGRIND_PRINTF_BACKTRACE( \
1062 "*** memcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +00001063 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +00001064 my_exit(127); \
sewardjb6c04032007-11-13 20:52:29 +00001065 /*NOTREACHED*/ \
1066 return NULL; \
1067 }
1068
njne6154662009-02-10 04:23:41 +00001069GLIBC26___MEMCPY_CHK(VG_Z_LIBC_SONAME, __memcpy_chk)
sewardjb6c04032007-11-13 20:52:29 +00001070
1071
sewardja77687c2010-08-19 13:22:34 +00001072#define STRSTR(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001073 void* VG_REPLACE_FUNCTION_EZU(2031,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001074 (void* haystack, void* needle); \
sewardjbd2cff22011-08-16 21:45:28 +00001075 void* VG_REPLACE_FUNCTION_EZU(2031,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001076 (void* haystack, void* needle) \
1077 { \
1078 UChar* h = (UChar*)haystack; \
1079 UChar* n = (UChar*)needle; \
1080 \
1081 /* find the length of n, not including terminating zero */ \
1082 UWord nlen = 0; \
1083 while (n[nlen]) nlen++; \
1084 \
1085 /* if n is the empty string, match immediately. */ \
1086 if (nlen == 0) return h; \
1087 \
1088 /* assert(nlen >= 1); */ \
1089 UChar n0 = n[0]; \
1090 \
1091 while (1) { \
1092 UChar hh = *h; \
1093 if (hh == 0) return NULL; \
1094 if (hh != n0) { h++; continue; } \
1095 \
1096 UWord i; \
1097 for (i = 0; i < nlen; i++) { \
1098 if (n[i] != h[i]) \
1099 break; \
1100 } \
1101 /* assert(i >= 0 && i <= nlen); */ \
1102 if (i == nlen) \
1103 return h; \
1104 \
1105 h++; \
1106 } \
1107 }
1108
1109#if defined(VGO_linux)
1110STRSTR(VG_Z_LIBC_SONAME, strstr)
1111#endif
1112
1113
1114#define STRPBRK(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001115 void* VG_REPLACE_FUNCTION_EZU(2032,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001116 (void* sV, void* acceptV); \
sewardjbd2cff22011-08-16 21:45:28 +00001117 void* VG_REPLACE_FUNCTION_EZU(2032,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001118 (void* sV, void* acceptV) \
1119 { \
1120 UChar* s = (UChar*)sV; \
1121 UChar* accept = (UChar*)acceptV; \
1122 \
1123 /* find the length of 'accept', not including terminating zero */ \
1124 UWord nacc = 0; \
1125 while (accept[nacc]) nacc++; \
1126 \
1127 /* if n is the empty string, fail immediately. */ \
1128 if (nacc == 0) return NULL; \
1129 \
1130 /* assert(nacc >= 1); */ \
1131 while (1) { \
1132 UWord i; \
1133 UChar sc = *s; \
1134 if (sc == 0) \
1135 break; \
1136 for (i = 0; i < nacc; i++) { \
1137 if (sc == accept[i]) \
1138 return s; \
1139 } \
1140 s++; \
1141 } \
1142 \
1143 return NULL; \
1144 }
1145
1146#if defined(VGO_linux)
1147STRPBRK(VG_Z_LIBC_SONAME, strpbrk)
1148#endif
1149
1150
1151#define STRCSPN(soname, fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001152 SizeT VG_REPLACE_FUNCTION_EZU(2033,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001153 (void* sV, void* rejectV); \
sewardjbd2cff22011-08-16 21:45:28 +00001154 SizeT VG_REPLACE_FUNCTION_EZU(2033,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001155 (void* sV, void* rejectV) \
1156 { \
1157 UChar* s = (UChar*)sV; \
1158 UChar* reject = (UChar*)rejectV; \
1159 \
1160 /* find the length of 'reject', not including terminating zero */ \
1161 UWord nrej = 0; \
1162 while (reject[nrej]) nrej++; \
1163 \
1164 UWord len = 0; \
1165 while (1) { \
1166 UWord i; \
1167 UChar sc = *s; \
1168 if (sc == 0) \
1169 break; \
1170 for (i = 0; i < nrej; i++) { \
1171 if (sc == reject[i]) \
1172 break; \
1173 } \
1174 /* assert(i >= 0 && i <= nrej); */ \
1175 if (i < nrej) \
1176 break; \
1177 s++; \
1178 len++; \
1179 } \
1180 \
1181 return len; \
1182 }
1183
1184#if defined(VGO_linux)
1185STRCSPN(VG_Z_LIBC_SONAME, strcspn)
1186#endif
1187
1188
sewardjbd2cff22011-08-16 21:45:28 +00001189#define STRSPN(soname, fnname) \
1190 SizeT VG_REPLACE_FUNCTION_EZU(2034,soname,fnname) \
1191 (void* sV, void* acceptV); \
1192 SizeT VG_REPLACE_FUNCTION_EZU(2034,soname,fnname) \
1193 (void* sV, void* acceptV) \
1194 { \
1195 UChar* s = (UChar*)sV; \
1196 UChar* accept = (UChar*)acceptV; \
1197 \
1198 /* find the length of 'accept', not including terminating zero */ \
1199 UWord nacc = 0; \
1200 while (accept[nacc]) nacc++; \
1201 if (nacc == 0) return 0; \
1202 \
1203 UWord len = 0; \
1204 while (1) { \
1205 UWord i; \
1206 UChar sc = *s; \
1207 if (sc == 0) \
1208 break; \
1209 for (i = 0; i < nacc; i++) { \
1210 if (sc == accept[i]) \
1211 break; \
1212 } \
1213 /* assert(i >= 0 && i <= nacc); */ \
1214 if (i == nacc) \
1215 break; \
1216 s++; \
1217 len++; \
1218 } \
1219 \
1220 return len; \
1221 }
1222
1223#if defined(VGO_linux)
1224STRSPN(VG_Z_LIBC_SONAME, strspn)
1225#endif
sewardjba189352010-08-20 18:24:16 +00001226
1227
sewardj31b9ce12006-10-17 01:27:13 +00001228/*------------------------------------------------------------*/
dirk09beb9e2007-04-19 09:47:32 +00001229/*--- Improve definedness checking of process environment ---*/
1230/*------------------------------------------------------------*/
1231
sewardjddc00dd2007-11-27 11:42:47 +00001232#if defined(VGO_linux)
1233
sewardjbd2cff22011-08-16 21:45:28 +00001234/* If these wind up getting generated via a macro, so that multiple
1235 versions of each function exist (as above), use the _EZU variants
1236 to assign equivalance class tags. */
1237
dirk09beb9e2007-04-19 09:47:32 +00001238/* putenv */
njne6154662009-02-10 04:23:41 +00001239int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string);
1240int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string)
dirk09beb9e2007-04-19 09:47:32 +00001241{
1242 OrigFn fn;
1243 Word result;
1244 const char* p = string;
1245 VALGRIND_GET_ORIG_FN(fn);
1246 /* Now by walking over the string we magically produce
1247 traces when hitting undefined memory. */
1248 if (p)
1249 while (*p++)
1250 ;
1251 CALL_FN_W_W(result, fn, string);
1252 return result;
1253}
1254
1255/* unsetenv */
njne6154662009-02-10 04:23:41 +00001256int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name);
1257int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name)
dirk09beb9e2007-04-19 09:47:32 +00001258{
1259 OrigFn fn;
1260 Word result;
1261 const char* p = name;
1262 VALGRIND_GET_ORIG_FN(fn);
1263 /* Now by walking over the string we magically produce
1264 traces when hitting undefined memory. */
1265 if (p)
1266 while (*p++)
1267 ;
1268 CALL_FN_W_W(result, fn, name);
1269 return result;
1270}
1271
1272/* setenv */
njne6154662009-02-10 04:23:41 +00001273int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001274 (const char* name, const char* value, int overwrite);
njne6154662009-02-10 04:23:41 +00001275int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001276 (const char* name, const char* value, int overwrite)
1277{
1278 OrigFn fn;
1279 Word result;
1280 const char* p;
1281 VALGRIND_GET_ORIG_FN(fn);
1282 /* Now by walking over the string we magically produce
1283 traces when hitting undefined memory. */
1284 if (name)
1285 for (p = name; *p; p++)
1286 ;
1287 if (value)
1288 for (p = value; *p; p++)
1289 ;
1290 VALGRIND_CHECK_VALUE_IS_DEFINED (overwrite);
1291 CALL_FN_W_WWW(result, fn, name, value, overwrite);
1292 return result;
1293}
1294
sewardjddc00dd2007-11-27 11:42:47 +00001295#endif /* defined(VGO_linux) */
1296
njn3e884182003-04-15 13:03:23 +00001297/*--------------------------------------------------------------------*/
njn46275862005-03-24 04:00:03 +00001298/*--- end ---*/
njn3e884182003-04-15 13:03:23 +00001299/*--------------------------------------------------------------------*/