blob: ebef4d8e43fc0716c23186dd8f544cbec4528f8b [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
sewardjdda830a2003-07-20 22:28:42 +000056/* Figure out if [dst .. dst+dstlen-1] overlaps with
57 [src .. src+srclen-1].
58 We assume that the address ranges do not wrap around
59 (which is safe since on Linux addresses >= 0xC0000000
60 are not accessible and the program will segfault in this
61 circumstance, presumably).
62*/
njn3e884182003-04-15 13:03:23 +000063static __inline__
njnc6168192004-11-29 13:54:10 +000064Bool is_overlap ( void* dst, const void* src, SizeT dstlen, SizeT srclen )
njn3e884182003-04-15 13:03:23 +000065{
sewardjdda830a2003-07-20 22:28:42 +000066 Addr loS, hiS, loD, hiD;
67
68 if (dstlen == 0 || srclen == 0)
69 return False;
70
71 loS = (Addr)src;
72 loD = (Addr)dst;
73 hiS = loS + srclen - 1;
74 hiD = loD + dstlen - 1;
75
76 /* So figure out if [loS .. hiS] overlaps with [loD .. hiD]. */
77 if (loS < loD) {
78 return !(hiS < loD);
79 }
80 else if (loD < loS) {
81 return !(hiD < loS);
82 }
83 else {
84 /* They start at same place. Since we know neither of them has
85 zero length, they must overlap. */
86 return True;
87 }
njn3e884182003-04-15 13:03:23 +000088}
89
njn1f8b3e72005-03-22 04:27:14 +000090// This is a macro rather than a function because we don't want to have an
91// extra function in the stack trace.
njn718d3b12006-12-16 00:54:12 +000092#define RECORD_OVERLAP_ERROR(s, src, dst, len) \
njn1f8b3e72005-03-22 04:27:14 +000093{ \
94 Word unused_res; \
sewardj0ec07f32006-01-12 12:32:32 +000095 VALGRIND_DO_CLIENT_REQUEST(unused_res, 0, \
96 _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR, \
njn718d3b12006-12-16 00:54:12 +000097 s, src, dst, len, 0); \
njn3e884182003-04-15 13:03:23 +000098}
99
njn16eeb4e2005-06-16 03:56:58 +0000100
101#define STRRCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000102 char* VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* s, int c ); \
103 char* VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000104 { \
105 UChar ch = (UChar)((UInt)c); \
106 UChar* p = (UChar*)s; \
107 UChar* last = NULL; \
108 while (True) { \
109 if (*p == ch) last = p; \
110 if (*p == 0) return last; \
111 p++; \
112 } \
njn3e884182003-04-15 13:03:23 +0000113 }
njn3e884182003-04-15 13:03:23 +0000114
njn16eeb4e2005-06-16 03:56:58 +0000115// Apparently rindex() is the same thing as strrchr()
njne6154662009-02-10 04:23:41 +0000116STRRCHR(VG_Z_LIBC_SONAME, strrchr)
117STRRCHR(VG_Z_LIBC_SONAME, rindex)
njnb4cfbc42009-05-04 04:20:02 +0000118#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000119STRRCHR(VG_Z_LIBC_SONAME, __GI_strrchr)
njne6154662009-02-10 04:23:41 +0000120STRRCHR(VG_Z_LD_LINUX_SO_2, rindex)
njnf76d27a2009-05-28 01:53:07 +0000121#elif defined(VGO_darwin)
122STRRCHR(VG_Z_DYLD, strrchr)
123STRRCHR(VG_Z_DYLD, rindex)
njnb4cfbc42009-05-04 04:20:02 +0000124#endif
njn16eeb4e2005-06-16 03:56:58 +0000125
126
127#define STRCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000128 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ); \
129 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000130 { \
131 UChar ch = (UChar)((UInt)c); \
132 UChar* p = (UChar*)s; \
133 while (True) { \
134 if (*p == ch) return p; \
135 if (*p == 0) return NULL; \
136 p++; \
137 } \
njn3e884182003-04-15 13:03:23 +0000138 }
njn3e884182003-04-15 13:03:23 +0000139
njn16eeb4e2005-06-16 03:56:58 +0000140// Apparently index() is the same thing as strchr()
njne6154662009-02-10 04:23:41 +0000141STRCHR(VG_Z_LIBC_SONAME, strchr)
njne6154662009-02-10 04:23:41 +0000142STRCHR(VG_Z_LIBC_SONAME, index)
njnb4cfbc42009-05-04 04:20:02 +0000143#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000144STRCHR(VG_Z_LIBC_SONAME, __GI_strchr)
njnb4cfbc42009-05-04 04:20:02 +0000145STRCHR(VG_Z_LD_LINUX_SO_2, strchr)
njne6154662009-02-10 04:23:41 +0000146STRCHR(VG_Z_LD_LINUX_SO_2, index)
njnb4cfbc42009-05-04 04:20:02 +0000147STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr)
njne6154662009-02-10 04:23:41 +0000148STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index)
njnf76d27a2009-05-28 01:53:07 +0000149#elif defined(VGO_darwin)
150STRCHR(VG_Z_DYLD, strchr)
151STRCHR(VG_Z_DYLD, index)
njnb4cfbc42009-05-04 04:20:02 +0000152#endif
njn3e884182003-04-15 13:03:23 +0000153
njn3e884182003-04-15 13:03:23 +0000154
njn16eeb4e2005-06-16 03:56:58 +0000155#define STRCAT(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000156 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ); \
157 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000158 { \
159 const Char* src_orig = src; \
160 Char* dst_orig = dst; \
161 while (*dst) dst++; \
162 while (*src) *dst++ = *src++; \
163 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000164 \
njn16eeb4e2005-06-16 03:56:58 +0000165 /* This is a bit redundant, I think; any overlap and the strcat will */ \
166 /* go forever... or until a seg fault occurs. */ \
167 if (is_overlap(dst_orig, \
168 src_orig, \
169 (Addr)dst-(Addr)dst_orig+1, \
170 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000171 RECORD_OVERLAP_ERROR("strcat", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000172 \
njn16eeb4e2005-06-16 03:56:58 +0000173 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000174 }
njn3e884182003-04-15 13:03:23 +0000175
njne6154662009-02-10 04:23:41 +0000176STRCAT(VG_Z_LIBC_SONAME, strcat)
tomd2645142009-10-29 09:27:11 +0000177#if defined(VGO_linux)
178STRCAT(VG_Z_LIBC_SONAME, __GI_strcat)
179#endif
njn16eeb4e2005-06-16 03:56:58 +0000180
181#define STRNCAT(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000182 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
183 ( char* dst, const char* src, SizeT n ); \
184 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
185 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000186 { \
187 const Char* src_orig = src; \
188 Char* dst_orig = dst; \
189 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000190 \
njn16eeb4e2005-06-16 03:56:58 +0000191 while (*dst) dst++; \
192 while (m < n && *src) { m++; *dst++ = *src++; } /* concat <= n chars */ \
193 *dst = 0; /* always add null */ \
sewardjb6c04032007-11-13 20:52:29 +0000194 \
njn16eeb4e2005-06-16 03:56:58 +0000195 /* This checks for overlap after copying, unavoidable without */ \
196 /* pre-counting lengths... should be ok */ \
197 if (is_overlap(dst_orig, \
198 src_orig, \
199 (Addr)dst-(Addr)dst_orig+1, \
200 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000201 RECORD_OVERLAP_ERROR("strncat", dst_orig, src_orig, n); \
sewardjb6c04032007-11-13 20:52:29 +0000202 \
njn16eeb4e2005-06-16 03:56:58 +0000203 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000204 }
njn3e884182003-04-15 13:03:23 +0000205
njne6154662009-02-10 04:23:41 +0000206STRNCAT(VG_Z_LIBC_SONAME, strncat)
njnf76d27a2009-05-28 01:53:07 +0000207#if defined(VGO_darwin)
208STRNCAT(VG_Z_DYLD, strncat)
209#endif
210
211
212/* Append src to dst. n is the size of dst's buffer. dst is guaranteed
213 to be nul-terminated after the copy, unless n <= strlen(dst_orig).
214 Returns min(n, strlen(dst_orig)) + strlen(src_orig).
215 Truncation occurred if retval >= n.
216*/
217#define STRLCAT(soname, fnname) \
218 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
219 ( char* dst, const char* src, SizeT n ); \
220 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
221 ( char* dst, const char* src, SizeT n ) \
222 { \
223 const Char* src_orig = src; \
224 Char* dst_orig = dst; \
225 SizeT m = 0; \
226\
227 while (m < n && *dst) { m++; dst++; } \
228 if (m < n) { \
229 /* Fill as far as dst_orig[n-2], then nul-terminate. */ \
230 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
231 *dst = 0; \
232 } else { \
233 /* No space to copy anything to dst. m == n */ \
234 } \
235 /* Finish counting min(n, strlen(dst_orig)) + strlen(src_orig) */ \
236 while (*src) { m++; src++; } \
237 /* This checks for overlap after copying, unavoidable without */ \
238 /* pre-counting lengths... should be ok */ \
239 if (is_overlap(dst_orig, \
240 src_orig, \
241 (Addr)dst-(Addr)dst_orig+1, \
242 (Addr)src-(Addr)src_orig+1)) \
243 RECORD_OVERLAP_ERROR("strlcat", dst_orig, src_orig, n); \
244\
245 return m; \
246 }
247
248#if defined(VGO_darwin)
249STRLCAT(VG_Z_LIBC_SONAME, strlcat)
250STRLCAT(VG_Z_DYLD, strlcat)
251#endif
sewardj31b9ce12006-10-17 01:27:13 +0000252
njn3e884182003-04-15 13:03:23 +0000253
njn16eeb4e2005-06-16 03:56:58 +0000254#define STRNLEN(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000255 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* str, SizeT n ); \
256 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* str, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000257 { \
258 SizeT i = 0; \
259 while (i < n && str[i] != 0) i++; \
260 return i; \
njn3e884182003-04-15 13:03:23 +0000261 }
njn3e884182003-04-15 13:03:23 +0000262
njne6154662009-02-10 04:23:41 +0000263STRNLEN(VG_Z_LIBC_SONAME, strnlen)
tomd2645142009-10-29 09:27:11 +0000264#if defined(VGO_linux)
265STRNLEN(VG_Z_LIBC_SONAME, __GI_strnlen)
266#endif
njn16eeb4e2005-06-16 03:56:58 +0000267
sewardj3ceec242003-07-30 21:24:25 +0000268
njn5ec15ed2005-08-24 19:55:51 +0000269// Note that this replacement often doesn't get used because gcc inlines
270// calls to strlen() with its own built-in version. This can be very
271// confusing if you aren't expecting it. Other small functions in this file
272// may also be inline by gcc.
njn16eeb4e2005-06-16 03:56:58 +0000273#define STRLEN(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000274 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ); \
275 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ) \
njn16eeb4e2005-06-16 03:56:58 +0000276 { \
277 SizeT i = 0; \
278 while (str[i] != 0) i++; \
279 return i; \
sewardj3ceec242003-07-30 21:24:25 +0000280 }
njn16eeb4e2005-06-16 03:56:58 +0000281
njnb4cfbc42009-05-04 04:20:02 +0000282STRLEN(VG_Z_LIBC_SONAME, strlen)
283#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000284STRLEN(VG_Z_LIBC_SONAME, __GI_strlen)
njne6154662009-02-10 04:23:41 +0000285STRLEN(VG_Z_LD_LINUX_SO_2, strlen)
286STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen)
njnb4cfbc42009-05-04 04:20:02 +0000287#endif
sewardj31b9ce12006-10-17 01:27:13 +0000288
njn16eeb4e2005-06-16 03:56:58 +0000289
290#define STRCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000291 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ); \
292 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000293 { \
294 const Char* src_orig = src; \
295 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000296 \
njn16eeb4e2005-06-16 03:56:58 +0000297 while (*src) *dst++ = *src++; \
298 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000299 \
njn16eeb4e2005-06-16 03:56:58 +0000300 /* This checks for overlap after copying, unavoidable without */ \
301 /* pre-counting length... should be ok */ \
302 if (is_overlap(dst_orig, \
303 src_orig, \
304 (Addr)dst-(Addr)dst_orig+1, \
305 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000306 RECORD_OVERLAP_ERROR("strcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000307 \
njn16eeb4e2005-06-16 03:56:58 +0000308 return dst_orig; \
309 }
310
njne6154662009-02-10 04:23:41 +0000311STRCPY(VG_Z_LIBC_SONAME, strcpy)
tomd2645142009-10-29 09:27:11 +0000312#if defined(VGO_linux)
313STRCPY(VG_Z_LIBC_SONAME, __GI_strcpy)
314#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000315STRCPY(VG_Z_DYLD, strcpy)
316#endif
njn16eeb4e2005-06-16 03:56:58 +0000317
318
319#define STRNCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000320 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) \
321 ( char* dst, const char* src, SizeT n ); \
322 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) \
323 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000324 { \
325 const Char* src_orig = src; \
326 Char* dst_orig = dst; \
327 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000328 \
njn16eeb4e2005-06-16 03:56:58 +0000329 while (m < n && *src) { m++; *dst++ = *src++; } \
330 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
331 /* but only m+1 bytes of src if terminator was found */ \
332 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
njn718d3b12006-12-16 00:54:12 +0000333 RECORD_OVERLAP_ERROR("strncpy", dst, src, n); \
njn16eeb4e2005-06-16 03:56:58 +0000334 while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */ \
335 \
336 return dst_orig; \
337 }
338
njne6154662009-02-10 04:23:41 +0000339STRNCPY(VG_Z_LIBC_SONAME, strncpy)
tomd2645142009-10-29 09:27:11 +0000340#if defined(VGO_linux)
341STRNCPY(VG_Z_LIBC_SONAME, __GI_strncpy)
342#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000343STRNCPY(VG_Z_DYLD, strncpy)
344#endif
345
346
347/* Copy up to n-1 bytes from src to dst. Then nul-terminate dst if n > 0.
348 Returns strlen(src). Does not zero-fill the remainder of dst. */
349#define STRLCPY(soname, fnname) \
350 SizeT VG_REPLACE_FUNCTION_ZU(soname, fnname) \
351 ( char* dst, const char* src, SizeT n ); \
352 SizeT VG_REPLACE_FUNCTION_ZU(soname, fnname) \
353 ( char* dst, const char* src, SizeT n ) \
354 { \
355 const char* src_orig = src; \
356 char* dst_orig = dst; \
357 SizeT m = 0; \
358\
359 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
360 /* m non-nul bytes have now been copied, and m <= n-1. */ \
361 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
362 /* but only m+1 bytes of src if terminator was found */ \
363 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
364 RECORD_OVERLAP_ERROR("strlcpy", dst, src, n); \
365 /* Nul-terminate dst. */ \
366 if (n > 0) *dst = 0; \
367 /* Finish counting strlen(src). */ \
368 while (*src) src++; \
369 return src - src_orig; \
370 }
371
372#if defined(VGO_darwin)
373STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
374STRLCPY(VG_Z_DYLD, strlcpy)
375#endif
njn16eeb4e2005-06-16 03:56:58 +0000376
377
378#define STRNCMP(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000379 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
380 ( const char* s1, const char* s2, SizeT nmax ); \
381 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
382 ( const char* s1, const char* s2, SizeT nmax ) \
njn16eeb4e2005-06-16 03:56:58 +0000383 { \
384 SizeT n = 0; \
385 while (True) { \
386 if (n >= nmax) return 0; \
387 if (*s1 == 0 && *s2 == 0) return 0; \
388 if (*s1 == 0) return -1; \
389 if (*s2 == 0) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000390 \
njn16eeb4e2005-06-16 03:56:58 +0000391 if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1; \
392 if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000393 \
njn16eeb4e2005-06-16 03:56:58 +0000394 s1++; s2++; n++; \
395 } \
396 }
397
njne6154662009-02-10 04:23:41 +0000398STRNCMP(VG_Z_LIBC_SONAME, strncmp)
tomd2645142009-10-29 09:27:11 +0000399#if defined(VGO_linux)
400STRNCMP(VG_Z_LIBC_SONAME, __GI_strncmp)
401#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000402STRNCMP(VG_Z_DYLD, strncmp)
403#endif
njn16eeb4e2005-06-16 03:56:58 +0000404
405
tomce6d0ac2010-11-12 10:03:13 +0000406#define STRCASECMP(soname, fnname) \
407 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
408 ( const char* s1, const char* s2 ); \
409 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
410 ( const char* s1, const char* s2 ) \
411 { \
tome03c8c42010-11-12 10:40:20 +0000412 extern int tolower(int); \
tomce6d0ac2010-11-12 10:03:13 +0000413 register unsigned char c1; \
414 register unsigned char c2; \
415 while (True) { \
416 c1 = tolower(*(unsigned char *)s1); \
417 c2 = tolower(*(unsigned char *)s2); \
418 if (c1 != c2) break; \
419 if (c1 == 0) break; \
420 s1++; s2++; \
421 } \
422 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
423 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
424 return 0; \
425 }
426
427STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp)
428#if defined(VGO_linux)
429STRCASECMP(VG_Z_LIBC_SONAME, __GI_strcasecmp)
430#endif
431
432
433#define STRNCASECMP(soname, fnname) \
434 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
435 ( const char* s1, const char* s2, SizeT nmax ); \
436 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
437 ( const char* s1, const char* s2, SizeT nmax ) \
438 { \
tome03c8c42010-11-12 10:40:20 +0000439 extern int tolower(int); \
tomce6d0ac2010-11-12 10:03:13 +0000440 SizeT n = 0; \
441 while (True) { \
442 if (n >= nmax) return 0; \
443 if (*s1 == 0 && *s2 == 0) return 0; \
444 if (*s1 == 0) return -1; \
445 if (*s2 == 0) return 1; \
446 \
447 if (tolower(*(unsigned char*)s1) < tolower(*(unsigned char*)s2)) return -1; \
448 if (tolower(*(unsigned char*)s1) > tolower(*(unsigned char*)s2)) return 1; \
449 \
450 s1++; s2++; n++; \
451 } \
452 }
453
454STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp)
455#if defined(VGO_linux)
456STRNCASECMP(VG_Z_LIBC_SONAME, __GI_strncasecmp)
457#elif defined(VGO_darwin)
458STRNCASECMP(VG_Z_DYLD, strncasecmp)
459#endif
460
461
tomce6d0ac2010-11-12 10:03:13 +0000462#define STRCASECMP_L(soname, fnname) \
463 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000464 ( const char* s1, const char* s2, void* locale ); \
tomce6d0ac2010-11-12 10:03:13 +0000465 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000466 ( const char* s1, const char* s2, void* locale ) \
tomce6d0ac2010-11-12 10:03:13 +0000467 { \
tome03c8c42010-11-12 10:40:20 +0000468 extern int tolower_l(int, void*) __attribute__((weak)); \
tomce6d0ac2010-11-12 10:03:13 +0000469 register unsigned char c1; \
470 register unsigned char c2; \
471 while (True) { \
472 c1 = tolower_l(*(unsigned char *)s1, locale); \
473 c2 = tolower_l(*(unsigned char *)s2, locale); \
474 if (c1 != c2) break; \
475 if (c1 == 0) break; \
476 s1++; s2++; \
477 } \
478 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
479 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
480 return 0; \
481 }
482
483STRCASECMP_L(VG_Z_LIBC_SONAME, strcasecmp_l)
484#if defined(VGO_linux)
485STRCASECMP_L(VG_Z_LIBC_SONAME, __GI_strcasecmp_l)
486#endif
487
488
489#define STRNCASECMP_L(soname, fnname) \
490 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000491 ( const char* s1, const char* s2, SizeT nmax, void* locale ); \
tomce6d0ac2010-11-12 10:03:13 +0000492 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000493 ( const char* s1, const char* s2, SizeT nmax, void* locale ) \
tomce6d0ac2010-11-12 10:03:13 +0000494 { \
tome03c8c42010-11-12 10:40:20 +0000495 extern int tolower_l(int, void*) __attribute__((weak)); \
tomce6d0ac2010-11-12 10:03:13 +0000496 SizeT n = 0; \
497 while (True) { \
498 if (n >= nmax) return 0; \
499 if (*s1 == 0 && *s2 == 0) return 0; \
500 if (*s1 == 0) return -1; \
501 if (*s2 == 0) return 1; \
502 \
503 if (tolower_l(*(unsigned char*)s1, locale) < tolower_l(*(unsigned char*)s2, locale)) return -1; \
504 if (tolower_l(*(unsigned char*)s1, locale) > tolower_l(*(unsigned char*)s2, locale)) return 1; \
505 \
506 s1++; s2++; n++; \
507 } \
508 }
509
510STRNCASECMP_L(VG_Z_LIBC_SONAME, strncasecmp_l)
511#if defined(VGO_linux)
512STRNCASECMP_L(VG_Z_LIBC_SONAME, __GI_strncasecmp_l)
513#elif defined(VGO_darwin)
514STRNCASECMP_L(VG_Z_DYLD, strncasecmp_l)
515#endif
516
517
njn16eeb4e2005-06-16 03:56:58 +0000518#define STRCMP(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000519 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
520 ( const char* s1, const char* s2 ); \
521 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
522 ( const char* s1, const char* s2 ) \
njn16eeb4e2005-06-16 03:56:58 +0000523 { \
524 register unsigned char c1; \
525 register unsigned char c2; \
526 while (True) { \
527 c1 = *(unsigned char *)s1; \
528 c2 = *(unsigned char *)s2; \
529 if (c1 != c2) break; \
530 if (c1 == 0) break; \
531 s1++; s2++; \
532 } \
533 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
534 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
535 return 0; \
536 }
537
njne6154662009-02-10 04:23:41 +0000538STRCMP(VG_Z_LIBC_SONAME, strcmp)
njnb4cfbc42009-05-04 04:20:02 +0000539#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000540STRCMP(VG_Z_LIBC_SONAME, __GI_strcmp)
njne6154662009-02-10 04:23:41 +0000541STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp)
542STRCMP(VG_Z_LD64_SO_1, strcmp)
njnb4cfbc42009-05-04 04:20:02 +0000543#endif
njn16eeb4e2005-06-16 03:56:58 +0000544
545
546#define MEMCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000547 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const void *s, int c, SizeT n); \
548 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const void *s, int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000549 { \
550 SizeT i; \
551 UChar c0 = (UChar)c; \
552 UChar* p = (UChar*)s; \
553 for (i = 0; i < n; i++) \
554 if (p[i] == c0) return (void*)(&p[i]); \
555 return NULL; \
556 }
557
njne6154662009-02-10 04:23:41 +0000558MEMCHR(VG_Z_LIBC_SONAME, memchr)
njnf76d27a2009-05-28 01:53:07 +0000559#if defined(VGO_darwin)
560MEMCHR(VG_Z_DYLD, memchr)
561#endif
njn16eeb4e2005-06-16 03:56:58 +0000562
563
564#define MEMCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000565 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
566 ( void *dst, const void *src, SizeT len ); \
567 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
568 ( void *dst, const void *src, SizeT len ) \
njn16eeb4e2005-06-16 03:56:58 +0000569 { \
njn16eeb4e2005-06-16 03:56:58 +0000570 if (is_overlap(dst, src, len, len)) \
njn718d3b12006-12-16 00:54:12 +0000571 RECORD_OVERLAP_ERROR("memcpy", dst, src, len); \
sewardjb6c04032007-11-13 20:52:29 +0000572 \
sewardj7b4e00b2010-08-24 09:05:52 +0000573 const Addr WS = sizeof(UWord); /* 8 or 4 */ \
574 const Addr WM = WS - 1; /* 7 or 3 */ \
575 \
576 if (dst < src) { \
577 \
578 /* Copying backwards. */ \
579 SizeT n = len; \
580 Addr d = (Addr)dst; \
581 Addr s = (Addr)src; \
582 \
583 if (((s^d) & WM) == 0) { \
584 /* s and d have same UWord alignment. */ \
585 /* Pull up to a UWord boundary. */ \
586 while ((s & WM) != 0 && n >= 1) \
587 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
588 /* Copy UWords. */ \
589 while (n >= WS) \
590 { *(UWord*)d = *(UWord*)s; s += WS; d += WS; n -= WS; } \
591 if (n == 0) \
592 return dst; \
njn16eeb4e2005-06-16 03:56:58 +0000593 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000594 if (((s|d) & 1) == 0) { \
595 /* Both are 16-aligned; copy what we can thusly. */ \
596 while (n >= 2) \
597 { *(UShort*)d = *(UShort*)s; s += 2; d += 2; n -= 2; } \
njn16eeb4e2005-06-16 03:56:58 +0000598 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000599 /* Copy leftovers, or everything if misaligned. */ \
600 while (n >= 1) \
601 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
602 \
603 } else if (dst > src) { \
604 \
605 SizeT n = len; \
606 Addr d = ((Addr)dst) + n; \
607 Addr s = ((Addr)src) + n; \
608 \
609 /* Copying forwards. */ \
610 if (((s^d) & WM) == 0) { \
611 /* s and d have same UWord alignment. */ \
612 /* Back down to a UWord boundary. */ \
613 while ((s & WM) != 0 && n >= 1) \
614 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
615 /* Copy UWords. */ \
616 while (n >= WS) \
617 { s -= WS; d -= WS; *(UWord*)d = *(UWord*)s; n -= WS; } \
618 if (n == 0) \
619 return dst; \
njn16eeb4e2005-06-16 03:56:58 +0000620 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000621 if (((s|d) & 1) == 0) { \
622 /* Both are 16-aligned; copy what we can thusly. */ \
623 while (n >= 2) \
624 { s -= 2; d -= 2; *(UShort*)d = *(UShort*)s; n -= 2; } \
njn16eeb4e2005-06-16 03:56:58 +0000625 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000626 /* Copy leftovers, or everything if misaligned. */ \
627 while (n >= 1) \
628 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
629 \
njn16eeb4e2005-06-16 03:56:58 +0000630 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000631 \
njn16eeb4e2005-06-16 03:56:58 +0000632 return dst; \
633 }
634
njne6154662009-02-10 04:23:41 +0000635MEMCPY(VG_Z_LIBC_SONAME, memcpy)
njnb4cfbc42009-05-04 04:20:02 +0000636#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +0000637MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */
638MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */
njnf76d27a2009-05-28 01:53:07 +0000639#elif defined(VGO_darwin)
640MEMCPY(VG_Z_DYLD, memcpy)
njnb4cfbc42009-05-04 04:20:02 +0000641#endif
sewardjf0b34322007-01-16 21:42:28 +0000642/* icc9 blats these around all over the place. Not only in the main
643 executable but various .so's. They are highly tuned and read
644 memory beyond the source boundary (although work correctly and
645 never go across page boundaries), so give errors when run natively,
646 at least for misaligned source arg. Just intercepting in the exe
647 only until we understand more about the problem. See
648 http://bugs.kde.org/show_bug.cgi?id=139776
649 */
650MEMCPY(NONE, _intel_fast_memcpy)
sewardj31b9ce12006-10-17 01:27:13 +0000651
njn16eeb4e2005-06-16 03:56:58 +0000652
653#define MEMCMP(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000654 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
655 ( const void *s1V, const void *s2V, SizeT n ); \
656 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
657 ( const void *s1V, const void *s2V, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000658 { \
659 int res; \
660 unsigned char a0; \
661 unsigned char b0; \
662 unsigned char* s1 = (unsigned char*)s1V; \
663 unsigned char* s2 = (unsigned char*)s2V; \
sewardjb6c04032007-11-13 20:52:29 +0000664 \
njn16eeb4e2005-06-16 03:56:58 +0000665 while (n != 0) { \
666 a0 = s1[0]; \
667 b0 = s2[0]; \
668 s1 += 1; \
669 s2 += 1; \
670 res = ((int)a0) - ((int)b0); \
671 if (res != 0) \
672 return res; \
673 n -= 1; \
674 } \
675 return 0; \
676 }
677
njne6154662009-02-10 04:23:41 +0000678MEMCMP(VG_Z_LIBC_SONAME, memcmp)
679MEMCMP(VG_Z_LIBC_SONAME, bcmp)
njnb4cfbc42009-05-04 04:20:02 +0000680#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +0000681MEMCMP(VG_Z_LD_SO_1, bcmp)
njnf76d27a2009-05-28 01:53:07 +0000682#elif defined(VGO_darwin)
683MEMCMP(VG_Z_DYLD, memcmp)
684MEMCMP(VG_Z_DYLD, bcmp)
njnb4cfbc42009-05-04 04:20:02 +0000685#endif
njn3e884182003-04-15 13:03:23 +0000686
jseward0845ef82003-12-22 22:31:27 +0000687
688/* Copy SRC to DEST, returning the address of the terminating '\0' in
689 DEST. (minor variant of strcpy) */
njn16eeb4e2005-06-16 03:56:58 +0000690#define STPCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000691 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ); \
692 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000693 { \
694 const Char* src_orig = src; \
695 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000696 \
njn16eeb4e2005-06-16 03:56:58 +0000697 while (*src) *dst++ = *src++; \
698 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000699 \
njn16eeb4e2005-06-16 03:56:58 +0000700 /* This checks for overlap after copying, unavoidable without */ \
701 /* pre-counting length... should be ok */ \
702 if (is_overlap(dst_orig, \
703 src_orig, \
704 (Addr)dst-(Addr)dst_orig+1, \
705 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000706 RECORD_OVERLAP_ERROR("stpcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000707 \
njn16eeb4e2005-06-16 03:56:58 +0000708 return dst; \
sewardj44e495f2005-05-12 17:58:28 +0000709 }
njn16eeb4e2005-06-16 03:56:58 +0000710
njne6154662009-02-10 04:23:41 +0000711STPCPY(VG_Z_LIBC_SONAME, stpcpy)
njnb4cfbc42009-05-04 04:20:02 +0000712#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000713STPCPY(VG_Z_LIBC_SONAME, __GI_stpcpy)
njne6154662009-02-10 04:23:41 +0000714STPCPY(VG_Z_LD_LINUX_SO_2, stpcpy)
715STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy)
njnf76d27a2009-05-28 01:53:07 +0000716#elif defined(VGO_darwin)
717STPCPY(VG_Z_DYLD, stpcpy)
njnb4cfbc42009-05-04 04:20:02 +0000718#endif
719
njn16eeb4e2005-06-16 03:56:58 +0000720
721#define MEMSET(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000722 void* VG_REPLACE_FUNCTION_ZU(soname,fnname)(void *s, Int c, SizeT n); \
723 void* VG_REPLACE_FUNCTION_ZU(soname,fnname)(void *s, Int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000724 { \
sewardj7b4e00b2010-08-24 09:05:52 +0000725 Addr a = (Addr)s; \
726 UInt c4 = (c & 0xFF); \
727 c4 = (c4 << 8) | c4; \
728 c4 = (c4 << 16) | c4; \
729 while ((a & 3) != 0 && n >= 1) \
730 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
731 while (n >= 4) \
732 { *(UInt*)a = c4; a += 4; n -= 4; } \
733 while (n >= 1) \
734 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
njn16eeb4e2005-06-16 03:56:58 +0000735 return s; \
sewardj44e495f2005-05-12 17:58:28 +0000736 }
njn16eeb4e2005-06-16 03:56:58 +0000737
njne6154662009-02-10 04:23:41 +0000738MEMSET(VG_Z_LIBC_SONAME, memset)
njnf76d27a2009-05-28 01:53:07 +0000739#if defined(VGO_darwin)
740MEMSET(VG_Z_DYLD, memset)
741#endif
njn16eeb4e2005-06-16 03:56:58 +0000742
743
744#define MEMMOVE(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000745 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
746 (void *dstV, const void *srcV, SizeT n); \
747 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
748 (void *dstV, const void *srcV, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000749 { \
750 SizeT i; \
751 Char* dst = (Char*)dstV; \
752 Char* src = (Char*)srcV; \
753 if (dst < src) { \
754 for (i = 0; i < n; i++) \
755 dst[i] = src[i]; \
756 } \
757 else \
758 if (dst > src) { \
759 for (i = 0; i < n; i++) \
760 dst[n-i-1] = src[n-i-1]; \
761 } \
762 return dst; \
763 }
764
njne6154662009-02-10 04:23:41 +0000765MEMMOVE(VG_Z_LIBC_SONAME, memmove)
njnf76d27a2009-05-28 01:53:07 +0000766#if defined(VGO_darwin)
767MEMMOVE(VG_Z_DYLD, memmove)
768#endif
769
770
771#define BCOPY(soname, fnname) \
772 void VG_REPLACE_FUNCTION_ZU(soname,fnname) \
773 (const void *srcV, void *dstV, SizeT n); \
774 void VG_REPLACE_FUNCTION_ZU(soname,fnname) \
775 (const void *srcV, void *dstV, SizeT n) \
776 { \
777 SizeT i; \
778 Char* dst = (Char*)dstV; \
779 Char* src = (Char*)srcV; \
780 if (dst < src) { \
781 for (i = 0; i < n; i++) \
782 dst[i] = src[i]; \
783 } \
784 else \
785 if (dst > src) { \
786 for (i = 0; i < n; i++) \
787 dst[n-i-1] = src[n-i-1]; \
788 } \
789 }
790
791#if defined(VGO_darwin)
792BCOPY(VG_Z_LIBC_SONAME, bcopy)
793BCOPY(VG_Z_DYLD, bcopy)
794#endif
sewardj44e495f2005-05-12 17:58:28 +0000795
jseward0845ef82003-12-22 22:31:27 +0000796
sewardj24cb2172007-02-23 09:03:26 +0000797/* glibc 2.5 variant of memmove which checks the dest is big enough.
798 There is no specific part of glibc that this is copied from. */
799#define GLIBC25___MEMMOVE_CHK(soname, fnname) \
800 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
801 (void *dstV, const void *srcV, SizeT n, SizeT destlen); \
802 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
803 (void *dstV, const void *srcV, SizeT n, SizeT destlen) \
804 { \
805 extern void _exit(int status); \
806 SizeT i; \
807 Char* dst = (Char*)dstV; \
808 Char* src = (Char*)srcV; \
809 if (destlen < n) \
810 goto badness; \
811 if (dst < src) { \
812 for (i = 0; i < n; i++) \
813 dst[i] = src[i]; \
814 } \
815 else \
816 if (dst > src) { \
817 for (i = 0; i < n; i++) \
818 dst[n-i-1] = src[n-i-1]; \
819 } \
820 return dst; \
821 badness: \
822 VALGRIND_PRINTF_BACKTRACE( \
823 "*** memmove_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000824 "program terminated\n"); \
sewardj24cb2172007-02-23 09:03:26 +0000825 _exit(127); \
sewardjc271ec82007-02-27 22:36:14 +0000826 /*NOTREACHED*/ \
827 return NULL; \
sewardj24cb2172007-02-23 09:03:26 +0000828 }
829
njne6154662009-02-10 04:23:41 +0000830GLIBC25___MEMMOVE_CHK(VG_Z_LIBC_SONAME, __memmove_chk)
sewardj24cb2172007-02-23 09:03:26 +0000831
832
sewardj4e9a4b62004-11-23 00:20:17 +0000833/* Find the first occurrence of C in S or the final NUL byte. */
njn16eeb4e2005-06-16 03:56:58 +0000834#define GLIBC232_STRCHRNUL(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000835 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in); \
836 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +0000837 { \
838 unsigned char c = (unsigned char) c_in; \
839 unsigned char* char_ptr = (unsigned char *)s; \
840 while (1) { \
841 if (*char_ptr == 0) return char_ptr; \
842 if (*char_ptr == c) return char_ptr; \
843 char_ptr++; \
844 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000845 }
njn16eeb4e2005-06-16 03:56:58 +0000846
njne6154662009-02-10 04:23:41 +0000847GLIBC232_STRCHRNUL(VG_Z_LIBC_SONAME, strchrnul)
sewardj4e9a4b62004-11-23 00:20:17 +0000848
849
850/* Find the first occurrence of C in S. */
njn16eeb4e2005-06-16 03:56:58 +0000851#define GLIBC232_RAWMEMCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000852 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in); \
853 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +0000854 { \
855 unsigned char c = (unsigned char) c_in; \
856 unsigned char* char_ptr = (unsigned char *)s; \
857 while (1) { \
858 if (*char_ptr == c) return char_ptr; \
859 char_ptr++; \
860 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000861 }
njn16eeb4e2005-06-16 03:56:58 +0000862
njne6154662009-02-10 04:23:41 +0000863GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, rawmemchr)
tomd2645142009-10-29 09:27:11 +0000864#if defined (VGO_linux)
865GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, __GI___rawmemchr)
866#endif
sewardj4e9a4b62004-11-23 00:20:17 +0000867
sewardjdc5d8322007-01-28 06:32:01 +0000868/* glibc variant of strcpy that checks the dest is big enough.
869 Copied from glibc-2.5/debug/test-strcpy_chk.c. */
sewardj620e5262006-12-31 00:22:30 +0000870#define GLIBC25___STRCPY_CHK(soname,fnname) \
871 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
872 (char* dst, const char* src, SizeT len); \
873 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
874 (char* dst, const char* src, SizeT len) \
875 { \
876 extern void _exit(int status); \
877 char* ret = dst; \
878 if (! len) \
879 goto badness; \
880 while ((*dst++ = *src++) != '\0') \
881 if (--len == 0) \
882 goto badness; \
883 return ret; \
884 badness: \
885 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +0000886 "*** strcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000887 "program terminated\n"); \
sewardj620e5262006-12-31 00:22:30 +0000888 _exit(127); \
889 /*NOTREACHED*/ \
890 return NULL; \
891 }
892
njne6154662009-02-10 04:23:41 +0000893GLIBC25___STRCPY_CHK(VG_Z_LIBC_SONAME, __strcpy_chk)
sewardj620e5262006-12-31 00:22:30 +0000894
895
sewardjdc5d8322007-01-28 06:32:01 +0000896/* glibc variant of stpcpy that checks the dest is big enough.
897 Copied from glibc-2.5/debug/test-stpcpy_chk.c. */
sewardjb8d03852007-01-27 00:49:44 +0000898#define GLIBC25___STPCPY_CHK(soname,fnname) \
899 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
900 (char* dst, const char* src, SizeT len); \
901 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
902 (char* dst, const char* src, SizeT len) \
903 { \
904 extern void _exit(int status); \
sewardjdc5d8322007-01-28 06:32:01 +0000905 if (! len) \
906 goto badness; \
907 while ((*dst++ = *src++) != '\0') \
908 if (--len == 0) \
sewardjb8d03852007-01-27 00:49:44 +0000909 goto badness; \
sewardjb8d03852007-01-27 00:49:44 +0000910 return dst - 1; \
911 badness: \
912 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +0000913 "*** stpcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000914 "program terminated\n"); \
sewardjb8d03852007-01-27 00:49:44 +0000915 _exit(127); \
916 /*NOTREACHED*/ \
917 return NULL; \
918 }
919
njne6154662009-02-10 04:23:41 +0000920GLIBC25___STPCPY_CHK(VG_Z_LIBC_SONAME, __stpcpy_chk)
sewardjb8d03852007-01-27 00:49:44 +0000921
922
sewardj841b72d2006-12-31 18:55:56 +0000923/* mempcpy */
924#define GLIBC25_MEMPCPY(soname, fnname) \
925 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
926 ( void *dst, const void *src, SizeT len ); \
927 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
928 ( void *dst, const void *src, SizeT len ) \
929 { \
930 register char *d; \
931 register char *s; \
932 SizeT len_saved = len; \
933 \
934 if (len == 0) \
935 return dst; \
936 \
937 if (is_overlap(dst, src, len, len)) \
938 RECORD_OVERLAP_ERROR("mempcpy", dst, src, len); \
939 \
940 if ( dst > src ) { \
941 d = (char *)dst + len - 1; \
942 s = (char *)src + len - 1; \
943 while ( len-- ) { \
944 *d-- = *s--; \
945 } \
946 } else if ( dst < src ) { \
947 d = (char *)dst; \
948 s = (char *)src; \
949 while ( len-- ) { \
950 *d++ = *s++; \
951 } \
952 } \
953 return (void*)( ((char*)dst) + len_saved ); \
954 }
955
njne6154662009-02-10 04:23:41 +0000956GLIBC25_MEMPCPY(VG_Z_LIBC_SONAME, mempcpy)
njnb4cfbc42009-05-04 04:20:02 +0000957#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +0000958GLIBC25_MEMPCPY(VG_Z_LD_SO_1, mempcpy) /* ld.so.1 */
njnb4cfbc42009-05-04 04:20:02 +0000959#endif
sewardj841b72d2006-12-31 18:55:56 +0000960
961
sewardjb6c04032007-11-13 20:52:29 +0000962#define GLIBC26___MEMCPY_CHK(soname, fnname) \
963 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
964 (void* dst, const void* src, SizeT len, SizeT dstlen ); \
965 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
966 (void* dst, const void* src, SizeT len, SizeT dstlen ) \
967 { \
968 extern void _exit(int status); \
969 register char *d; \
970 register char *s; \
971 \
972 if (dstlen < len) goto badness; \
973 \
974 if (len == 0) \
975 return dst; \
976 \
977 if (is_overlap(dst, src, len, len)) \
978 RECORD_OVERLAP_ERROR("memcpy_chk", dst, src, len); \
979 \
980 if ( dst > src ) { \
981 d = (char *)dst + len - 1; \
982 s = (char *)src + len - 1; \
983 while ( len-- ) { \
984 *d-- = *s--; \
985 } \
986 } else if ( dst < src ) { \
987 d = (char *)dst; \
988 s = (char *)src; \
989 while ( len-- ) { \
990 *d++ = *s++; \
991 } \
992 } \
993 return dst; \
994 badness: \
995 VALGRIND_PRINTF_BACKTRACE( \
996 "*** memcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000997 "program terminated\n"); \
sewardjb6c04032007-11-13 20:52:29 +0000998 _exit(127); \
999 /*NOTREACHED*/ \
1000 return NULL; \
1001 }
1002
njne6154662009-02-10 04:23:41 +00001003GLIBC26___MEMCPY_CHK(VG_Z_LIBC_SONAME, __memcpy_chk)
sewardjb6c04032007-11-13 20:52:29 +00001004
1005
sewardja77687c2010-08-19 13:22:34 +00001006#define STRSTR(soname, fnname) \
1007 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1008 (void* haystack, void* needle); \
1009 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1010 (void* haystack, void* needle) \
1011 { \
1012 UChar* h = (UChar*)haystack; \
1013 UChar* n = (UChar*)needle; \
1014 \
1015 /* find the length of n, not including terminating zero */ \
1016 UWord nlen = 0; \
1017 while (n[nlen]) nlen++; \
1018 \
1019 /* if n is the empty string, match immediately. */ \
1020 if (nlen == 0) return h; \
1021 \
1022 /* assert(nlen >= 1); */ \
1023 UChar n0 = n[0]; \
1024 \
1025 while (1) { \
1026 UChar hh = *h; \
1027 if (hh == 0) return NULL; \
1028 if (hh != n0) { h++; continue; } \
1029 \
1030 UWord i; \
1031 for (i = 0; i < nlen; i++) { \
1032 if (n[i] != h[i]) \
1033 break; \
1034 } \
1035 /* assert(i >= 0 && i <= nlen); */ \
1036 if (i == nlen) \
1037 return h; \
1038 \
1039 h++; \
1040 } \
1041 }
1042
1043#if defined(VGO_linux)
1044STRSTR(VG_Z_LIBC_SONAME, strstr)
1045#endif
1046
1047
1048#define STRPBRK(soname, fnname) \
1049 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1050 (void* sV, void* acceptV); \
1051 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1052 (void* sV, void* acceptV) \
1053 { \
1054 UChar* s = (UChar*)sV; \
1055 UChar* accept = (UChar*)acceptV; \
1056 \
1057 /* find the length of 'accept', not including terminating zero */ \
1058 UWord nacc = 0; \
1059 while (accept[nacc]) nacc++; \
1060 \
1061 /* if n is the empty string, fail immediately. */ \
1062 if (nacc == 0) return NULL; \
1063 \
1064 /* assert(nacc >= 1); */ \
1065 while (1) { \
1066 UWord i; \
1067 UChar sc = *s; \
1068 if (sc == 0) \
1069 break; \
1070 for (i = 0; i < nacc; i++) { \
1071 if (sc == accept[i]) \
1072 return s; \
1073 } \
1074 s++; \
1075 } \
1076 \
1077 return NULL; \
1078 }
1079
1080#if defined(VGO_linux)
1081STRPBRK(VG_Z_LIBC_SONAME, strpbrk)
1082#endif
1083
1084
1085#define STRCSPN(soname, fnname) \
1086 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1087 (void* sV, void* rejectV); \
1088 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1089 (void* sV, void* rejectV) \
1090 { \
1091 UChar* s = (UChar*)sV; \
1092 UChar* reject = (UChar*)rejectV; \
1093 \
1094 /* find the length of 'reject', not including terminating zero */ \
1095 UWord nrej = 0; \
1096 while (reject[nrej]) nrej++; \
1097 \
1098 UWord len = 0; \
1099 while (1) { \
1100 UWord i; \
1101 UChar sc = *s; \
1102 if (sc == 0) \
1103 break; \
1104 for (i = 0; i < nrej; i++) { \
1105 if (sc == reject[i]) \
1106 break; \
1107 } \
1108 /* assert(i >= 0 && i <= nrej); */ \
1109 if (i < nrej) \
1110 break; \
1111 s++; \
1112 len++; \
1113 } \
1114 \
1115 return len; \
1116 }
1117
1118#if defined(VGO_linux)
1119STRCSPN(VG_Z_LIBC_SONAME, strcspn)
1120#endif
1121
1122
sewardjba189352010-08-20 18:24:16 +00001123// And here's a validated strspn replacement, should it
1124// become necessary.
1125//UWord mystrspn( UChar* s, UChar* accept )
1126//{
1127// /* find the length of 'accept', not including terminating zero */
1128// UWord nacc = 0;
1129// while (accept[nacc]) nacc++;
1130// if (nacc == 0) return 0;
1131//
1132// UWord len = 0;
1133// while (1) {
1134// UWord i;
1135// UChar sc = *s;
1136// if (sc == 0)
1137// break;
1138// for (i = 0; i < nacc; i++) {
1139// if (sc == accept[i])
1140// break;
1141// }
1142// assert(i >= 0 && i <= nacc);
1143// if (i == nacc)
1144// break;
1145// s++;
1146// len++;
1147// }
1148//
1149// return len;
1150//}
1151
1152
sewardj31b9ce12006-10-17 01:27:13 +00001153/*------------------------------------------------------------*/
dirk09beb9e2007-04-19 09:47:32 +00001154/*--- Improve definedness checking of process environment ---*/
1155/*------------------------------------------------------------*/
1156
sewardjddc00dd2007-11-27 11:42:47 +00001157#if defined(VGO_linux)
1158
dirk09beb9e2007-04-19 09:47:32 +00001159/* putenv */
njne6154662009-02-10 04:23:41 +00001160int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string);
1161int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string)
dirk09beb9e2007-04-19 09:47:32 +00001162{
1163 OrigFn fn;
1164 Word result;
1165 const char* p = string;
1166 VALGRIND_GET_ORIG_FN(fn);
1167 /* Now by walking over the string we magically produce
1168 traces when hitting undefined memory. */
1169 if (p)
1170 while (*p++)
1171 ;
1172 CALL_FN_W_W(result, fn, string);
1173 return result;
1174}
1175
1176/* unsetenv */
njne6154662009-02-10 04:23:41 +00001177int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name);
1178int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name)
dirk09beb9e2007-04-19 09:47:32 +00001179{
1180 OrigFn fn;
1181 Word result;
1182 const char* p = name;
1183 VALGRIND_GET_ORIG_FN(fn);
1184 /* Now by walking over the string we magically produce
1185 traces when hitting undefined memory. */
1186 if (p)
1187 while (*p++)
1188 ;
1189 CALL_FN_W_W(result, fn, name);
1190 return result;
1191}
1192
1193/* setenv */
njne6154662009-02-10 04:23:41 +00001194int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001195 (const char* name, const char* value, int overwrite);
njne6154662009-02-10 04:23:41 +00001196int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001197 (const char* name, const char* value, int overwrite)
1198{
1199 OrigFn fn;
1200 Word result;
1201 const char* p;
1202 VALGRIND_GET_ORIG_FN(fn);
1203 /* Now by walking over the string we magically produce
1204 traces when hitting undefined memory. */
1205 if (name)
1206 for (p = name; *p; p++)
1207 ;
1208 if (value)
1209 for (p = value; *p; p++)
1210 ;
1211 VALGRIND_CHECK_VALUE_IS_DEFINED (overwrite);
1212 CALL_FN_W_WWW(result, fn, name, value, overwrite);
1213 return result;
1214}
1215
sewardjddc00dd2007-11-27 11:42:47 +00001216#endif /* defined(VGO_linux) */
1217
1218
dirk09beb9e2007-04-19 09:47:32 +00001219/*------------------------------------------------------------*/
sewardj31b9ce12006-10-17 01:27:13 +00001220/*--- AIX stuff only after this point ---*/
1221/*------------------------------------------------------------*/
1222
sewardjddc00dd2007-11-27 11:42:47 +00001223/* Generate replacements for strcat, strncat, strcpy, strncpy, strcmp
sewardj31b9ce12006-10-17 01:27:13 +00001224 in the given soname. */
sewardjddc00dd2007-11-27 11:42:47 +00001225#define Str5FNs(_soname) \
sewardj31b9ce12006-10-17 01:27:13 +00001226 STRCAT(_soname, strcat) \
1227 STRNCAT(_soname, strncat) \
1228 STRCPY(_soname, strcpy) \
sewardjddc00dd2007-11-27 11:42:47 +00001229 STRNCPY(_soname, strncpy) \
1230 STRCMP(_soname, strcmp)
sewardj31b9ce12006-10-17 01:27:13 +00001231
1232#if defined(VGP_ppc32_aix5)
sewardjddc00dd2007-11-27 11:42:47 +00001233Str5FNs(NONE) /* in main exe */
1234Str5FNs(libCZdaZLshrcoreZdoZR) /* libC.a(shrcore.o) */
1235Str5FNs(libX11ZdaZLshr4ZdoZR) /* libX11.a(shr4.o) */
1236Str5FNs(libXmZdaZLshrZaZdoZR) /* libXm.a(shr*.o) */
1237Str5FNs(libXtZdaZLshr4ZdoZR) /* libXt.a(shr4.o) */
1238Str5FNs(libppeZurZdaZLdynamicZdoZR) /* libppe_r.a(dynamic.o) */
1239Str5FNs(libodmZdaZLshrZdoZR) /* libodm.a(shr.o) */
1240Str5FNs(libmpiZurZdaZLmpicoreZurZdoZR) /* libmpi_r.a(mpicore_r.o) */
1241Str5FNs(libmpiZurZdaZLmpipoeZurZdoZR) /* libmpi_r.a(mpipoe_r.o) */
1242Str5FNs(libmpiZurZdaZLmpciZurZdoZR) /* libmpi_r.a(mpci_r.o) */
1243Str5FNs(libslurmZdso) /* libslurm.so */
1244Str5FNs(libglibZdso) /* libglib.so */
1245Str5FNs(libIMZdaZLshrZdoZR) /* libIM.a(shr.o) */
1246Str5FNs(libiconvZdaZLshr4ZdoZR) /* libiconv.a(shr4.o) */
1247Str5FNs(libGLZdaZLshrZdoZR) /* libGL.a(shr.o) */
1248Str5FNs(libgdkZdso) /* libgdk.so */
1249Str5FNs(libcursesZdaZLshr42ZdoZR) /* libcurses.a(shr42.o) */
1250Str5FNs(libqtZda) /* libqt.a */
sewardjfd4b6f42007-11-29 03:08:32 +00001251Str5FNs(ZaZLlibglibZhZaZdsoZaZR) /* *(libglib-*.so*) */
1252Str5FNs(ZaZLlibfontconfigZdsoZaZR) /* *(libfontconfig.so*) */
1253Str5FNs(libQtZaa) /* libQt*.a */
sewardj31b9ce12006-10-17 01:27:13 +00001254#endif
1255#if defined(VGP_ppc64_aix5)
sewardjddc00dd2007-11-27 11:42:47 +00001256Str5FNs(NONE) /* in main exe */
1257Str5FNs(libX11ZdaZLshrZu64ZdoZR) /* libX11.a(shr_64.o) */
1258Str5FNs(libiconvZdaZLshr4Zu64ZdoZR) /* libiconv.a(shr4_64.o) */
1259Str5FNs(libGLZdaZLshrZu64ZdoZR) /* libGL.a(shr_64.o) */
1260Str5FNs(libppeZurZdaZLdynamic64ZdoZR) /* libppe_r.a(dynamic64.o) */
1261Str5FNs(libodmZdaZLshrZu64ZdoZR) /* libodm.a(shr_64.o) */
1262Str5FNs(libmpiZurZdaZLmpicore64ZurZdoZR) /* libmpi_r.a(mpicore64_r.o) */
1263Str5FNs(libmpiZurZdaZLmpipoe64ZurZdoZR) /* libmpi_r.a(mpipoe64_r.o) */
1264Str5FNs(libCZdaZLshrcoreZu64ZdoZR) /* libC.a(shrcore_64.o) */
1265Str5FNs(libmpiZurZdaZLmpci64ZurZdoZR) /* libmpi_r.a(mpci64_r.o) */
1266Str5FNs(libqtZda) /* libqt.a */
sewardjfd4b6f42007-11-29 03:08:32 +00001267Str5FNs(ZaZLlibglibZhZaZdsoZaZR) /* *(libglib-*.so*) */
1268Str5FNs(ZaZLlibfontconfigZdsoZaZR) /* *(libfontconfig.so*) */
1269Str5FNs(libQtZaa) /* libQt*.a */
sewardj31b9ce12006-10-17 01:27:13 +00001270#endif
1271
1272
1273/* AIX's libm contains a sqrt implementation which does a nasty thing:
1274 it loads the initial estimate of the root into a FP register, but
1275 only the upper half of the number is initialised data. Hence the
1276 least significant 32 mantissa bits are undefined, and it then uses
1277 Newton-Raphson iteration to compute the final, defined result.
1278 This fools memcheck completely; the only solution I can think of is
1279 provide our own substitute. The _FAST variant is almost right
1280 except the result is not correctly rounded. The _EXACT variant,
1281 which is selected by default, is always right; but it's also pretty
1282 darn slow. */
1283
1284#if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
1285#define SQRT_FAST(soname, fnname) \
1286 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ); \
1287 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ) \
1288 { \
1289 static UInt T1[32] = \
1290 { 0, 1024, 3062, 5746, 9193, 13348, \
1291 18162, 23592, 29598, 36145, 43202, 50740, \
1292 58733, 67158, 75992, 85215, 83599, 71378, \
1293 60428, 50647, 41945, 34246, 27478, 21581, \
1294 16499, 12183, 8588, 5674, 3403, 1742, \
1295 661, 130 }; \
1296 UInt x0, x1, sign, expo, mant0, bIGENDIAN = 1; \
1297 union { UInt w[2]; double d; } u; \
1298 u.d = x; \
1299 x0 = u.w[1 - bIGENDIAN]; /* high half */ \
1300 x1 = u.w[bIGENDIAN]; /* low half */ \
1301 sign = x0 >> 31; \
1302 expo = (x0 >> 20) & 0x7FF; \
1303 mant0 = x0 & 0xFFFFF; \
1304 if ( (sign == 0 && expo >= 1 && expo <= 0x7FE) /* +normal */ \
1305 || (sign == 0 && expo == 0 \
1306 && (mant0 | x1) > 0) /* +denorm */) { \
1307 /* common case; do Newton-Raphson */ \
1308 /* technically k should be signed int32, but since we're \
1309 always entering here with x > 0, doesn't matter that it's \
1310 unsigned. */ \
1311 double y; \
1312 UInt k = (x0>>1) + 0x1ff80000; \
1313 u.w[1 - bIGENDIAN] = k - T1[31&(k>>15)]; \
1314 u.w[bIGENDIAN] = 0; \
1315 y = u.d; \
1316 y = (y+x/y)/2.0 ; \
1317 y = (y+x/y)/2.0 ; \
1318 y = y-(y-x/y)/2.0 ; \
1319 return y; \
1320 } \
1321 if ( (sign == 1 && expo >= 1 && expo <= 0x7FE) /* -normal */ \
1322 || (sign == 1 && expo == 0 \
1323 && (mant0 | x1) > 0) /* -denorm */) { \
1324 u.w[1 - bIGENDIAN] = 0xFFF00000; \
1325 u.w[bIGENDIAN] = 0x1; \
1326 return u.d; /* -Inf -> NaN */ \
1327 } \
1328 if ((expo | mant0 | x1) == 0) \
1329 return x; /* +/-zero -> self */ \
1330 if (expo == 0x7FF && (mant0 | x1) == 0) { \
1331 if (sign == 0) \
1332 return x; /* +Inf -> self */ \
1333 u.w[1 - bIGENDIAN] = 0xFFF00000; \
1334 u.w[bIGENDIAN] = 0x1; \
1335 return u.d; /* -Inf -> NaN */ \
1336 } \
1337 /* must be +/- NaN */ \
1338 return x; /* +/-NaN -> self */ \
1339 }
1340
1341#define SQRT_EXACT(soname, fnname) \
1342 /* \
1343 * ==================================================== \
1344 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. \
1345 * \
1346 * Developed at SunPro, a Sun Microsystems, Inc. business. \
1347 * Permission to use, copy, modify, and distribute this \
1348 * software is freely granted, provided that this notice \
1349 * is preserved. \
1350 * ==================================================== \
1351 */ \
1352 /* \
1353 * Return correctly rounded sqrt. \
1354 * ------------------------------------------ \
1355 * | Use the hardware sqrt if you have one | \
1356 * ------------------------------------------ \
1357 * Method: \
1358 * Bit by bit method using integer arithmetic. (Slow, but portable) \
1359 * 1. Normalization \
1360 * Scale x to y in [1,4) with even powers of 2: \
1361 * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then \
1362 * sqrt(x) = 2^k * sqrt(y) \
1363 * 2. Bit by bit computation \
1364 * Let q = sqrt(y) truncated to i bit after binary point (q = 1), \
1365 * i 0 \
1366 * i+1 2 \
1367 * s = 2*q , and y = 2 * ( y - q ). (1) \
1368 * i i i i \
1369 * \
1370 * To compute q from q , one checks whether \
1371 * i+1 i \
1372 * \
1373 * -(i+1) 2 \
1374 * (q + 2 ) <= y. (2) \
1375 * i \
1376 * -(i+1) \
1377 * If (2) is false, then q = q ; otherwise q = q + 2 . \
1378 * i+1 i i+1 i \
1379 * \
1380 * With some algebric manipulation, it is not difficult to see \
1381 * that (2) is equivalent to \
1382 * -(i+1) \
1383 * s + 2 <= y (3) \
1384 * i i \
1385 * \
1386 * The advantage of (3) is that s and y can be computed by \
1387 * i i \
1388 * the following recurrence formula: \
1389 * if (3) is false \
1390 * \
1391 * s = s , y = y ; (4) \
1392 * i+1 i i+1 i \
1393 * \
1394 * otherwise, \
1395 * -i -(i+1) \
1396 * s = s + 2 , y = y - s - 2 (5) \
1397 * i+1 i i+1 i i \
1398 * \
1399 * \
1400 * One may easily use induction to prove (4) and (5). \
1401 * Note. Since the left hand side of (3) contain only i+2 bits, \
1402 * it does not necessary to do a full (53-bit) comparison \
1403 * in (3). \
1404 * 3. Final rounding \
1405 * After generating the 53 bits result, we compute one more bit. \
1406 * Together with the remainder, we can decide whether the \
1407 * result is exact, bigger than 1/2ulp, or less than 1/2ulp \
1408 * (it will never equal to 1/2ulp). \
1409 * The rounding mode can be detected by checking whether \
1410 * huge + tiny is equal to huge, and whether huge - tiny is \
1411 * equal to huge for some floating point number "huge" and "tiny". \
1412 * \
1413 * Special cases: \
1414 * sqrt(+-0) = +-0 ... exact \
1415 * sqrt(inf) = inf \
1416 * sqrt(-ve) = NaN ... with invalid signal \
1417 * sqrt(NaN) = NaN ... with invalid signal for signaling NaN \
1418 * \
1419 */ \
1420 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ); \
1421 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ) \
1422 { \
1423 const Int bIGENDIAN = 1; \
1424 const double one = 1.0, tiny=1.0e-300; \
1425 double z; \
1426 Int sign = (Int)0x80000000; \
1427 Int ix0,s0,q,m,t,i; \
1428 UInt r,t1,s1,ix1,q1; \
1429 union { UInt w[2]; double d; } u; \
1430 u.d = x; \
1431 ix0 = u.w[1-bIGENDIAN]; \
1432 ix1 = u.w[bIGENDIAN]; \
1433 \
1434 /* take care of Inf and NaN */ \
1435 if((ix0&0x7ff00000)==0x7ff00000) { \
1436 return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf \
1437 sqrt(-inf)=sNaN */ \
1438 } \
1439 /* take care of zero */ \
1440 if(ix0<=0) { \
1441 if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */ \
1442 else if(ix0<0) \
1443 return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ \
1444 } \
1445 /* normalize x */ \
1446 m = (ix0>>20); \
1447 if(m==0) { /* subnormal x */ \
1448 while(ix0==0) { \
1449 m -= 21; \
1450 ix0 |= (ix1>>11); ix1 <<= 21; \
1451 } \
1452 for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1; \
1453 m -= i-1; \
1454 ix0 |= (ix1>>(32-i)); \
1455 ix1 <<= i; \
1456 } \
1457 m -= 1023; /* unbias exponent */ \
1458 ix0 = (ix0&0x000fffff)|0x00100000; \
1459 if(m&1){ /* odd m, double x to make it even */ \
1460 ix0 += ix0 + ((ix1&sign)>>31); \
1461 ix1 += ix1; \
1462 } \
1463 m >>= 1; /* m = [m/2] */ \
1464 /* generate sqrt(x) bit by bit */ \
1465 ix0 += ix0 + ((ix1&sign)>>31); \
1466 ix1 += ix1; \
1467 q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ \
1468 r = 0x00200000; /* r = moving bit from right to left */ \
1469 while(r!=0) { \
1470 t = s0+r; \
1471 if(t<=ix0) { \
1472 s0 = t+r; \
1473 ix0 -= t; \
1474 q += r; \
1475 } \
1476 ix0 += ix0 + ((ix1&sign)>>31); \
1477 ix1 += ix1; \
1478 r>>=1; \
1479 } \
1480 r = sign; \
1481 while(r!=0) { \
1482 t1 = s1+r; \
1483 t = s0; \
1484 if((t<ix0)||((t==ix0)&&(t1<=ix1))) { \
1485 s1 = t1+r; \
1486 if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1; \
1487 ix0 -= t; \
1488 if (ix1 < t1) ix0 -= 1; \
1489 ix1 -= t1; \
1490 q1 += r; \
1491 } \
1492 ix0 += ix0 + ((ix1&sign)>>31); \
1493 ix1 += ix1; \
1494 r>>=1; \
1495 } \
1496 /* use floating add to find out rounding direction */ \
1497 if((ix0|ix1)!=0) { \
1498 z = one-tiny; /* trigger inexact flag */ \
1499 if (z>=one) { \
1500 z = one+tiny; \
1501 if (q1==(UInt)0xffffffff) { q1=0; q += 1;} \
1502 else if (z>one) { \
1503 if (q1==(UInt)0xfffffffe) q+=1; \
1504 q1+=2; \
1505 } else \
1506 q1 += (q1&1); \
1507 } \
1508 } \
1509 ix0 = (q>>1)+0x3fe00000; \
1510 ix1 = q1>>1; \
1511 if ((q&1)==1) ix1 |= sign; \
1512 ix0 += (m <<20); \
1513 ix0 = u.w[1-bIGENDIAN] = ix0; \
1514 ix1 = u.w[bIGENDIAN] = ix1; \
1515 z = u.d; \
1516 return z; \
1517 }
1518
1519#if 0
1520SQRT_FAST(NONE, sqrt) /* xlC generates these */
1521SQRT_FAST(NONE, _sqrt) /* xlf generates these */
1522#else
1523SQRT_EXACT(NONE, sqrt) /* xlC generates these */
1524SQRT_EXACT(NONE, _sqrt) /* xlf generates these */
1525#endif
1526
1527#endif /* defined(VGP_ppc32_aix5) */
1528
njn3e884182003-04-15 13:03:23 +00001529/*--------------------------------------------------------------------*/
njn46275862005-03-24 04:00:03 +00001530/*--- end ---*/
njn3e884182003-04-15 13:03:23 +00001531/*--------------------------------------------------------------------*/