blob: d29dc5979169ff35941c3f673190f328a72ac310 [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
sewardjec062e82011-10-23 07:32:08 +000012 Copyright (C) 2000-2011 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
sewardj96044842011-08-18 13:09:55 +000056/* Assignment of behavioural equivalence class tags: 2NNNP is intended
sewardjbd2cff22011-08-16 21:45:28 +000057 to be reserved for Memcheck. Current usage:
58
sewardj96044842011-08-18 13:09:55 +000059 20010 STRRCHR
60 20020 STRCHR
61 20030 STRCAT
62 20040 STRNCAT
63 20050 STRLCAT
64 20060 STRNLEN
65 20070 STRLEN
66 20080 STRCPY
67 20090 STRNCPY
68 20100 STRLCPY
69 20110 STRNCMP
70 20120 STRCASECMP
71 20130 STRNCASECMP
72 20140 STRCASECMP_L
73 20150 STRNCASECMP_L
74 20160 STRCMP
75 20170 MEMCHR
76
77 20180 MEMCPY if there's a conflict between memcpy and
78 20181 MEMMOVE memmove, prefer memmove
79
80 20190 MEMCMP
81 20200 STPCPY
82 20210 MEMSET
83 2022P unused (was previously MEMMOVE)
84 20230 BCOPY
85 20240 GLIBC25___MEMMOVE_CHK
86 20250 GLIBC232_STRCHRNUL
87 20260 GLIBC232_RAWMEMCHR
88 20270 GLIBC25___STRCPY_CHK
89 20280 GLIBC25___STPCPY_CHK
90 20290 GLIBC25_MEMPCPY
91 20300 GLIBC26___MEMCPY_CHK
92 20310 STRSTR
93 20320 STRPBRK
94 20330 STRCSPN
95 20340 STRSPN
sewardj284f2a32011-10-21 08:07:13 +000096 20350 STRCASESTR
sewardjbd2cff22011-08-16 21:45:28 +000097*/
98
sewardj126e82d2011-07-12 13:33:00 +000099
sewardjdda830a2003-07-20 22:28:42 +0000100/* Figure out if [dst .. dst+dstlen-1] overlaps with
101 [src .. src+srclen-1].
102 We assume that the address ranges do not wrap around
103 (which is safe since on Linux addresses >= 0xC0000000
104 are not accessible and the program will segfault in this
105 circumstance, presumably).
106*/
sewardj126e82d2011-07-12 13:33:00 +0000107static inline
njnc6168192004-11-29 13:54:10 +0000108Bool is_overlap ( void* dst, const void* src, SizeT dstlen, SizeT srclen )
njn3e884182003-04-15 13:03:23 +0000109{
sewardjdda830a2003-07-20 22:28:42 +0000110 Addr loS, hiS, loD, hiD;
111
112 if (dstlen == 0 || srclen == 0)
113 return False;
114
115 loS = (Addr)src;
116 loD = (Addr)dst;
117 hiS = loS + srclen - 1;
118 hiD = loD + dstlen - 1;
119
120 /* So figure out if [loS .. hiS] overlaps with [loD .. hiD]. */
121 if (loS < loD) {
122 return !(hiS < loD);
123 }
124 else if (loD < loS) {
125 return !(hiD < loS);
126 }
127 else {
128 /* They start at same place. Since we know neither of them has
129 zero length, they must overlap. */
130 return True;
131 }
njn3e884182003-04-15 13:03:23 +0000132}
133
sewardj126e82d2011-07-12 13:33:00 +0000134
135/* Call here to exit if we can't continue. On Android we can't call
136 _exit for some reason, so we have to blunt-instrument it. */
137__attribute__ ((__noreturn__))
138static inline void my_exit ( int x )
139{
140# if defined(VGPV_arm_linux_android)
141 __asm__ __volatile__(".word 0xFFFFFFFF");
142 while (1) {}
143# else
florian28936a82011-10-05 14:36:00 +0000144 extern __attribute__ ((__noreturn__)) void _exit(int status);
sewardj49665422011-07-12 13:50:59 +0000145 _exit(x);
sewardj126e82d2011-07-12 13:33:00 +0000146# endif
147}
148
149
njn1f8b3e72005-03-22 04:27:14 +0000150// This is a macro rather than a function because we don't want to have an
151// extra function in the stack trace.
bart575ce8e2011-05-15 07:04:03 +0000152#define RECORD_OVERLAP_ERROR(s, src, dst, len) \
sewardj4b3a7422011-10-24 13:21:57 +0000153 VALGRIND_DO_CLIENT_REQUEST_STMT( \
bart575ce8e2011-05-15 07:04:03 +0000154 _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR, \
155 s, src, dst, len, 0)
njn3e884182003-04-15 13:03:23 +0000156
njn16eeb4e2005-06-16 03:56:58 +0000157
sewardj3c944452011-09-05 20:39:57 +0000158/*---------------------- strrchr ----------------------*/
159
njn16eeb4e2005-06-16 03:56:58 +0000160#define STRRCHR(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000161 char* VG_REPLACE_FUNCTION_EZU(20010,soname,fnname)( const char* s, int c ); \
162 char* VG_REPLACE_FUNCTION_EZU(20010,soname,fnname)( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000163 { \
164 UChar ch = (UChar)((UInt)c); \
165 UChar* p = (UChar*)s; \
166 UChar* last = NULL; \
167 while (True) { \
168 if (*p == ch) last = p; \
169 if (*p == 0) return last; \
170 p++; \
171 } \
njn3e884182003-04-15 13:03:23 +0000172 }
njn3e884182003-04-15 13:03:23 +0000173
njn16eeb4e2005-06-16 03:56:58 +0000174// Apparently rindex() is the same thing as strrchr()
njnb4cfbc42009-05-04 04:20:02 +0000175#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000176 STRRCHR(VG_Z_LIBC_SONAME, strrchr)
177 STRRCHR(VG_Z_LIBC_SONAME, rindex)
178 STRRCHR(VG_Z_LIBC_SONAME, __GI_strrchr)
179 STRRCHR(VG_Z_LD_LINUX_SO_2, rindex)
sewardj4157d4f2011-09-05 22:18:13 +0000180
njnf76d27a2009-05-28 01:53:07 +0000181#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000182 //STRRCHR(VG_Z_LIBC_SONAME, strrchr)
183 //STRRCHR(VG_Z_LIBC_SONAME, rindex)
184 //STRRCHR(VG_Z_DYLD, strrchr)
185 //STRRCHR(VG_Z_DYLD, rindex)
186 STRRCHR(VG_Z_LIBC_SONAME, strrchr)
sewardj4157d4f2011-09-05 22:18:13 +0000187
njnb4cfbc42009-05-04 04:20:02 +0000188#endif
njn16eeb4e2005-06-16 03:56:58 +0000189
190
sewardj3c944452011-09-05 20:39:57 +0000191/*---------------------- strchr ----------------------*/
192
njn16eeb4e2005-06-16 03:56:58 +0000193#define STRCHR(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000194 char* VG_REPLACE_FUNCTION_EZU(20020,soname,fnname) ( const char* s, int c ); \
195 char* VG_REPLACE_FUNCTION_EZU(20020,soname,fnname) ( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000196 { \
197 UChar ch = (UChar)((UInt)c); \
198 UChar* p = (UChar*)s; \
199 while (True) { \
200 if (*p == ch) return p; \
201 if (*p == 0) return NULL; \
202 p++; \
203 } \
njn3e884182003-04-15 13:03:23 +0000204 }
njn3e884182003-04-15 13:03:23 +0000205
njn16eeb4e2005-06-16 03:56:58 +0000206// Apparently index() is the same thing as strchr()
njnb4cfbc42009-05-04 04:20:02 +0000207#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000208 STRCHR(VG_Z_LIBC_SONAME, strchr)
209 STRCHR(VG_Z_LIBC_SONAME, index)
210 STRCHR(VG_Z_LIBC_SONAME, __GI_strchr)
211# if !defined(VGP_x86_linux)
212 STRCHR(VG_Z_LD_LINUX_SO_2, strchr)
213 STRCHR(VG_Z_LD_LINUX_SO_2, index)
214 STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr)
215 STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index)
216# endif
sewardj4157d4f2011-09-05 22:18:13 +0000217
njnf76d27a2009-05-28 01:53:07 +0000218#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000219 //STRCHR(VG_Z_LIBC_SONAME, strchr)
220 //STRCHR(VG_Z_LIBC_SONAME, index)
221 //STRCHR(VG_Z_DYLD, strchr)
222 //STRCHR(VG_Z_DYLD, index)
223 STRCHR(VG_Z_LIBC_SONAME, strchr)
sewardj4157d4f2011-09-05 22:18:13 +0000224
njnb4cfbc42009-05-04 04:20:02 +0000225#endif
njn3e884182003-04-15 13:03:23 +0000226
njn3e884182003-04-15 13:03:23 +0000227
sewardj3c944452011-09-05 20:39:57 +0000228/*---------------------- strcat ----------------------*/
229
njn16eeb4e2005-06-16 03:56:58 +0000230#define STRCAT(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000231 char* VG_REPLACE_FUNCTION_EZU(20030,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000232 ( char* dst, const char* src ); \
sewardj96044842011-08-18 13:09:55 +0000233 char* VG_REPLACE_FUNCTION_EZU(20030,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000234 ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000235 { \
236 const Char* src_orig = src; \
237 Char* dst_orig = dst; \
238 while (*dst) dst++; \
239 while (*src) *dst++ = *src++; \
240 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000241 \
njn16eeb4e2005-06-16 03:56:58 +0000242 /* This is a bit redundant, I think; any overlap and the strcat will */ \
243 /* go forever... or until a seg fault occurs. */ \
244 if (is_overlap(dst_orig, \
245 src_orig, \
246 (Addr)dst-(Addr)dst_orig+1, \
247 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000248 RECORD_OVERLAP_ERROR("strcat", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000249 \
njn16eeb4e2005-06-16 03:56:58 +0000250 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000251 }
njn3e884182003-04-15 13:03:23 +0000252
tomd2645142009-10-29 09:27:11 +0000253#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000254 STRCAT(VG_Z_LIBC_SONAME, strcat)
255 STRCAT(VG_Z_LIBC_SONAME, __GI_strcat)
sewardj4157d4f2011-09-05 22:18:13 +0000256
sewardj3c944452011-09-05 20:39:57 +0000257#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000258 //STRCAT(VG_Z_LIBC_SONAME, strcat)
sewardj4157d4f2011-09-05 22:18:13 +0000259
tomd2645142009-10-29 09:27:11 +0000260#endif
njn16eeb4e2005-06-16 03:56:58 +0000261
sewardj3c944452011-09-05 20:39:57 +0000262
263/*---------------------- strncat ----------------------*/
264
njn16eeb4e2005-06-16 03:56:58 +0000265#define STRNCAT(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000266 char* VG_REPLACE_FUNCTION_EZU(20040,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000267 ( char* dst, const char* src, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000268 char* VG_REPLACE_FUNCTION_EZU(20040,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000269 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000270 { \
271 const Char* src_orig = src; \
272 Char* dst_orig = dst; \
273 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000274 \
njn16eeb4e2005-06-16 03:56:58 +0000275 while (*dst) dst++; \
276 while (m < n && *src) { m++; *dst++ = *src++; } /* concat <= n chars */ \
277 *dst = 0; /* always add null */ \
sewardjb6c04032007-11-13 20:52:29 +0000278 \
njn16eeb4e2005-06-16 03:56:58 +0000279 /* This checks for overlap after copying, unavoidable without */ \
280 /* pre-counting lengths... should be ok */ \
281 if (is_overlap(dst_orig, \
282 src_orig, \
sewardjbd2cff22011-08-16 21:45:28 +0000283 (Addr)dst-(Addr)dst_orig+1, \
njn16eeb4e2005-06-16 03:56:58 +0000284 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000285 RECORD_OVERLAP_ERROR("strncat", dst_orig, src_orig, n); \
sewardjb6c04032007-11-13 20:52:29 +0000286 \
njn16eeb4e2005-06-16 03:56:58 +0000287 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000288 }
njn3e884182003-04-15 13:03:23 +0000289
sewardj3c944452011-09-05 20:39:57 +0000290#if defined(VGO_linux)
291 STRNCAT(VG_Z_LIBC_SONAME, strncat)
sewardj4157d4f2011-09-05 22:18:13 +0000292
sewardj3c944452011-09-05 20:39:57 +0000293#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000294 //STRNCAT(VG_Z_LIBC_SONAME, strncat)
295 //STRNCAT(VG_Z_DYLD, strncat)
sewardj4157d4f2011-09-05 22:18:13 +0000296
njnf76d27a2009-05-28 01:53:07 +0000297#endif
298
299
sewardj3c944452011-09-05 20:39:57 +0000300/*---------------------- strlcat ----------------------*/
301
njnf76d27a2009-05-28 01:53:07 +0000302/* Append src to dst. n is the size of dst's buffer. dst is guaranteed
303 to be nul-terminated after the copy, unless n <= strlen(dst_orig).
304 Returns min(n, strlen(dst_orig)) + strlen(src_orig).
305 Truncation occurred if retval >= n.
306*/
307#define STRLCAT(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000308 SizeT VG_REPLACE_FUNCTION_EZU(20050,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000309 ( char* dst, const char* src, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000310 SizeT VG_REPLACE_FUNCTION_EZU(20050,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000311 ( char* dst, const char* src, SizeT n ) \
312 { \
313 const Char* src_orig = src; \
314 Char* dst_orig = dst; \
315 SizeT m = 0; \
sewardjbd2cff22011-08-16 21:45:28 +0000316 \
njnf76d27a2009-05-28 01:53:07 +0000317 while (m < n && *dst) { m++; dst++; } \
318 if (m < n) { \
319 /* Fill as far as dst_orig[n-2], then nul-terminate. */ \
320 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
321 *dst = 0; \
322 } else { \
323 /* No space to copy anything to dst. m == n */ \
324 } \
325 /* Finish counting min(n, strlen(dst_orig)) + strlen(src_orig) */ \
326 while (*src) { m++; src++; } \
327 /* This checks for overlap after copying, unavoidable without */ \
328 /* pre-counting lengths... should be ok */ \
329 if (is_overlap(dst_orig, \
330 src_orig, \
331 (Addr)dst-(Addr)dst_orig+1, \
332 (Addr)src-(Addr)src_orig+1)) \
333 RECORD_OVERLAP_ERROR("strlcat", dst_orig, src_orig, n); \
sewardjbd2cff22011-08-16 21:45:28 +0000334 \
njnf76d27a2009-05-28 01:53:07 +0000335 return m; \
336 }
337
sewardj3c944452011-09-05 20:39:57 +0000338#if defined(VGO_linux)
sewardj4157d4f2011-09-05 22:18:13 +0000339
sewardj3c944452011-09-05 20:39:57 +0000340#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000341 //STRLCAT(VG_Z_LIBC_SONAME, strlcat)
342 //STRLCAT(VG_Z_DYLD, strlcat)
sewardj3c944452011-09-05 20:39:57 +0000343 STRLCAT(VG_Z_LIBC_SONAME, strlcat)
sewardj4157d4f2011-09-05 22:18:13 +0000344
njnf76d27a2009-05-28 01:53:07 +0000345#endif
sewardj31b9ce12006-10-17 01:27:13 +0000346
njn3e884182003-04-15 13:03:23 +0000347
sewardj3c944452011-09-05 20:39:57 +0000348/*---------------------- strnlen ----------------------*/
349
njn16eeb4e2005-06-16 03:56:58 +0000350#define STRNLEN(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000351 SizeT VG_REPLACE_FUNCTION_EZU(20060,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000352 ( const char* str, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000353 SizeT VG_REPLACE_FUNCTION_EZU(20060,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000354 ( const char* str, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000355 { \
356 SizeT i = 0; \
357 while (i < n && str[i] != 0) i++; \
358 return i; \
njn3e884182003-04-15 13:03:23 +0000359 }
njn3e884182003-04-15 13:03:23 +0000360
tomd2645142009-10-29 09:27:11 +0000361#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000362 STRNLEN(VG_Z_LIBC_SONAME, strnlen)
363 STRNLEN(VG_Z_LIBC_SONAME, __GI_strnlen)
sewardj4157d4f2011-09-05 22:18:13 +0000364
sewardj3c944452011-09-05 20:39:57 +0000365#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000366 //STRNLEN(VG_Z_LIBC_SONAME, strnlen)
sewardj4157d4f2011-09-05 22:18:13 +0000367
tomd2645142009-10-29 09:27:11 +0000368#endif
njn16eeb4e2005-06-16 03:56:58 +0000369
sewardj3ceec242003-07-30 21:24:25 +0000370
sewardj3c944452011-09-05 20:39:57 +0000371/*---------------------- strlen ----------------------*/
372
njn5ec15ed2005-08-24 19:55:51 +0000373// Note that this replacement often doesn't get used because gcc inlines
374// calls to strlen() with its own built-in version. This can be very
sewardj3c944452011-09-05 20:39:57 +0000375// confusing if you aren't expecting it. Other small functions in
376// this file may also be inline by gcc.
377
njn16eeb4e2005-06-16 03:56:58 +0000378#define STRLEN(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000379 SizeT VG_REPLACE_FUNCTION_EZU(20070,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000380 ( const char* str ); \
sewardj96044842011-08-18 13:09:55 +0000381 SizeT VG_REPLACE_FUNCTION_EZU(20070,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000382 ( const char* str ) \
njn16eeb4e2005-06-16 03:56:58 +0000383 { \
384 SizeT i = 0; \
385 while (str[i] != 0) i++; \
386 return i; \
sewardj3ceec242003-07-30 21:24:25 +0000387 }
njn16eeb4e2005-06-16 03:56:58 +0000388
njnb4cfbc42009-05-04 04:20:02 +0000389#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000390 STRLEN(VG_Z_LIBC_SONAME, strlen)
391 STRLEN(VG_Z_LIBC_SONAME, __GI_strlen)
sewardj70f291d2011-09-26 20:20:19 +0000392# if defined(VGPV_arm_linux_android)
393 STRLEN(NONE, __dl_strlen); /* in /system/bin/linker */
394# endif
sewardj4157d4f2011-09-05 22:18:13 +0000395
sewardj3c944452011-09-05 20:39:57 +0000396#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000397 //STRLEN(VG_Z_LIBC_SONAME, strlen)
398 STRLEN(VG_Z_LIBC_SONAME, strlen)
sewardj4157d4f2011-09-05 22:18:13 +0000399
njnb4cfbc42009-05-04 04:20:02 +0000400#endif
sewardj31b9ce12006-10-17 01:27:13 +0000401
njn16eeb4e2005-06-16 03:56:58 +0000402
sewardj3c944452011-09-05 20:39:57 +0000403/*---------------------- strcpy ----------------------*/
404
njn16eeb4e2005-06-16 03:56:58 +0000405#define STRCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000406 char* VG_REPLACE_FUNCTION_EZU(20080,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000407 ( char* dst, const char* src ); \
sewardj96044842011-08-18 13:09:55 +0000408 char* VG_REPLACE_FUNCTION_EZU(20080,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000409 ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000410 { \
411 const Char* src_orig = src; \
412 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000413 \
njn16eeb4e2005-06-16 03:56:58 +0000414 while (*src) *dst++ = *src++; \
415 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000416 \
njn16eeb4e2005-06-16 03:56:58 +0000417 /* This checks for overlap after copying, unavoidable without */ \
418 /* pre-counting length... should be ok */ \
419 if (is_overlap(dst_orig, \
420 src_orig, \
sewardjbd2cff22011-08-16 21:45:28 +0000421 (Addr)dst-(Addr)dst_orig+1, \
njn16eeb4e2005-06-16 03:56:58 +0000422 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000423 RECORD_OVERLAP_ERROR("strcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000424 \
njn16eeb4e2005-06-16 03:56:58 +0000425 return dst_orig; \
426 }
427
tomd2645142009-10-29 09:27:11 +0000428#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000429 STRCPY(VG_Z_LIBC_SONAME, strcpy)
430 STRCPY(VG_Z_LIBC_SONAME, __GI_strcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000431
tomd2645142009-10-29 09:27:11 +0000432#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000433 //STRCPY(VG_Z_LIBC_SONAME, strcpy)
434 //STRCPY(VG_Z_DYLD, strcpy)
sewardj3c944452011-09-05 20:39:57 +0000435 STRCPY(VG_Z_LIBC_SONAME, strcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000436
njnf76d27a2009-05-28 01:53:07 +0000437#endif
njn16eeb4e2005-06-16 03:56:58 +0000438
439
sewardj3c944452011-09-05 20:39:57 +0000440/*---------------------- strncpy ----------------------*/
441
njn16eeb4e2005-06-16 03:56:58 +0000442#define STRNCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000443 char* VG_REPLACE_FUNCTION_EZU(20090,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000444 ( char* dst, const char* src, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000445 char* VG_REPLACE_FUNCTION_EZU(20090,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000446 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000447 { \
448 const Char* src_orig = src; \
449 Char* dst_orig = dst; \
450 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000451 \
njn16eeb4e2005-06-16 03:56:58 +0000452 while (m < n && *src) { m++; *dst++ = *src++; } \
453 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
454 /* but only m+1 bytes of src if terminator was found */ \
455 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
njn718d3b12006-12-16 00:54:12 +0000456 RECORD_OVERLAP_ERROR("strncpy", dst, src, n); \
njn16eeb4e2005-06-16 03:56:58 +0000457 while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */ \
sewardj3c944452011-09-05 20:39:57 +0000458 \
njn16eeb4e2005-06-16 03:56:58 +0000459 return dst_orig; \
460 }
461
tomd2645142009-10-29 09:27:11 +0000462#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000463 STRNCPY(VG_Z_LIBC_SONAME, strncpy)
464 STRNCPY(VG_Z_LIBC_SONAME, __GI_strncpy)
sewardj4157d4f2011-09-05 22:18:13 +0000465
tomd2645142009-10-29 09:27:11 +0000466#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000467 //STRNCPY(VG_Z_LIBC_SONAME, strncpy)
468 //STRNCPY(VG_Z_DYLD, strncpy)
sewardj3c944452011-09-05 20:39:57 +0000469 STRNCPY(VG_Z_LIBC_SONAME, strncpy)
sewardj4157d4f2011-09-05 22:18:13 +0000470
njnf76d27a2009-05-28 01:53:07 +0000471#endif
472
473
sewardj3c944452011-09-05 20:39:57 +0000474/*---------------------- strlcpy ----------------------*/
475
njnf76d27a2009-05-28 01:53:07 +0000476/* Copy up to n-1 bytes from src to dst. Then nul-terminate dst if n > 0.
477 Returns strlen(src). Does not zero-fill the remainder of dst. */
478#define STRLCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000479 SizeT VG_REPLACE_FUNCTION_EZU(20100,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000480 ( char* dst, const char* src, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000481 SizeT VG_REPLACE_FUNCTION_EZU(20100,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000482 ( char* dst, const char* src, SizeT n ) \
483 { \
484 const char* src_orig = src; \
485 char* dst_orig = dst; \
486 SizeT m = 0; \
sewardjbd2cff22011-08-16 21:45:28 +0000487 \
njnf76d27a2009-05-28 01:53:07 +0000488 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
489 /* m non-nul bytes have now been copied, and m <= n-1. */ \
490 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
491 /* but only m+1 bytes of src if terminator was found */ \
492 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
493 RECORD_OVERLAP_ERROR("strlcpy", dst, src, n); \
494 /* Nul-terminate dst. */ \
495 if (n > 0) *dst = 0; \
496 /* Finish counting strlen(src). */ \
497 while (*src) src++; \
498 return src - src_orig; \
499 }
500
sewardj3c944452011-09-05 20:39:57 +0000501#if defined(VGO_linux)
sewardj4157d4f2011-09-05 22:18:13 +0000502
sewardj3c944452011-09-05 20:39:57 +0000503#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000504 //STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
505 //STRLCPY(VG_Z_DYLD, strlcpy)
sewardj3c944452011-09-05 20:39:57 +0000506 STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000507
njnf76d27a2009-05-28 01:53:07 +0000508#endif
njn16eeb4e2005-06-16 03:56:58 +0000509
510
sewardj3c944452011-09-05 20:39:57 +0000511/*---------------------- strncmp ----------------------*/
512
njn16eeb4e2005-06-16 03:56:58 +0000513#define STRNCMP(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000514 int VG_REPLACE_FUNCTION_EZU(20110,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000515 ( const char* s1, const char* s2, SizeT nmax ); \
sewardj96044842011-08-18 13:09:55 +0000516 int VG_REPLACE_FUNCTION_EZU(20110,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000517 ( const char* s1, const char* s2, SizeT nmax ) \
njn16eeb4e2005-06-16 03:56:58 +0000518 { \
519 SizeT n = 0; \
520 while (True) { \
521 if (n >= nmax) return 0; \
522 if (*s1 == 0 && *s2 == 0) return 0; \
523 if (*s1 == 0) return -1; \
524 if (*s2 == 0) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000525 \
njn16eeb4e2005-06-16 03:56:58 +0000526 if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1; \
527 if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000528 \
njn16eeb4e2005-06-16 03:56:58 +0000529 s1++; s2++; n++; \
530 } \
531 }
532
tomd2645142009-10-29 09:27:11 +0000533#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000534 STRNCMP(VG_Z_LIBC_SONAME, strncmp)
535 STRNCMP(VG_Z_LIBC_SONAME, __GI_strncmp)
sewardj4157d4f2011-09-05 22:18:13 +0000536
tomd2645142009-10-29 09:27:11 +0000537#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000538 //STRNCMP(VG_Z_LIBC_SONAME, strncmp)
539 //STRNCMP(VG_Z_DYLD, strncmp)
540 STRNCMP(VG_Z_LIBC_SONAME, strncmp)
sewardj4157d4f2011-09-05 22:18:13 +0000541
njnf76d27a2009-05-28 01:53:07 +0000542#endif
njn16eeb4e2005-06-16 03:56:58 +0000543
544
sewardj3c944452011-09-05 20:39:57 +0000545/*---------------------- strcasecmp ----------------------*/
546
tomce6d0ac2010-11-12 10:03:13 +0000547#define STRCASECMP(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000548 int VG_REPLACE_FUNCTION_EZU(20120,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000549 ( const char* s1, const char* s2 ); \
sewardj96044842011-08-18 13:09:55 +0000550 int VG_REPLACE_FUNCTION_EZU(20120,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000551 ( const char* s1, const char* s2 ) \
552 { \
tome03c8c42010-11-12 10:40:20 +0000553 extern int tolower(int); \
tomce6d0ac2010-11-12 10:03:13 +0000554 register unsigned char c1; \
555 register unsigned char c2; \
556 while (True) { \
557 c1 = tolower(*(unsigned char *)s1); \
558 c2 = tolower(*(unsigned char *)s2); \
559 if (c1 != c2) break; \
560 if (c1 == 0) break; \
561 s1++; s2++; \
562 } \
563 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
564 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
565 return 0; \
566 }
567
sewardj3c944452011-09-05 20:39:57 +0000568#if defined(VGO_linux)
569# if !defined(VGPV_arm_linux_android)
570 STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp)
571 STRCASECMP(VG_Z_LIBC_SONAME, __GI_strcasecmp)
572# endif
sewardj4157d4f2011-09-05 22:18:13 +0000573
sewardj3c944452011-09-05 20:39:57 +0000574#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000575 //STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp)
sewardj4157d4f2011-09-05 22:18:13 +0000576
tomce6d0ac2010-11-12 10:03:13 +0000577#endif
578
579
sewardj3c944452011-09-05 20:39:57 +0000580/*---------------------- strncasecmp ----------------------*/
581
tomce6d0ac2010-11-12 10:03:13 +0000582#define STRNCASECMP(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000583 int VG_REPLACE_FUNCTION_EZU(20130,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000584 ( const char* s1, const char* s2, SizeT nmax ); \
sewardj96044842011-08-18 13:09:55 +0000585 int VG_REPLACE_FUNCTION_EZU(20130,soname,fnname) \
tomce6d0ac2010-11-12 10:03:13 +0000586 ( const char* s1, const char* s2, SizeT nmax ) \
587 { \
tome03c8c42010-11-12 10:40:20 +0000588 extern int tolower(int); \
tomce6d0ac2010-11-12 10:03:13 +0000589 SizeT n = 0; \
590 while (True) { \
591 if (n >= nmax) return 0; \
592 if (*s1 == 0 && *s2 == 0) return 0; \
593 if (*s1 == 0) return -1; \
594 if (*s2 == 0) return 1; \
595 \
sewardjbd2cff22011-08-16 21:45:28 +0000596 if (tolower(*(unsigned char*)s1) \
597 < tolower(*(unsigned char*)s2)) return -1; \
598 if (tolower(*(unsigned char*)s1) \
599 > tolower(*(unsigned char*)s2)) return 1; \
tomce6d0ac2010-11-12 10:03:13 +0000600 \
601 s1++; s2++; n++; \
602 } \
603 }
604
sewardj3c944452011-09-05 20:39:57 +0000605#if defined(VGO_linux)
606# if !defined(VGPV_arm_linux_android)
607 STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp)
608 STRNCASECMP(VG_Z_LIBC_SONAME, __GI_strncasecmp)
609# endif
sewardj4157d4f2011-09-05 22:18:13 +0000610
tomce6d0ac2010-11-12 10:03:13 +0000611#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000612 //STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp)
613 //STRNCASECMP(VG_Z_DYLD, strncasecmp)
sewardj4157d4f2011-09-05 22:18:13 +0000614
tomce6d0ac2010-11-12 10:03:13 +0000615#endif
616
617
sewardj3c944452011-09-05 20:39:57 +0000618/*---------------------- strcasecmp_l ----------------------*/
619
tomce6d0ac2010-11-12 10:03:13 +0000620#define STRCASECMP_L(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000621 int VG_REPLACE_FUNCTION_EZU(20140,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000622 ( const char* s1, const char* s2, void* locale ); \
sewardj96044842011-08-18 13:09:55 +0000623 int VG_REPLACE_FUNCTION_EZU(20140,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000624 ( const char* s1, const char* s2, void* locale ) \
tomce6d0ac2010-11-12 10:03:13 +0000625 { \
sewardj3c944452011-09-05 20:39:57 +0000626 extern int tolower_l(int, void*) __attribute__((weak)); \
tomce6d0ac2010-11-12 10:03:13 +0000627 register unsigned char c1; \
628 register unsigned char c2; \
629 while (True) { \
630 c1 = tolower_l(*(unsigned char *)s1, locale); \
631 c2 = tolower_l(*(unsigned char *)s2, locale); \
632 if (c1 != c2) break; \
633 if (c1 == 0) break; \
634 s1++; s2++; \
635 } \
636 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
637 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
638 return 0; \
639 }
640
tomce6d0ac2010-11-12 10:03:13 +0000641#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000642 STRCASECMP_L(VG_Z_LIBC_SONAME, strcasecmp_l)
643 STRCASECMP_L(VG_Z_LIBC_SONAME, __GI_strcasecmp_l)
644 STRCASECMP_L(VG_Z_LIBC_SONAME, __GI___strcasecmp_l)
sewardj4157d4f2011-09-05 22:18:13 +0000645
sewardj3c944452011-09-05 20:39:57 +0000646#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000647 //STRCASECMP_L(VG_Z_LIBC_SONAME, strcasecmp_l)
sewardj4157d4f2011-09-05 22:18:13 +0000648
tomce6d0ac2010-11-12 10:03:13 +0000649#endif
650
651
sewardj3c944452011-09-05 20:39:57 +0000652/*---------------------- strncasecmp_l ----------------------*/
653
tomce6d0ac2010-11-12 10:03:13 +0000654#define STRNCASECMP_L(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000655 int VG_REPLACE_FUNCTION_EZU(20150,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000656 ( const char* s1, const char* s2, SizeT nmax, void* locale ); \
sewardj96044842011-08-18 13:09:55 +0000657 int VG_REPLACE_FUNCTION_EZU(20150,soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000658 ( const char* s1, const char* s2, SizeT nmax, void* locale ) \
tomce6d0ac2010-11-12 10:03:13 +0000659 { \
tome03c8c42010-11-12 10:40:20 +0000660 extern int tolower_l(int, void*) __attribute__((weak)); \
tomce6d0ac2010-11-12 10:03:13 +0000661 SizeT n = 0; \
662 while (True) { \
663 if (n >= nmax) return 0; \
664 if (*s1 == 0 && *s2 == 0) return 0; \
665 if (*s1 == 0) return -1; \
666 if (*s2 == 0) return 1; \
667 \
sewardjbd2cff22011-08-16 21:45:28 +0000668 if (tolower_l(*(unsigned char*)s1, locale) \
669 < tolower_l(*(unsigned char*)s2, locale)) return -1; \
670 if (tolower_l(*(unsigned char*)s1, locale) \
671 > tolower_l(*(unsigned char*)s2, locale)) return 1; \
tomce6d0ac2010-11-12 10:03:13 +0000672 \
673 s1++; s2++; n++; \
674 } \
675 }
676
tomce6d0ac2010-11-12 10:03:13 +0000677#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000678 STRNCASECMP_L(VG_Z_LIBC_SONAME, strncasecmp_l)
679 STRNCASECMP_L(VG_Z_LIBC_SONAME, __GI_strncasecmp_l)
sewardj4157d4f2011-09-05 22:18:13 +0000680
tomce6d0ac2010-11-12 10:03:13 +0000681#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000682 //STRNCASECMP_L(VG_Z_LIBC_SONAME, strncasecmp_l)
683 //STRNCASECMP_L(VG_Z_DYLD, strncasecmp_l)
sewardj4157d4f2011-09-05 22:18:13 +0000684
tomce6d0ac2010-11-12 10:03:13 +0000685#endif
686
687
sewardj3c944452011-09-05 20:39:57 +0000688/*---------------------- strcmp ----------------------*/
689
njn16eeb4e2005-06-16 03:56:58 +0000690#define STRCMP(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000691 int VG_REPLACE_FUNCTION_EZU(20160,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000692 ( const char* s1, const char* s2 ); \
sewardj96044842011-08-18 13:09:55 +0000693 int VG_REPLACE_FUNCTION_EZU(20160,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000694 ( const char* s1, const char* s2 ) \
njn16eeb4e2005-06-16 03:56:58 +0000695 { \
696 register unsigned char c1; \
697 register unsigned char c2; \
698 while (True) { \
699 c1 = *(unsigned char *)s1; \
700 c2 = *(unsigned char *)s2; \
701 if (c1 != c2) break; \
702 if (c1 == 0) break; \
703 s1++; s2++; \
704 } \
705 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
706 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
707 return 0; \
708 }
709
njnb4cfbc42009-05-04 04:20:02 +0000710#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000711 STRCMP(VG_Z_LIBC_SONAME, strcmp)
712 STRCMP(VG_Z_LIBC_SONAME, __GI_strcmp)
713 STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp)
714 STRCMP(VG_Z_LD64_SO_1, strcmp)
sewardj70f291d2011-09-26 20:20:19 +0000715# if defined(VGPV_arm_linux_android)
716 STRCMP(NONE, __dl_strcmp); /* in /system/bin/linker */
717# endif
sewardj4157d4f2011-09-05 22:18:13 +0000718
sewardj3c944452011-09-05 20:39:57 +0000719#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000720 //STRCMP(VG_Z_LIBC_SONAME, strcmp)
721 STRCMP(VG_Z_LIBC_SONAME, strcmp)
sewardj4157d4f2011-09-05 22:18:13 +0000722
njnb4cfbc42009-05-04 04:20:02 +0000723#endif
njn16eeb4e2005-06-16 03:56:58 +0000724
725
sewardj3c944452011-09-05 20:39:57 +0000726/*---------------------- memchr ----------------------*/
727
njn16eeb4e2005-06-16 03:56:58 +0000728#define MEMCHR(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000729 void* VG_REPLACE_FUNCTION_EZU(20170,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000730 (const void *s, int c, SizeT n); \
sewardj96044842011-08-18 13:09:55 +0000731 void* VG_REPLACE_FUNCTION_EZU(20170,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000732 (const void *s, int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000733 { \
734 SizeT i; \
735 UChar c0 = (UChar)c; \
736 UChar* p = (UChar*)s; \
737 for (i = 0; i < n; i++) \
738 if (p[i] == c0) return (void*)(&p[i]); \
739 return NULL; \
740 }
741
sewardj3c944452011-09-05 20:39:57 +0000742#if defined(VGO_linux)
743 MEMCHR(VG_Z_LIBC_SONAME, memchr)
sewardj4157d4f2011-09-05 22:18:13 +0000744
sewardj3c944452011-09-05 20:39:57 +0000745#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000746 //MEMCHR(VG_Z_LIBC_SONAME, memchr)
747 //MEMCHR(VG_Z_DYLD, memchr)
sewardj4157d4f2011-09-05 22:18:13 +0000748
njnf76d27a2009-05-28 01:53:07 +0000749#endif
njn16eeb4e2005-06-16 03:56:58 +0000750
751
sewardj3c944452011-09-05 20:39:57 +0000752/*---------------------- memcpy ----------------------*/
753
sewardjbd2cff22011-08-16 21:45:28 +0000754#define MEMMOVE_OR_MEMCPY(becTag, soname, fnname, do_ol_check) \
sewardjd88797f2011-08-17 21:25:50 +0000755 void* VG_REPLACE_FUNCTION_EZZ(becTag,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000756 ( void *dst, const void *src, SizeT len ); \
sewardjd88797f2011-08-17 21:25:50 +0000757 void* VG_REPLACE_FUNCTION_EZZ(becTag,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000758 ( void *dst, const void *src, SizeT len ) \
njn16eeb4e2005-06-16 03:56:58 +0000759 { \
sewardjbd2cff22011-08-16 21:45:28 +0000760 if (do_ol_check && is_overlap(dst, src, len, len)) \
njn718d3b12006-12-16 00:54:12 +0000761 RECORD_OVERLAP_ERROR("memcpy", dst, src, len); \
sewardjb6c04032007-11-13 20:52:29 +0000762 \
sewardj7b4e00b2010-08-24 09:05:52 +0000763 const Addr WS = sizeof(UWord); /* 8 or 4 */ \
764 const Addr WM = WS - 1; /* 7 or 3 */ \
765 \
tom863ab7c2011-08-18 08:10:20 +0000766 if (len > 0) { \
767 if (dst < src) { \
sewardj7b4e00b2010-08-24 09:05:52 +0000768 \
tom863ab7c2011-08-18 08:10:20 +0000769 /* Copying backwards. */ \
770 SizeT n = len; \
771 Addr d = (Addr)dst; \
772 Addr s = (Addr)src; \
773 \
774 if (((s^d) & WM) == 0) { \
775 /* s and d have same UWord alignment. */ \
776 /* Pull up to a UWord boundary. */ \
777 while ((s & WM) != 0 && n >= 1) \
778 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
779 /* Copy UWords. */ \
780 while (n >= WS) \
781 { *(UWord*)d = *(UWord*)s; s += WS; d += WS; n -= WS; } \
782 if (n == 0) \
783 return dst; \
784 } \
785 if (((s|d) & 1) == 0) { \
786 /* Both are 16-aligned; copy what we can thusly. */ \
787 while (n >= 2) \
788 { *(UShort*)d = *(UShort*)s; s += 2; d += 2; n -= 2; } \
789 } \
790 /* Copy leftovers, or everything if misaligned. */ \
791 while (n >= 1) \
sewardj7b4e00b2010-08-24 09:05:52 +0000792 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
sewardj7b4e00b2010-08-24 09:05:52 +0000793 \
tom863ab7c2011-08-18 08:10:20 +0000794 } else if (dst > src) { \
795 \
796 SizeT n = len; \
797 Addr d = ((Addr)dst) + n; \
798 Addr s = ((Addr)src) + n; \
799 \
800 /* Copying forwards. */ \
801 if (((s^d) & WM) == 0) { \
802 /* s and d have same UWord alignment. */ \
803 /* Back down to a UWord boundary. */ \
804 while ((s & WM) != 0 && n >= 1) \
805 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
806 /* Copy UWords. */ \
807 while (n >= WS) \
808 { s -= WS; d -= WS; *(UWord*)d = *(UWord*)s; n -= WS; } \
809 if (n == 0) \
810 return dst; \
811 } \
812 if (((s|d) & 1) == 0) { \
813 /* Both are 16-aligned; copy what we can thusly. */ \
814 while (n >= 2) \
815 { s -= 2; d -= 2; *(UShort*)d = *(UShort*)s; n -= 2; } \
816 } \
817 /* Copy leftovers, or everything if misaligned. */ \
818 while (n >= 1) \
sewardj7b4e00b2010-08-24 09:05:52 +0000819 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
tom863ab7c2011-08-18 08:10:20 +0000820 \
njn16eeb4e2005-06-16 03:56:58 +0000821 } \
njn16eeb4e2005-06-16 03:56:58 +0000822 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000823 \
njn16eeb4e2005-06-16 03:56:58 +0000824 return dst; \
825 }
826
sewardjbd2cff22011-08-16 21:45:28 +0000827#define MEMMOVE(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000828 MEMMOVE_OR_MEMCPY(20181, soname, fnname, 0)
sewardjbd2cff22011-08-16 21:45:28 +0000829
830#define MEMCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000831 MEMMOVE_OR_MEMCPY(20180, soname, fnname, 1)
sewardjbd2cff22011-08-16 21:45:28 +0000832
njnb4cfbc42009-05-04 04:20:02 +0000833#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000834 /* For older memcpy we have to use memmove-like semantics and skip
835 the overlap check; sigh; see #275284. */
836 MEMMOVE(VG_Z_LIBC_SONAME, memcpyZAGLIBCZu2Zd2Zd5) /* memcpy@GLIBC_2.2.5 */
837 MEMCPY(VG_Z_LIBC_SONAME, memcpyZAZAGLIBCZu2Zd14) /* memcpy@@GLIBC_2.14 */
838 MEMCPY(VG_Z_LIBC_SONAME, memcpy) /* fallback case */
839 MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */
840 MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */
sewardj3c944452011-09-05 20:39:57 +0000841 /* icc9 blats these around all over the place. Not only in the main
842 executable but various .so's. They are highly tuned and read
843 memory beyond the source boundary (although work correctly and
844 never go across page boundaries), so give errors when run
845 natively, at least for misaligned source arg. Just intercepting
846 in the exe only until we understand more about the problem. See
847 http://bugs.kde.org/show_bug.cgi?id=139776
sewardjf0b34322007-01-16 21:42:28 +0000848 */
sewardj3c944452011-09-05 20:39:57 +0000849 MEMCPY(NONE, ZuintelZufastZumemcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000850
851#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000852 //MEMCPY(VG_Z_LIBC_SONAME, memcpy)
853 //MEMCPY(VG_Z_DYLD, memcpy)
854 MEMCPY(VG_Z_LIBC_SONAME, memcpyZDVARIANTZDsse3x) /* memcpy$VARIANT$sse3x */
855 MEMCPY(VG_Z_LIBC_SONAME, memcpyZDVARIANTZDsse42) /* memcpy$VARIANT$sse42 */
sewardj4157d4f2011-09-05 22:18:13 +0000856
sewardj3c944452011-09-05 20:39:57 +0000857#endif
sewardj31b9ce12006-10-17 01:27:13 +0000858
njn16eeb4e2005-06-16 03:56:58 +0000859
sewardj3c944452011-09-05 20:39:57 +0000860/*---------------------- memcmp ----------------------*/
861
njn16eeb4e2005-06-16 03:56:58 +0000862#define MEMCMP(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000863 int VG_REPLACE_FUNCTION_EZU(20190,soname,fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000864 ( const void *s1V, const void *s2V, SizeT n ); \
sewardj96044842011-08-18 13:09:55 +0000865 int VG_REPLACE_FUNCTION_EZU(20190,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000866 ( const void *s1V, const void *s2V, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000867 { \
868 int res; \
869 unsigned char a0; \
870 unsigned char b0; \
871 unsigned char* s1 = (unsigned char*)s1V; \
872 unsigned char* s2 = (unsigned char*)s2V; \
sewardjb6c04032007-11-13 20:52:29 +0000873 \
njn16eeb4e2005-06-16 03:56:58 +0000874 while (n != 0) { \
875 a0 = s1[0]; \
876 b0 = s2[0]; \
877 s1 += 1; \
878 s2 += 1; \
879 res = ((int)a0) - ((int)b0); \
880 if (res != 0) \
881 return res; \
882 n -= 1; \
883 } \
884 return 0; \
885 }
886
njnb4cfbc42009-05-04 04:20:02 +0000887#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000888 MEMCMP(VG_Z_LIBC_SONAME, memcmp)
889 MEMCMP(VG_Z_LIBC_SONAME, bcmp)
890 MEMCMP(VG_Z_LD_SO_1, bcmp)
sewardj4157d4f2011-09-05 22:18:13 +0000891
njnf76d27a2009-05-28 01:53:07 +0000892#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000893 //MEMCMP(VG_Z_LIBC_SONAME, memcmp)
894 //MEMCMP(VG_Z_LIBC_SONAME, bcmp)
895 //MEMCMP(VG_Z_DYLD, memcmp)
896 //MEMCMP(VG_Z_DYLD, bcmp)
sewardj4157d4f2011-09-05 22:18:13 +0000897
njnb4cfbc42009-05-04 04:20:02 +0000898#endif
njn3e884182003-04-15 13:03:23 +0000899
jseward0845ef82003-12-22 22:31:27 +0000900
sewardj3c944452011-09-05 20:39:57 +0000901/*---------------------- stpcpy ----------------------*/
902
jseward0845ef82003-12-22 22:31:27 +0000903/* Copy SRC to DEST, returning the address of the terminating '\0' in
904 DEST. (minor variant of strcpy) */
njn16eeb4e2005-06-16 03:56:58 +0000905#define STPCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000906 char* VG_REPLACE_FUNCTION_EZU(20200,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000907 ( char* dst, const char* src ); \
sewardj96044842011-08-18 13:09:55 +0000908 char* VG_REPLACE_FUNCTION_EZU(20200,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000909 ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000910 { \
911 const Char* src_orig = src; \
912 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000913 \
njn16eeb4e2005-06-16 03:56:58 +0000914 while (*src) *dst++ = *src++; \
915 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000916 \
njn16eeb4e2005-06-16 03:56:58 +0000917 /* This checks for overlap after copying, unavoidable without */ \
918 /* pre-counting length... should be ok */ \
919 if (is_overlap(dst_orig, \
920 src_orig, \
921 (Addr)dst-(Addr)dst_orig+1, \
922 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000923 RECORD_OVERLAP_ERROR("stpcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000924 \
njn16eeb4e2005-06-16 03:56:58 +0000925 return dst; \
sewardj44e495f2005-05-12 17:58:28 +0000926 }
njn16eeb4e2005-06-16 03:56:58 +0000927
njnb4cfbc42009-05-04 04:20:02 +0000928#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +0000929 STPCPY(VG_Z_LIBC_SONAME, stpcpy)
930 STPCPY(VG_Z_LIBC_SONAME, __GI_stpcpy)
931 STPCPY(VG_Z_LD_LINUX_SO_2, stpcpy)
932 STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000933
njnf76d27a2009-05-28 01:53:07 +0000934#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000935 //STPCPY(VG_Z_LIBC_SONAME, stpcpy)
936 //STPCPY(VG_Z_DYLD, stpcpy)
sewardj4157d4f2011-09-05 22:18:13 +0000937
njnb4cfbc42009-05-04 04:20:02 +0000938#endif
939
njn16eeb4e2005-06-16 03:56:58 +0000940
sewardj3c944452011-09-05 20:39:57 +0000941/*---------------------- memset ----------------------*/
942
943/* Why are we bothering to intercept this? It seems entirely
944 pointless. */
sewardj731f9cf2011-09-21 08:43:08 +0000945
njn16eeb4e2005-06-16 03:56:58 +0000946#define MEMSET(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000947 void* VG_REPLACE_FUNCTION_EZU(20210,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000948 (void *s, Int c, SizeT n); \
sewardj96044842011-08-18 13:09:55 +0000949 void* VG_REPLACE_FUNCTION_EZU(20210,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +0000950 (void *s, Int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000951 { \
sewardj7b4e00b2010-08-24 09:05:52 +0000952 Addr a = (Addr)s; \
953 UInt c4 = (c & 0xFF); \
954 c4 = (c4 << 8) | c4; \
955 c4 = (c4 << 16) | c4; \
956 while ((a & 3) != 0 && n >= 1) \
957 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
958 while (n >= 4) \
959 { *(UInt*)a = c4; a += 4; n -= 4; } \
960 while (n >= 1) \
961 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
njn16eeb4e2005-06-16 03:56:58 +0000962 return s; \
sewardj44e495f2005-05-12 17:58:28 +0000963 }
njn16eeb4e2005-06-16 03:56:58 +0000964
sewardj3c944452011-09-05 20:39:57 +0000965#if defined(VGO_linux)
966 MEMSET(VG_Z_LIBC_SONAME, memset)
sewardj4157d4f2011-09-05 22:18:13 +0000967
sewardj3c944452011-09-05 20:39:57 +0000968#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000969 //MEMSET(VG_Z_LIBC_SONAME, memset)
970 //MEMSET(VG_Z_DYLD, memset)
sewardj3c944452011-09-05 20:39:57 +0000971 MEMSET(VG_Z_LIBC_SONAME, memset)
sewardj4157d4f2011-09-05 22:18:13 +0000972
njnf76d27a2009-05-28 01:53:07 +0000973#endif
njn16eeb4e2005-06-16 03:56:58 +0000974
975
sewardj3c944452011-09-05 20:39:57 +0000976/*---------------------- memmove ----------------------*/
977
sewardj96044842011-08-18 13:09:55 +0000978/* memmove -- use the MEMMOVE defn above. */
sewardj731f9cf2011-09-21 08:43:08 +0000979
sewardj3c944452011-09-05 20:39:57 +0000980#if defined(VGO_linux)
981 MEMMOVE(VG_Z_LIBC_SONAME, memmove)
sewardj4157d4f2011-09-05 22:18:13 +0000982
sewardj3c944452011-09-05 20:39:57 +0000983#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +0000984 //MEMMOVE(VG_Z_LIBC_SONAME, memmove)
985 //MEMMOVE(VG_Z_DYLD, memmove)#
986 MEMMOVE(VG_Z_LIBC_SONAME, memmoveZDVARIANTZDsse3x) /* memmove$VARIANT$sse3x */
987 MEMMOVE(VG_Z_LIBC_SONAME, memmoveZDVARIANTZDsse42) /* memmove$VARIANT$sse42 */
sewardj4157d4f2011-09-05 22:18:13 +0000988
njnf76d27a2009-05-28 01:53:07 +0000989#endif
990
991
sewardj3c944452011-09-05 20:39:57 +0000992/*---------------------- bcopy ----------------------*/
993
njnf76d27a2009-05-28 01:53:07 +0000994#define BCOPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +0000995 void VG_REPLACE_FUNCTION_EZU(20230,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000996 (const void *srcV, void *dstV, SizeT n); \
sewardj96044842011-08-18 13:09:55 +0000997 void VG_REPLACE_FUNCTION_EZU(20230,soname,fnname) \
njnf76d27a2009-05-28 01:53:07 +0000998 (const void *srcV, void *dstV, SizeT n) \
999 { \
1000 SizeT i; \
1001 Char* dst = (Char*)dstV; \
1002 Char* src = (Char*)srcV; \
1003 if (dst < src) { \
1004 for (i = 0; i < n; i++) \
1005 dst[i] = src[i]; \
1006 } \
1007 else \
1008 if (dst > src) { \
1009 for (i = 0; i < n; i++) \
1010 dst[n-i-1] = src[n-i-1]; \
1011 } \
1012 }
1013
sewardj3c944452011-09-05 20:39:57 +00001014#if defined(VGO_linux)
sewardj4157d4f2011-09-05 22:18:13 +00001015
sewardj3c944452011-09-05 20:39:57 +00001016#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +00001017 //BCOPY(VG_Z_LIBC_SONAME, bcopy)
1018 //BCOPY(VG_Z_DYLD, bcopy)
sewardj4157d4f2011-09-05 22:18:13 +00001019
njnf76d27a2009-05-28 01:53:07 +00001020#endif
sewardj44e495f2005-05-12 17:58:28 +00001021
jseward0845ef82003-12-22 22:31:27 +00001022
sewardj3c944452011-09-05 20:39:57 +00001023/*-------------------- memmove_chk --------------------*/
1024
sewardj24cb2172007-02-23 09:03:26 +00001025/* glibc 2.5 variant of memmove which checks the dest is big enough.
1026 There is no specific part of glibc that this is copied from. */
1027#define GLIBC25___MEMMOVE_CHK(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001028 void* VG_REPLACE_FUNCTION_EZU(20240,soname,fnname) \
sewardj24cb2172007-02-23 09:03:26 +00001029 (void *dstV, const void *srcV, SizeT n, SizeT destlen); \
sewardj96044842011-08-18 13:09:55 +00001030 void* VG_REPLACE_FUNCTION_EZU(20240,soname,fnname) \
sewardj24cb2172007-02-23 09:03:26 +00001031 (void *dstV, const void *srcV, SizeT n, SizeT destlen) \
1032 { \
sewardj24cb2172007-02-23 09:03:26 +00001033 SizeT i; \
1034 Char* dst = (Char*)dstV; \
1035 Char* src = (Char*)srcV; \
1036 if (destlen < n) \
1037 goto badness; \
1038 if (dst < src) { \
1039 for (i = 0; i < n; i++) \
1040 dst[i] = src[i]; \
1041 } \
1042 else \
1043 if (dst > src) { \
1044 for (i = 0; i < n; i++) \
1045 dst[n-i-1] = src[n-i-1]; \
1046 } \
1047 return dst; \
1048 badness: \
1049 VALGRIND_PRINTF_BACKTRACE( \
1050 "*** memmove_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +00001051 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +00001052 my_exit(127); \
sewardjc271ec82007-02-27 22:36:14 +00001053 /*NOTREACHED*/ \
1054 return NULL; \
sewardj24cb2172007-02-23 09:03:26 +00001055 }
1056
sewardj3c944452011-09-05 20:39:57 +00001057#if defined(VGO_linux)
1058 GLIBC25___MEMMOVE_CHK(VG_Z_LIBC_SONAME, __memmove_chk)
sewardj4157d4f2011-09-05 22:18:13 +00001059
sewardj3c944452011-09-05 20:39:57 +00001060#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001061
sewardj3c944452011-09-05 20:39:57 +00001062#endif
sewardj24cb2172007-02-23 09:03:26 +00001063
1064
sewardj3c944452011-09-05 20:39:57 +00001065/*-------------------- strchrnul --------------------*/
1066
sewardj4e9a4b62004-11-23 00:20:17 +00001067/* Find the first occurrence of C in S or the final NUL byte. */
njn16eeb4e2005-06-16 03:56:58 +00001068#define GLIBC232_STRCHRNUL(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001069 char* VG_REPLACE_FUNCTION_EZU(20250,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001070 (const char* s, int c_in); \
sewardj96044842011-08-18 13:09:55 +00001071 char* VG_REPLACE_FUNCTION_EZU(20250,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001072 (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +00001073 { \
1074 unsigned char c = (unsigned char) c_in; \
1075 unsigned char* char_ptr = (unsigned char *)s; \
1076 while (1) { \
1077 if (*char_ptr == 0) return char_ptr; \
1078 if (*char_ptr == c) return char_ptr; \
1079 char_ptr++; \
1080 } \
sewardj4e9a4b62004-11-23 00:20:17 +00001081 }
njn16eeb4e2005-06-16 03:56:58 +00001082
sewardj3c944452011-09-05 20:39:57 +00001083#if defined(VGO_linux)
1084 GLIBC232_STRCHRNUL(VG_Z_LIBC_SONAME, strchrnul)
sewardj4157d4f2011-09-05 22:18:13 +00001085
sewardj3c944452011-09-05 20:39:57 +00001086#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001087
sewardj3c944452011-09-05 20:39:57 +00001088#endif
sewardj4e9a4b62004-11-23 00:20:17 +00001089
1090
sewardj3c944452011-09-05 20:39:57 +00001091/*---------------------- rawmemchr ----------------------*/
1092
sewardj4e9a4b62004-11-23 00:20:17 +00001093/* Find the first occurrence of C in S. */
njn16eeb4e2005-06-16 03:56:58 +00001094#define GLIBC232_RAWMEMCHR(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001095 char* VG_REPLACE_FUNCTION_EZU(20260,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001096 (const char* s, int c_in); \
sewardj96044842011-08-18 13:09:55 +00001097 char* VG_REPLACE_FUNCTION_EZU(20260,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001098 (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +00001099 { \
1100 unsigned char c = (unsigned char) c_in; \
1101 unsigned char* char_ptr = (unsigned char *)s; \
1102 while (1) { \
1103 if (*char_ptr == c) return char_ptr; \
1104 char_ptr++; \
1105 } \
sewardj4e9a4b62004-11-23 00:20:17 +00001106 }
njn16eeb4e2005-06-16 03:56:58 +00001107
tomd2645142009-10-29 09:27:11 +00001108#if defined (VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001109 GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, rawmemchr)
1110 GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, __GI___rawmemchr)
sewardj4157d4f2011-09-05 22:18:13 +00001111
sewardj3c944452011-09-05 20:39:57 +00001112#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001113
tomd2645142009-10-29 09:27:11 +00001114#endif
sewardj4e9a4b62004-11-23 00:20:17 +00001115
sewardj3c944452011-09-05 20:39:57 +00001116
1117/*---------------------- strcpy_chk ----------------------*/
1118
sewardjdc5d8322007-01-28 06:32:01 +00001119/* glibc variant of strcpy that checks the dest is big enough.
1120 Copied from glibc-2.5/debug/test-strcpy_chk.c. */
sewardj620e5262006-12-31 00:22:30 +00001121#define GLIBC25___STRCPY_CHK(soname,fnname) \
sewardj96044842011-08-18 13:09:55 +00001122 char* VG_REPLACE_FUNCTION_EZU(20270,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001123 (char* dst, const char* src, SizeT len); \
sewardj96044842011-08-18 13:09:55 +00001124 char* VG_REPLACE_FUNCTION_EZU(20270,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001125 (char* dst, const char* src, SizeT len) \
sewardj620e5262006-12-31 00:22:30 +00001126 { \
sewardj620e5262006-12-31 00:22:30 +00001127 char* ret = dst; \
1128 if (! len) \
1129 goto badness; \
1130 while ((*dst++ = *src++) != '\0') \
1131 if (--len == 0) \
1132 goto badness; \
1133 return ret; \
1134 badness: \
1135 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +00001136 "*** strcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +00001137 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +00001138 my_exit(127); \
sewardj620e5262006-12-31 00:22:30 +00001139 /*NOTREACHED*/ \
1140 return NULL; \
1141 }
1142
sewardj3c944452011-09-05 20:39:57 +00001143#if defined(VGO_linux)
1144 GLIBC25___STRCPY_CHK(VG_Z_LIBC_SONAME, __strcpy_chk)
sewardj4157d4f2011-09-05 22:18:13 +00001145
sewardj3c944452011-09-05 20:39:57 +00001146#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001147
sewardj3c944452011-09-05 20:39:57 +00001148#endif
sewardj620e5262006-12-31 00:22:30 +00001149
1150
sewardj3c944452011-09-05 20:39:57 +00001151/*---------------------- stpcpy_chk ----------------------*/
1152
sewardjdc5d8322007-01-28 06:32:01 +00001153/* glibc variant of stpcpy that checks the dest is big enough.
1154 Copied from glibc-2.5/debug/test-stpcpy_chk.c. */
sewardjb8d03852007-01-27 00:49:44 +00001155#define GLIBC25___STPCPY_CHK(soname,fnname) \
sewardj96044842011-08-18 13:09:55 +00001156 char* VG_REPLACE_FUNCTION_EZU(20280,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001157 (char* dst, const char* src, SizeT len); \
sewardj96044842011-08-18 13:09:55 +00001158 char* VG_REPLACE_FUNCTION_EZU(20280,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001159 (char* dst, const char* src, SizeT len) \
sewardjb8d03852007-01-27 00:49:44 +00001160 { \
sewardjdc5d8322007-01-28 06:32:01 +00001161 if (! len) \
1162 goto badness; \
1163 while ((*dst++ = *src++) != '\0') \
1164 if (--len == 0) \
sewardjb8d03852007-01-27 00:49:44 +00001165 goto badness; \
sewardjb8d03852007-01-27 00:49:44 +00001166 return dst - 1; \
1167 badness: \
1168 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +00001169 "*** stpcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +00001170 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +00001171 my_exit(127); \
sewardjb8d03852007-01-27 00:49:44 +00001172 /*NOTREACHED*/ \
1173 return NULL; \
1174 }
1175
sewardj3c944452011-09-05 20:39:57 +00001176#if defined(VGO_linux)
1177 GLIBC25___STPCPY_CHK(VG_Z_LIBC_SONAME, __stpcpy_chk)
sewardj4157d4f2011-09-05 22:18:13 +00001178
sewardj3c944452011-09-05 20:39:57 +00001179#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001180
sewardj3c944452011-09-05 20:39:57 +00001181#endif
sewardjb8d03852007-01-27 00:49:44 +00001182
1183
sewardj3c944452011-09-05 20:39:57 +00001184/*---------------------- mempcpy ----------------------*/
1185
sewardj841b72d2006-12-31 18:55:56 +00001186/* mempcpy */
1187#define GLIBC25_MEMPCPY(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001188 void* VG_REPLACE_FUNCTION_EZU(20290,soname,fnname) \
sewardj841b72d2006-12-31 18:55:56 +00001189 ( void *dst, const void *src, SizeT len ); \
sewardj96044842011-08-18 13:09:55 +00001190 void* VG_REPLACE_FUNCTION_EZU(20290,soname,fnname) \
sewardj841b72d2006-12-31 18:55:56 +00001191 ( void *dst, const void *src, SizeT len ) \
1192 { \
1193 register char *d; \
1194 register char *s; \
1195 SizeT len_saved = len; \
1196 \
1197 if (len == 0) \
1198 return dst; \
1199 \
1200 if (is_overlap(dst, src, len, len)) \
1201 RECORD_OVERLAP_ERROR("mempcpy", dst, src, len); \
1202 \
1203 if ( dst > src ) { \
1204 d = (char *)dst + len - 1; \
1205 s = (char *)src + len - 1; \
1206 while ( len-- ) { \
1207 *d-- = *s--; \
1208 } \
1209 } else if ( dst < src ) { \
1210 d = (char *)dst; \
1211 s = (char *)src; \
1212 while ( len-- ) { \
1213 *d++ = *s++; \
1214 } \
1215 } \
1216 return (void*)( ((char*)dst) + len_saved ); \
1217 }
1218
njnb4cfbc42009-05-04 04:20:02 +00001219#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001220 GLIBC25_MEMPCPY(VG_Z_LIBC_SONAME, mempcpy)
1221 GLIBC25_MEMPCPY(VG_Z_LD_SO_1, mempcpy) /* ld.so.1 */
sewardj4157d4f2011-09-05 22:18:13 +00001222
sewardj3c944452011-09-05 20:39:57 +00001223#elif defined(VGO_darwin)
sewardj731f9cf2011-09-21 08:43:08 +00001224 //GLIBC25_MEMPCPY(VG_Z_LIBC_SONAME, mempcpy)
sewardj4157d4f2011-09-05 22:18:13 +00001225
njnb4cfbc42009-05-04 04:20:02 +00001226#endif
sewardj841b72d2006-12-31 18:55:56 +00001227
1228
sewardj3c944452011-09-05 20:39:57 +00001229/*-------------------- memcpy_chk --------------------*/
1230
sewardjb6c04032007-11-13 20:52:29 +00001231#define GLIBC26___MEMCPY_CHK(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001232 void* VG_REPLACE_FUNCTION_EZU(20300,soname,fnname) \
sewardjb6c04032007-11-13 20:52:29 +00001233 (void* dst, const void* src, SizeT len, SizeT dstlen ); \
sewardj96044842011-08-18 13:09:55 +00001234 void* VG_REPLACE_FUNCTION_EZU(20300,soname,fnname) \
sewardjb6c04032007-11-13 20:52:29 +00001235 (void* dst, const void* src, SizeT len, SizeT dstlen ) \
1236 { \
sewardjb6c04032007-11-13 20:52:29 +00001237 register char *d; \
1238 register char *s; \
1239 \
1240 if (dstlen < len) goto badness; \
1241 \
1242 if (len == 0) \
1243 return dst; \
1244 \
1245 if (is_overlap(dst, src, len, len)) \
1246 RECORD_OVERLAP_ERROR("memcpy_chk", dst, src, len); \
1247 \
1248 if ( dst > src ) { \
1249 d = (char *)dst + len - 1; \
1250 s = (char *)src + len - 1; \
1251 while ( len-- ) { \
1252 *d-- = *s--; \
1253 } \
1254 } else if ( dst < src ) { \
1255 d = (char *)dst; \
1256 s = (char *)src; \
1257 while ( len-- ) { \
1258 *d++ = *s++; \
1259 } \
1260 } \
1261 return dst; \
1262 badness: \
1263 VALGRIND_PRINTF_BACKTRACE( \
1264 "*** memcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +00001265 "program terminated\n"); \
sewardj126e82d2011-07-12 13:33:00 +00001266 my_exit(127); \
sewardjb6c04032007-11-13 20:52:29 +00001267 /*NOTREACHED*/ \
1268 return NULL; \
1269 }
1270
sewardj3c944452011-09-05 20:39:57 +00001271#if defined(VGO_linux)
1272 GLIBC26___MEMCPY_CHK(VG_Z_LIBC_SONAME, __memcpy_chk)
sewardj4157d4f2011-09-05 22:18:13 +00001273
sewardj3c944452011-09-05 20:39:57 +00001274#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001275
sewardj3c944452011-09-05 20:39:57 +00001276#endif
sewardjb6c04032007-11-13 20:52:29 +00001277
1278
sewardj3c944452011-09-05 20:39:57 +00001279/*---------------------- strstr ----------------------*/
1280
sewardja77687c2010-08-19 13:22:34 +00001281#define STRSTR(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001282 void* VG_REPLACE_FUNCTION_EZU(20310,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001283 (void* haystack, void* needle); \
sewardj96044842011-08-18 13:09:55 +00001284 void* VG_REPLACE_FUNCTION_EZU(20310,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001285 (void* haystack, void* needle) \
1286 { \
1287 UChar* h = (UChar*)haystack; \
1288 UChar* n = (UChar*)needle; \
1289 \
1290 /* find the length of n, not including terminating zero */ \
1291 UWord nlen = 0; \
1292 while (n[nlen]) nlen++; \
1293 \
1294 /* if n is the empty string, match immediately. */ \
1295 if (nlen == 0) return h; \
1296 \
1297 /* assert(nlen >= 1); */ \
1298 UChar n0 = n[0]; \
1299 \
1300 while (1) { \
1301 UChar hh = *h; \
1302 if (hh == 0) return NULL; \
1303 if (hh != n0) { h++; continue; } \
1304 \
1305 UWord i; \
1306 for (i = 0; i < nlen; i++) { \
1307 if (n[i] != h[i]) \
1308 break; \
1309 } \
1310 /* assert(i >= 0 && i <= nlen); */ \
1311 if (i == nlen) \
1312 return h; \
1313 \
1314 h++; \
1315 } \
1316 }
1317
1318#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001319 STRSTR(VG_Z_LIBC_SONAME, strstr)
sewardj4157d4f2011-09-05 22:18:13 +00001320
sewardj3c944452011-09-05 20:39:57 +00001321#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001322
sewardja77687c2010-08-19 13:22:34 +00001323#endif
1324
1325
sewardj3c944452011-09-05 20:39:57 +00001326/*---------------------- strpbrk ----------------------*/
1327
sewardja77687c2010-08-19 13:22:34 +00001328#define STRPBRK(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001329 void* VG_REPLACE_FUNCTION_EZU(20320,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001330 (void* sV, void* acceptV); \
sewardj96044842011-08-18 13:09:55 +00001331 void* VG_REPLACE_FUNCTION_EZU(20320,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001332 (void* sV, void* acceptV) \
1333 { \
1334 UChar* s = (UChar*)sV; \
1335 UChar* accept = (UChar*)acceptV; \
1336 \
1337 /* find the length of 'accept', not including terminating zero */ \
1338 UWord nacc = 0; \
1339 while (accept[nacc]) nacc++; \
1340 \
1341 /* if n is the empty string, fail immediately. */ \
1342 if (nacc == 0) return NULL; \
1343 \
1344 /* assert(nacc >= 1); */ \
1345 while (1) { \
1346 UWord i; \
1347 UChar sc = *s; \
1348 if (sc == 0) \
1349 break; \
1350 for (i = 0; i < nacc; i++) { \
1351 if (sc == accept[i]) \
1352 return s; \
1353 } \
1354 s++; \
1355 } \
1356 \
1357 return NULL; \
1358 }
1359
1360#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001361 STRPBRK(VG_Z_LIBC_SONAME, strpbrk)
sewardj4157d4f2011-09-05 22:18:13 +00001362
sewardj3c944452011-09-05 20:39:57 +00001363#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001364
sewardja77687c2010-08-19 13:22:34 +00001365#endif
1366
1367
sewardj3c944452011-09-05 20:39:57 +00001368/*---------------------- strcspn ----------------------*/
1369
sewardja77687c2010-08-19 13:22:34 +00001370#define STRCSPN(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001371 SizeT VG_REPLACE_FUNCTION_EZU(20330,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001372 (void* sV, void* rejectV); \
sewardj96044842011-08-18 13:09:55 +00001373 SizeT VG_REPLACE_FUNCTION_EZU(20330,soname,fnname) \
sewardja77687c2010-08-19 13:22:34 +00001374 (void* sV, void* rejectV) \
1375 { \
1376 UChar* s = (UChar*)sV; \
1377 UChar* reject = (UChar*)rejectV; \
1378 \
1379 /* find the length of 'reject', not including terminating zero */ \
1380 UWord nrej = 0; \
1381 while (reject[nrej]) nrej++; \
1382 \
1383 UWord len = 0; \
1384 while (1) { \
1385 UWord i; \
1386 UChar sc = *s; \
1387 if (sc == 0) \
1388 break; \
1389 for (i = 0; i < nrej; i++) { \
1390 if (sc == reject[i]) \
1391 break; \
1392 } \
1393 /* assert(i >= 0 && i <= nrej); */ \
1394 if (i < nrej) \
1395 break; \
1396 s++; \
1397 len++; \
1398 } \
1399 \
1400 return len; \
1401 }
1402
1403#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001404 STRCSPN(VG_Z_LIBC_SONAME, strcspn)
sewardj4157d4f2011-09-05 22:18:13 +00001405
sewardj3c944452011-09-05 20:39:57 +00001406#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001407
sewardja77687c2010-08-19 13:22:34 +00001408#endif
1409
1410
sewardj3c944452011-09-05 20:39:57 +00001411/*---------------------- strspn ----------------------*/
1412
sewardjbd2cff22011-08-16 21:45:28 +00001413#define STRSPN(soname, fnname) \
sewardj96044842011-08-18 13:09:55 +00001414 SizeT VG_REPLACE_FUNCTION_EZU(20340,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001415 (void* sV, void* acceptV); \
sewardj96044842011-08-18 13:09:55 +00001416 SizeT VG_REPLACE_FUNCTION_EZU(20340,soname,fnname) \
sewardjbd2cff22011-08-16 21:45:28 +00001417 (void* sV, void* acceptV) \
1418 { \
1419 UChar* s = (UChar*)sV; \
1420 UChar* accept = (UChar*)acceptV; \
1421 \
1422 /* find the length of 'accept', not including terminating zero */ \
1423 UWord nacc = 0; \
1424 while (accept[nacc]) nacc++; \
1425 if (nacc == 0) return 0; \
1426 \
1427 UWord len = 0; \
1428 while (1) { \
1429 UWord i; \
1430 UChar sc = *s; \
1431 if (sc == 0) \
1432 break; \
1433 for (i = 0; i < nacc; i++) { \
1434 if (sc == accept[i]) \
1435 break; \
1436 } \
1437 /* assert(i >= 0 && i <= nacc); */ \
1438 if (i == nacc) \
1439 break; \
1440 s++; \
1441 len++; \
1442 } \
1443 \
1444 return len; \
1445 }
1446
1447#if defined(VGO_linux)
sewardj3c944452011-09-05 20:39:57 +00001448 STRSPN(VG_Z_LIBC_SONAME, strspn)
sewardj4157d4f2011-09-05 22:18:13 +00001449
sewardj3c944452011-09-05 20:39:57 +00001450#elif defined(VGO_darwin)
sewardj4157d4f2011-09-05 22:18:13 +00001451
sewardjbd2cff22011-08-16 21:45:28 +00001452#endif
sewardjba189352010-08-20 18:24:16 +00001453
1454
sewardj284f2a32011-10-21 08:07:13 +00001455/*---------------------- strcasestr ----------------------*/
1456
1457#define STRCASESTR(soname, fnname) \
1458 void* VG_REPLACE_FUNCTION_EZU(20350,soname,fnname) \
1459 (void* haystack, void* needle); \
1460 void* VG_REPLACE_FUNCTION_EZU(20350,soname,fnname) \
1461 (void* haystack, void* needle) \
1462 { \
1463 extern int tolower(int); \
1464 UChar* h = (UChar*)haystack; \
1465 UChar* n = (UChar*)needle; \
1466 \
1467 /* find the length of n, not including terminating zero */ \
1468 UWord nlen = 0; \
1469 while (n[nlen]) nlen++; \
1470 \
1471 /* if n is the empty string, match immediately. */ \
1472 if (nlen == 0) return h; \
1473 \
1474 /* assert(nlen >= 1); */ \
1475 UChar n0 = tolower(n[0]); \
1476 \
1477 while (1) { \
1478 UChar hh = tolower(*h); \
1479 if (hh == 0) return NULL; \
1480 if (hh != n0) { h++; continue; } \
1481 \
1482 UWord i; \
1483 for (i = 0; i < nlen; i++) { \
1484 if (tolower(n[i]) != tolower(h[i])) \
1485 break; \
1486 } \
1487 /* assert(i >= 0 && i <= nlen); */ \
1488 if (i == nlen) \
1489 return h; \
1490 \
1491 h++; \
1492 } \
1493 }
1494
1495#if defined(VGO_linux)
1496 STRCASESTR(VG_Z_LIBC_SONAME, strcasestr)
1497
1498#elif defined(VGO_darwin)
1499
1500#endif
1501
1502
sewardj31b9ce12006-10-17 01:27:13 +00001503/*------------------------------------------------------------*/
dirk09beb9e2007-04-19 09:47:32 +00001504/*--- Improve definedness checking of process environment ---*/
1505/*------------------------------------------------------------*/
1506
sewardjddc00dd2007-11-27 11:42:47 +00001507#if defined(VGO_linux)
1508
sewardjbd2cff22011-08-16 21:45:28 +00001509/* If these wind up getting generated via a macro, so that multiple
1510 versions of each function exist (as above), use the _EZU variants
1511 to assign equivalance class tags. */
1512
sewardj3c944452011-09-05 20:39:57 +00001513/*---------------------- putenv ----------------------*/
1514
njne6154662009-02-10 04:23:41 +00001515int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string);
1516int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string)
dirk09beb9e2007-04-19 09:47:32 +00001517{
1518 OrigFn fn;
1519 Word result;
1520 const char* p = string;
1521 VALGRIND_GET_ORIG_FN(fn);
1522 /* Now by walking over the string we magically produce
1523 traces when hitting undefined memory. */
1524 if (p)
1525 while (*p++)
sewardj3c944452011-09-05 20:39:57 +00001526 __asm__ __volatile__("" ::: "memory");
dirk09beb9e2007-04-19 09:47:32 +00001527 CALL_FN_W_W(result, fn, string);
1528 return result;
1529}
1530
sewardj3c944452011-09-05 20:39:57 +00001531
1532/*---------------------- unsetenv ----------------------*/
1533
njne6154662009-02-10 04:23:41 +00001534int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name);
1535int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name)
dirk09beb9e2007-04-19 09:47:32 +00001536{
1537 OrigFn fn;
1538 Word result;
1539 const char* p = name;
1540 VALGRIND_GET_ORIG_FN(fn);
1541 /* Now by walking over the string we magically produce
1542 traces when hitting undefined memory. */
1543 if (p)
1544 while (*p++)
sewardj3c944452011-09-05 20:39:57 +00001545 __asm__ __volatile__("" ::: "memory");
dirk09beb9e2007-04-19 09:47:32 +00001546 CALL_FN_W_W(result, fn, name);
1547 return result;
1548}
1549
sewardj3c944452011-09-05 20:39:57 +00001550
1551/*---------------------- setenv ----------------------*/
1552
dirk09beb9e2007-04-19 09:47:32 +00001553/* setenv */
njne6154662009-02-10 04:23:41 +00001554int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001555 (const char* name, const char* value, int overwrite);
njne6154662009-02-10 04:23:41 +00001556int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001557 (const char* name, const char* value, int overwrite)
1558{
1559 OrigFn fn;
1560 Word result;
1561 const char* p;
1562 VALGRIND_GET_ORIG_FN(fn);
1563 /* Now by walking over the string we magically produce
1564 traces when hitting undefined memory. */
1565 if (name)
1566 for (p = name; *p; p++)
sewardj3c944452011-09-05 20:39:57 +00001567 __asm__ __volatile__("" ::: "memory");
dirk09beb9e2007-04-19 09:47:32 +00001568 if (value)
1569 for (p = value; *p; p++)
sewardj3c944452011-09-05 20:39:57 +00001570 __asm__ __volatile__("" ::: "memory");
dirk09beb9e2007-04-19 09:47:32 +00001571 VALGRIND_CHECK_VALUE_IS_DEFINED (overwrite);
1572 CALL_FN_W_WWW(result, fn, name, value, overwrite);
1573 return result;
1574}
1575
sewardjddc00dd2007-11-27 11:42:47 +00001576#endif /* defined(VGO_linux) */
1577
njn3e884182003-04-15 13:03:23 +00001578/*--------------------------------------------------------------------*/
njn46275862005-03-24 04:00:03 +00001579/*--- end ---*/
njn3e884182003-04-15 13:03:23 +00001580/*--------------------------------------------------------------------*/