blob: c45d270b0491d42833f8a7551d461516bd7da936 [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.
bart575ce8e2011-05-15 07:04:03 +000092#define RECORD_OVERLAP_ERROR(s, src, dst, len) \
93 VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
94 _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR, \
95 s, src, dst, len, 0)
njn3e884182003-04-15 13:03:23 +000096
njn16eeb4e2005-06-16 03:56:58 +000097
98#define STRRCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +000099 char* VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* s, int c ); \
100 char* VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000101 { \
102 UChar ch = (UChar)((UInt)c); \
103 UChar* p = (UChar*)s; \
104 UChar* last = NULL; \
105 while (True) { \
106 if (*p == ch) last = p; \
107 if (*p == 0) return last; \
108 p++; \
109 } \
njn3e884182003-04-15 13:03:23 +0000110 }
njn3e884182003-04-15 13:03:23 +0000111
njn16eeb4e2005-06-16 03:56:58 +0000112// Apparently rindex() is the same thing as strrchr()
njne6154662009-02-10 04:23:41 +0000113STRRCHR(VG_Z_LIBC_SONAME, strrchr)
114STRRCHR(VG_Z_LIBC_SONAME, rindex)
njnb4cfbc42009-05-04 04:20:02 +0000115#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000116STRRCHR(VG_Z_LIBC_SONAME, __GI_strrchr)
njne6154662009-02-10 04:23:41 +0000117STRRCHR(VG_Z_LD_LINUX_SO_2, rindex)
njnf76d27a2009-05-28 01:53:07 +0000118#elif defined(VGO_darwin)
119STRRCHR(VG_Z_DYLD, strrchr)
120STRRCHR(VG_Z_DYLD, rindex)
njnb4cfbc42009-05-04 04:20:02 +0000121#endif
njn16eeb4e2005-06-16 03:56:58 +0000122
123
124#define STRCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000125 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ); \
126 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000127 { \
128 UChar ch = (UChar)((UInt)c); \
129 UChar* p = (UChar*)s; \
130 while (True) { \
131 if (*p == ch) return p; \
132 if (*p == 0) return NULL; \
133 p++; \
134 } \
njn3e884182003-04-15 13:03:23 +0000135 }
njn3e884182003-04-15 13:03:23 +0000136
njn16eeb4e2005-06-16 03:56:58 +0000137// Apparently index() is the same thing as strchr()
njne6154662009-02-10 04:23:41 +0000138STRCHR(VG_Z_LIBC_SONAME, strchr)
njne6154662009-02-10 04:23:41 +0000139STRCHR(VG_Z_LIBC_SONAME, index)
njnb4cfbc42009-05-04 04:20:02 +0000140#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000141STRCHR(VG_Z_LIBC_SONAME, __GI_strchr)
njnb4cfbc42009-05-04 04:20:02 +0000142STRCHR(VG_Z_LD_LINUX_SO_2, strchr)
njne6154662009-02-10 04:23:41 +0000143STRCHR(VG_Z_LD_LINUX_SO_2, index)
njnb4cfbc42009-05-04 04:20:02 +0000144STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr)
njne6154662009-02-10 04:23:41 +0000145STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index)
njnf76d27a2009-05-28 01:53:07 +0000146#elif defined(VGO_darwin)
147STRCHR(VG_Z_DYLD, strchr)
148STRCHR(VG_Z_DYLD, index)
njnb4cfbc42009-05-04 04:20:02 +0000149#endif
njn3e884182003-04-15 13:03:23 +0000150
njn3e884182003-04-15 13:03:23 +0000151
njn16eeb4e2005-06-16 03:56:58 +0000152#define STRCAT(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000153 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ); \
154 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000155 { \
156 const Char* src_orig = src; \
157 Char* dst_orig = dst; \
158 while (*dst) dst++; \
159 while (*src) *dst++ = *src++; \
160 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000161 \
njn16eeb4e2005-06-16 03:56:58 +0000162 /* This is a bit redundant, I think; any overlap and the strcat will */ \
163 /* go forever... or until a seg fault occurs. */ \
164 if (is_overlap(dst_orig, \
165 src_orig, \
166 (Addr)dst-(Addr)dst_orig+1, \
167 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000168 RECORD_OVERLAP_ERROR("strcat", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000169 \
njn16eeb4e2005-06-16 03:56:58 +0000170 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000171 }
njn3e884182003-04-15 13:03:23 +0000172
njne6154662009-02-10 04:23:41 +0000173STRCAT(VG_Z_LIBC_SONAME, strcat)
tomd2645142009-10-29 09:27:11 +0000174#if defined(VGO_linux)
175STRCAT(VG_Z_LIBC_SONAME, __GI_strcat)
176#endif
njn16eeb4e2005-06-16 03:56:58 +0000177
178#define STRNCAT(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000179 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
180 ( char* dst, const char* src, SizeT n ); \
181 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
182 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000183 { \
184 const Char* src_orig = src; \
185 Char* dst_orig = dst; \
186 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000187 \
njn16eeb4e2005-06-16 03:56:58 +0000188 while (*dst) dst++; \
189 while (m < n && *src) { m++; *dst++ = *src++; } /* concat <= n chars */ \
190 *dst = 0; /* always add null */ \
sewardjb6c04032007-11-13 20:52:29 +0000191 \
njn16eeb4e2005-06-16 03:56:58 +0000192 /* This checks for overlap after copying, unavoidable without */ \
193 /* pre-counting lengths... should be ok */ \
194 if (is_overlap(dst_orig, \
195 src_orig, \
196 (Addr)dst-(Addr)dst_orig+1, \
197 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000198 RECORD_OVERLAP_ERROR("strncat", dst_orig, src_orig, n); \
sewardjb6c04032007-11-13 20:52:29 +0000199 \
njn16eeb4e2005-06-16 03:56:58 +0000200 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000201 }
njn3e884182003-04-15 13:03:23 +0000202
njne6154662009-02-10 04:23:41 +0000203STRNCAT(VG_Z_LIBC_SONAME, strncat)
njnf76d27a2009-05-28 01:53:07 +0000204#if defined(VGO_darwin)
205STRNCAT(VG_Z_DYLD, strncat)
206#endif
207
208
209/* Append src to dst. n is the size of dst's buffer. dst is guaranteed
210 to be nul-terminated after the copy, unless n <= strlen(dst_orig).
211 Returns min(n, strlen(dst_orig)) + strlen(src_orig).
212 Truncation occurred if retval >= n.
213*/
214#define STRLCAT(soname, fnname) \
215 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
216 ( char* dst, const char* src, SizeT n ); \
217 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
218 ( char* dst, const char* src, SizeT n ) \
219 { \
220 const Char* src_orig = src; \
221 Char* dst_orig = dst; \
222 SizeT m = 0; \
223\
224 while (m < n && *dst) { m++; dst++; } \
225 if (m < n) { \
226 /* Fill as far as dst_orig[n-2], then nul-terminate. */ \
227 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
228 *dst = 0; \
229 } else { \
230 /* No space to copy anything to dst. m == n */ \
231 } \
232 /* Finish counting min(n, strlen(dst_orig)) + strlen(src_orig) */ \
233 while (*src) { m++; src++; } \
234 /* This checks for overlap after copying, unavoidable without */ \
235 /* pre-counting lengths... should be ok */ \
236 if (is_overlap(dst_orig, \
237 src_orig, \
238 (Addr)dst-(Addr)dst_orig+1, \
239 (Addr)src-(Addr)src_orig+1)) \
240 RECORD_OVERLAP_ERROR("strlcat", dst_orig, src_orig, n); \
241\
242 return m; \
243 }
244
245#if defined(VGO_darwin)
246STRLCAT(VG_Z_LIBC_SONAME, strlcat)
247STRLCAT(VG_Z_DYLD, strlcat)
248#endif
sewardj31b9ce12006-10-17 01:27:13 +0000249
njn3e884182003-04-15 13:03:23 +0000250
njn16eeb4e2005-06-16 03:56:58 +0000251#define STRNLEN(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000252 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* str, SizeT n ); \
253 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* str, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000254 { \
255 SizeT i = 0; \
256 while (i < n && str[i] != 0) i++; \
257 return i; \
njn3e884182003-04-15 13:03:23 +0000258 }
njn3e884182003-04-15 13:03:23 +0000259
njne6154662009-02-10 04:23:41 +0000260STRNLEN(VG_Z_LIBC_SONAME, strnlen)
tomd2645142009-10-29 09:27:11 +0000261#if defined(VGO_linux)
262STRNLEN(VG_Z_LIBC_SONAME, __GI_strnlen)
263#endif
njn16eeb4e2005-06-16 03:56:58 +0000264
sewardj3ceec242003-07-30 21:24:25 +0000265
njn5ec15ed2005-08-24 19:55:51 +0000266// Note that this replacement often doesn't get used because gcc inlines
267// calls to strlen() with its own built-in version. This can be very
268// confusing if you aren't expecting it. Other small functions in this file
269// may also be inline by gcc.
njn16eeb4e2005-06-16 03:56:58 +0000270#define STRLEN(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000271 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ); \
272 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ) \
njn16eeb4e2005-06-16 03:56:58 +0000273 { \
274 SizeT i = 0; \
275 while (str[i] != 0) i++; \
276 return i; \
sewardj3ceec242003-07-30 21:24:25 +0000277 }
njn16eeb4e2005-06-16 03:56:58 +0000278
njnb4cfbc42009-05-04 04:20:02 +0000279STRLEN(VG_Z_LIBC_SONAME, strlen)
280#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000281STRLEN(VG_Z_LIBC_SONAME, __GI_strlen)
njne6154662009-02-10 04:23:41 +0000282STRLEN(VG_Z_LD_LINUX_SO_2, strlen)
283STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen)
njnb4cfbc42009-05-04 04:20:02 +0000284#endif
sewardj31b9ce12006-10-17 01:27:13 +0000285
njn16eeb4e2005-06-16 03:56:58 +0000286
287#define STRCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000288 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ); \
289 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000290 { \
291 const Char* src_orig = src; \
292 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000293 \
njn16eeb4e2005-06-16 03:56:58 +0000294 while (*src) *dst++ = *src++; \
295 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000296 \
njn16eeb4e2005-06-16 03:56:58 +0000297 /* This checks for overlap after copying, unavoidable without */ \
298 /* pre-counting length... should be ok */ \
299 if (is_overlap(dst_orig, \
300 src_orig, \
301 (Addr)dst-(Addr)dst_orig+1, \
302 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000303 RECORD_OVERLAP_ERROR("strcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000304 \
njn16eeb4e2005-06-16 03:56:58 +0000305 return dst_orig; \
306 }
307
njne6154662009-02-10 04:23:41 +0000308STRCPY(VG_Z_LIBC_SONAME, strcpy)
tomd2645142009-10-29 09:27:11 +0000309#if defined(VGO_linux)
310STRCPY(VG_Z_LIBC_SONAME, __GI_strcpy)
311#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000312STRCPY(VG_Z_DYLD, strcpy)
313#endif
njn16eeb4e2005-06-16 03:56:58 +0000314
315
316#define STRNCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000317 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) \
318 ( char* dst, const char* src, SizeT n ); \
319 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) \
320 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000321 { \
322 const Char* src_orig = src; \
323 Char* dst_orig = dst; \
324 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000325 \
njn16eeb4e2005-06-16 03:56:58 +0000326 while (m < n && *src) { m++; *dst++ = *src++; } \
327 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
328 /* but only m+1 bytes of src if terminator was found */ \
329 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
njn718d3b12006-12-16 00:54:12 +0000330 RECORD_OVERLAP_ERROR("strncpy", dst, src, n); \
njn16eeb4e2005-06-16 03:56:58 +0000331 while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */ \
332 \
333 return dst_orig; \
334 }
335
njne6154662009-02-10 04:23:41 +0000336STRNCPY(VG_Z_LIBC_SONAME, strncpy)
tomd2645142009-10-29 09:27:11 +0000337#if defined(VGO_linux)
338STRNCPY(VG_Z_LIBC_SONAME, __GI_strncpy)
339#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000340STRNCPY(VG_Z_DYLD, strncpy)
341#endif
342
343
344/* Copy up to n-1 bytes from src to dst. Then nul-terminate dst if n > 0.
345 Returns strlen(src). Does not zero-fill the remainder of dst. */
346#define STRLCPY(soname, fnname) \
347 SizeT VG_REPLACE_FUNCTION_ZU(soname, fnname) \
348 ( char* dst, const char* src, SizeT n ); \
349 SizeT VG_REPLACE_FUNCTION_ZU(soname, fnname) \
350 ( char* dst, const char* src, SizeT n ) \
351 { \
352 const char* src_orig = src; \
353 char* dst_orig = dst; \
354 SizeT m = 0; \
355\
356 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
357 /* m non-nul bytes have now been copied, and m <= n-1. */ \
358 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
359 /* but only m+1 bytes of src if terminator was found */ \
360 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
361 RECORD_OVERLAP_ERROR("strlcpy", dst, src, n); \
362 /* Nul-terminate dst. */ \
363 if (n > 0) *dst = 0; \
364 /* Finish counting strlen(src). */ \
365 while (*src) src++; \
366 return src - src_orig; \
367 }
368
369#if defined(VGO_darwin)
370STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
371STRLCPY(VG_Z_DYLD, strlcpy)
372#endif
njn16eeb4e2005-06-16 03:56:58 +0000373
374
375#define STRNCMP(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000376 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
377 ( const char* s1, const char* s2, SizeT nmax ); \
378 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
379 ( const char* s1, const char* s2, SizeT nmax ) \
njn16eeb4e2005-06-16 03:56:58 +0000380 { \
381 SizeT n = 0; \
382 while (True) { \
383 if (n >= nmax) return 0; \
384 if (*s1 == 0 && *s2 == 0) return 0; \
385 if (*s1 == 0) return -1; \
386 if (*s2 == 0) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000387 \
njn16eeb4e2005-06-16 03:56:58 +0000388 if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1; \
389 if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000390 \
njn16eeb4e2005-06-16 03:56:58 +0000391 s1++; s2++; n++; \
392 } \
393 }
394
njne6154662009-02-10 04:23:41 +0000395STRNCMP(VG_Z_LIBC_SONAME, strncmp)
tomd2645142009-10-29 09:27:11 +0000396#if defined(VGO_linux)
397STRNCMP(VG_Z_LIBC_SONAME, __GI_strncmp)
398#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000399STRNCMP(VG_Z_DYLD, strncmp)
400#endif
njn16eeb4e2005-06-16 03:56:58 +0000401
402
tomce6d0ac2010-11-12 10:03:13 +0000403#define STRCASECMP(soname, fnname) \
404 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
405 ( const char* s1, const char* s2 ); \
406 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
407 ( const char* s1, const char* s2 ) \
408 { \
tome03c8c42010-11-12 10:40:20 +0000409 extern int tolower(int); \
tomce6d0ac2010-11-12 10:03:13 +0000410 register unsigned char c1; \
411 register unsigned char c2; \
412 while (True) { \
413 c1 = tolower(*(unsigned char *)s1); \
414 c2 = tolower(*(unsigned char *)s2); \
415 if (c1 != c2) break; \
416 if (c1 == 0) break; \
417 s1++; s2++; \
418 } \
419 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
420 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
421 return 0; \
422 }
423
424STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp)
425#if defined(VGO_linux)
426STRCASECMP(VG_Z_LIBC_SONAME, __GI_strcasecmp)
427#endif
428
429
430#define STRNCASECMP(soname, fnname) \
431 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
432 ( const char* s1, const char* s2, SizeT nmax ); \
433 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
434 ( const char* s1, const char* s2, SizeT nmax ) \
435 { \
tome03c8c42010-11-12 10:40:20 +0000436 extern int tolower(int); \
tomce6d0ac2010-11-12 10:03:13 +0000437 SizeT n = 0; \
438 while (True) { \
439 if (n >= nmax) return 0; \
440 if (*s1 == 0 && *s2 == 0) return 0; \
441 if (*s1 == 0) return -1; \
442 if (*s2 == 0) return 1; \
443 \
444 if (tolower(*(unsigned char*)s1) < tolower(*(unsigned char*)s2)) return -1; \
445 if (tolower(*(unsigned char*)s1) > tolower(*(unsigned char*)s2)) return 1; \
446 \
447 s1++; s2++; n++; \
448 } \
449 }
450
451STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp)
452#if defined(VGO_linux)
453STRNCASECMP(VG_Z_LIBC_SONAME, __GI_strncasecmp)
454#elif defined(VGO_darwin)
455STRNCASECMP(VG_Z_DYLD, strncasecmp)
456#endif
457
458
tomce6d0ac2010-11-12 10:03:13 +0000459#define STRCASECMP_L(soname, fnname) \
460 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000461 ( const char* s1, const char* s2, void* locale ); \
tomce6d0ac2010-11-12 10:03:13 +0000462 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000463 ( const char* s1, const char* s2, void* locale ) \
tomce6d0ac2010-11-12 10:03:13 +0000464 { \
tome03c8c42010-11-12 10:40:20 +0000465 extern int tolower_l(int, void*) __attribute__((weak)); \
tomce6d0ac2010-11-12 10:03:13 +0000466 register unsigned char c1; \
467 register unsigned char c2; \
468 while (True) { \
469 c1 = tolower_l(*(unsigned char *)s1, locale); \
470 c2 = tolower_l(*(unsigned char *)s2, locale); \
471 if (c1 != c2) break; \
472 if (c1 == 0) break; \
473 s1++; s2++; \
474 } \
475 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
476 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
477 return 0; \
478 }
479
480STRCASECMP_L(VG_Z_LIBC_SONAME, strcasecmp_l)
481#if defined(VGO_linux)
482STRCASECMP_L(VG_Z_LIBC_SONAME, __GI_strcasecmp_l)
483#endif
484
485
486#define STRNCASECMP_L(soname, fnname) \
487 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000488 ( const char* s1, const char* s2, SizeT nmax, void* locale ); \
tomce6d0ac2010-11-12 10:03:13 +0000489 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
tome03c8c42010-11-12 10:40:20 +0000490 ( const char* s1, const char* s2, SizeT nmax, void* locale ) \
tomce6d0ac2010-11-12 10:03:13 +0000491 { \
tome03c8c42010-11-12 10:40:20 +0000492 extern int tolower_l(int, void*) __attribute__((weak)); \
tomce6d0ac2010-11-12 10:03:13 +0000493 SizeT n = 0; \
494 while (True) { \
495 if (n >= nmax) return 0; \
496 if (*s1 == 0 && *s2 == 0) return 0; \
497 if (*s1 == 0) return -1; \
498 if (*s2 == 0) return 1; \
499 \
500 if (tolower_l(*(unsigned char*)s1, locale) < tolower_l(*(unsigned char*)s2, locale)) return -1; \
501 if (tolower_l(*(unsigned char*)s1, locale) > tolower_l(*(unsigned char*)s2, locale)) return 1; \
502 \
503 s1++; s2++; n++; \
504 } \
505 }
506
507STRNCASECMP_L(VG_Z_LIBC_SONAME, strncasecmp_l)
508#if defined(VGO_linux)
509STRNCASECMP_L(VG_Z_LIBC_SONAME, __GI_strncasecmp_l)
510#elif defined(VGO_darwin)
511STRNCASECMP_L(VG_Z_DYLD, strncasecmp_l)
512#endif
513
514
njn16eeb4e2005-06-16 03:56:58 +0000515#define STRCMP(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000516 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
517 ( const char* s1, const char* s2 ); \
518 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
519 ( const char* s1, const char* s2 ) \
njn16eeb4e2005-06-16 03:56:58 +0000520 { \
521 register unsigned char c1; \
522 register unsigned char c2; \
523 while (True) { \
524 c1 = *(unsigned char *)s1; \
525 c2 = *(unsigned char *)s2; \
526 if (c1 != c2) break; \
527 if (c1 == 0) break; \
528 s1++; s2++; \
529 } \
530 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
531 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
532 return 0; \
533 }
534
njne6154662009-02-10 04:23:41 +0000535STRCMP(VG_Z_LIBC_SONAME, strcmp)
njnb4cfbc42009-05-04 04:20:02 +0000536#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000537STRCMP(VG_Z_LIBC_SONAME, __GI_strcmp)
njne6154662009-02-10 04:23:41 +0000538STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp)
539STRCMP(VG_Z_LD64_SO_1, strcmp)
njnb4cfbc42009-05-04 04:20:02 +0000540#endif
njn16eeb4e2005-06-16 03:56:58 +0000541
542
543#define MEMCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000544 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const void *s, int c, SizeT n); \
545 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const void *s, int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000546 { \
547 SizeT i; \
548 UChar c0 = (UChar)c; \
549 UChar* p = (UChar*)s; \
550 for (i = 0; i < n; i++) \
551 if (p[i] == c0) return (void*)(&p[i]); \
552 return NULL; \
553 }
554
njne6154662009-02-10 04:23:41 +0000555MEMCHR(VG_Z_LIBC_SONAME, memchr)
njnf76d27a2009-05-28 01:53:07 +0000556#if defined(VGO_darwin)
557MEMCHR(VG_Z_DYLD, memchr)
558#endif
njn16eeb4e2005-06-16 03:56:58 +0000559
560
561#define MEMCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000562 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
563 ( void *dst, const void *src, SizeT len ); \
564 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
565 ( void *dst, const void *src, SizeT len ) \
njn16eeb4e2005-06-16 03:56:58 +0000566 { \
njn16eeb4e2005-06-16 03:56:58 +0000567 if (is_overlap(dst, src, len, len)) \
njn718d3b12006-12-16 00:54:12 +0000568 RECORD_OVERLAP_ERROR("memcpy", dst, src, len); \
sewardjb6c04032007-11-13 20:52:29 +0000569 \
sewardj7b4e00b2010-08-24 09:05:52 +0000570 const Addr WS = sizeof(UWord); /* 8 or 4 */ \
571 const Addr WM = WS - 1; /* 7 or 3 */ \
572 \
573 if (dst < src) { \
574 \
575 /* Copying backwards. */ \
576 SizeT n = len; \
577 Addr d = (Addr)dst; \
578 Addr s = (Addr)src; \
579 \
580 if (((s^d) & WM) == 0) { \
581 /* s and d have same UWord alignment. */ \
582 /* Pull up to a UWord boundary. */ \
583 while ((s & WM) != 0 && n >= 1) \
584 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
585 /* Copy UWords. */ \
586 while (n >= WS) \
587 { *(UWord*)d = *(UWord*)s; s += WS; d += WS; n -= WS; } \
588 if (n == 0) \
589 return dst; \
njn16eeb4e2005-06-16 03:56:58 +0000590 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000591 if (((s|d) & 1) == 0) { \
592 /* Both are 16-aligned; copy what we can thusly. */ \
593 while (n >= 2) \
594 { *(UShort*)d = *(UShort*)s; s += 2; d += 2; n -= 2; } \
njn16eeb4e2005-06-16 03:56:58 +0000595 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000596 /* Copy leftovers, or everything if misaligned. */ \
597 while (n >= 1) \
598 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
599 \
600 } else if (dst > src) { \
601 \
602 SizeT n = len; \
603 Addr d = ((Addr)dst) + n; \
604 Addr s = ((Addr)src) + n; \
605 \
606 /* Copying forwards. */ \
607 if (((s^d) & WM) == 0) { \
608 /* s and d have same UWord alignment. */ \
609 /* Back down to a UWord boundary. */ \
610 while ((s & WM) != 0 && n >= 1) \
611 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
612 /* Copy UWords. */ \
613 while (n >= WS) \
614 { s -= WS; d -= WS; *(UWord*)d = *(UWord*)s; n -= WS; } \
615 if (n == 0) \
616 return dst; \
njn16eeb4e2005-06-16 03:56:58 +0000617 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000618 if (((s|d) & 1) == 0) { \
619 /* Both are 16-aligned; copy what we can thusly. */ \
620 while (n >= 2) \
621 { s -= 2; d -= 2; *(UShort*)d = *(UShort*)s; n -= 2; } \
njn16eeb4e2005-06-16 03:56:58 +0000622 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000623 /* Copy leftovers, or everything if misaligned. */ \
624 while (n >= 1) \
625 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
626 \
njn16eeb4e2005-06-16 03:56:58 +0000627 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000628 \
njn16eeb4e2005-06-16 03:56:58 +0000629 return dst; \
630 }
631
njne6154662009-02-10 04:23:41 +0000632MEMCPY(VG_Z_LIBC_SONAME, memcpy)
njnb4cfbc42009-05-04 04:20:02 +0000633#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +0000634MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */
635MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */
njnf76d27a2009-05-28 01:53:07 +0000636#elif defined(VGO_darwin)
637MEMCPY(VG_Z_DYLD, memcpy)
njnb4cfbc42009-05-04 04:20:02 +0000638#endif
sewardjf0b34322007-01-16 21:42:28 +0000639/* icc9 blats these around all over the place. Not only in the main
640 executable but various .so's. They are highly tuned and read
641 memory beyond the source boundary (although work correctly and
642 never go across page boundaries), so give errors when run natively,
643 at least for misaligned source arg. Just intercepting in the exe
644 only until we understand more about the problem. See
645 http://bugs.kde.org/show_bug.cgi?id=139776
646 */
647MEMCPY(NONE, _intel_fast_memcpy)
sewardj31b9ce12006-10-17 01:27:13 +0000648
njn16eeb4e2005-06-16 03:56:58 +0000649
650#define MEMCMP(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000651 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
652 ( const void *s1V, const void *s2V, SizeT n ); \
653 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
654 ( const void *s1V, const void *s2V, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000655 { \
656 int res; \
657 unsigned char a0; \
658 unsigned char b0; \
659 unsigned char* s1 = (unsigned char*)s1V; \
660 unsigned char* s2 = (unsigned char*)s2V; \
sewardjb6c04032007-11-13 20:52:29 +0000661 \
njn16eeb4e2005-06-16 03:56:58 +0000662 while (n != 0) { \
663 a0 = s1[0]; \
664 b0 = s2[0]; \
665 s1 += 1; \
666 s2 += 1; \
667 res = ((int)a0) - ((int)b0); \
668 if (res != 0) \
669 return res; \
670 n -= 1; \
671 } \
672 return 0; \
673 }
674
njne6154662009-02-10 04:23:41 +0000675MEMCMP(VG_Z_LIBC_SONAME, memcmp)
676MEMCMP(VG_Z_LIBC_SONAME, bcmp)
njnb4cfbc42009-05-04 04:20:02 +0000677#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +0000678MEMCMP(VG_Z_LD_SO_1, bcmp)
njnf76d27a2009-05-28 01:53:07 +0000679#elif defined(VGO_darwin)
680MEMCMP(VG_Z_DYLD, memcmp)
681MEMCMP(VG_Z_DYLD, bcmp)
njnb4cfbc42009-05-04 04:20:02 +0000682#endif
njn3e884182003-04-15 13:03:23 +0000683
jseward0845ef82003-12-22 22:31:27 +0000684
685/* Copy SRC to DEST, returning the address of the terminating '\0' in
686 DEST. (minor variant of strcpy) */
njn16eeb4e2005-06-16 03:56:58 +0000687#define STPCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000688 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ); \
689 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000690 { \
691 const Char* src_orig = src; \
692 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000693 \
njn16eeb4e2005-06-16 03:56:58 +0000694 while (*src) *dst++ = *src++; \
695 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000696 \
njn16eeb4e2005-06-16 03:56:58 +0000697 /* This checks for overlap after copying, unavoidable without */ \
698 /* pre-counting length... should be ok */ \
699 if (is_overlap(dst_orig, \
700 src_orig, \
701 (Addr)dst-(Addr)dst_orig+1, \
702 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000703 RECORD_OVERLAP_ERROR("stpcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000704 \
njn16eeb4e2005-06-16 03:56:58 +0000705 return dst; \
sewardj44e495f2005-05-12 17:58:28 +0000706 }
njn16eeb4e2005-06-16 03:56:58 +0000707
njne6154662009-02-10 04:23:41 +0000708STPCPY(VG_Z_LIBC_SONAME, stpcpy)
njnb4cfbc42009-05-04 04:20:02 +0000709#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000710STPCPY(VG_Z_LIBC_SONAME, __GI_stpcpy)
njne6154662009-02-10 04:23:41 +0000711STPCPY(VG_Z_LD_LINUX_SO_2, stpcpy)
712STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy)
njnf76d27a2009-05-28 01:53:07 +0000713#elif defined(VGO_darwin)
714STPCPY(VG_Z_DYLD, stpcpy)
njnb4cfbc42009-05-04 04:20:02 +0000715#endif
716
njn16eeb4e2005-06-16 03:56:58 +0000717
718#define MEMSET(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000719 void* VG_REPLACE_FUNCTION_ZU(soname,fnname)(void *s, Int c, SizeT n); \
720 void* VG_REPLACE_FUNCTION_ZU(soname,fnname)(void *s, Int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000721 { \
sewardj7b4e00b2010-08-24 09:05:52 +0000722 Addr a = (Addr)s; \
723 UInt c4 = (c & 0xFF); \
724 c4 = (c4 << 8) | c4; \
725 c4 = (c4 << 16) | c4; \
726 while ((a & 3) != 0 && n >= 1) \
727 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
728 while (n >= 4) \
729 { *(UInt*)a = c4; a += 4; n -= 4; } \
730 while (n >= 1) \
731 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
njn16eeb4e2005-06-16 03:56:58 +0000732 return s; \
sewardj44e495f2005-05-12 17:58:28 +0000733 }
njn16eeb4e2005-06-16 03:56:58 +0000734
njne6154662009-02-10 04:23:41 +0000735MEMSET(VG_Z_LIBC_SONAME, memset)
njnf76d27a2009-05-28 01:53:07 +0000736#if defined(VGO_darwin)
737MEMSET(VG_Z_DYLD, memset)
738#endif
njn16eeb4e2005-06-16 03:56:58 +0000739
740
741#define MEMMOVE(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000742 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
743 (void *dstV, const void *srcV, SizeT n); \
744 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
745 (void *dstV, const void *srcV, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000746 { \
747 SizeT i; \
748 Char* dst = (Char*)dstV; \
749 Char* src = (Char*)srcV; \
750 if (dst < src) { \
751 for (i = 0; i < n; i++) \
752 dst[i] = src[i]; \
753 } \
754 else \
755 if (dst > src) { \
756 for (i = 0; i < n; i++) \
757 dst[n-i-1] = src[n-i-1]; \
758 } \
759 return dst; \
760 }
761
njne6154662009-02-10 04:23:41 +0000762MEMMOVE(VG_Z_LIBC_SONAME, memmove)
njnf76d27a2009-05-28 01:53:07 +0000763#if defined(VGO_darwin)
764MEMMOVE(VG_Z_DYLD, memmove)
765#endif
766
767
768#define BCOPY(soname, fnname) \
769 void VG_REPLACE_FUNCTION_ZU(soname,fnname) \
770 (const void *srcV, void *dstV, SizeT n); \
771 void VG_REPLACE_FUNCTION_ZU(soname,fnname) \
772 (const void *srcV, void *dstV, SizeT n) \
773 { \
774 SizeT i; \
775 Char* dst = (Char*)dstV; \
776 Char* src = (Char*)srcV; \
777 if (dst < src) { \
778 for (i = 0; i < n; i++) \
779 dst[i] = src[i]; \
780 } \
781 else \
782 if (dst > src) { \
783 for (i = 0; i < n; i++) \
784 dst[n-i-1] = src[n-i-1]; \
785 } \
786 }
787
788#if defined(VGO_darwin)
789BCOPY(VG_Z_LIBC_SONAME, bcopy)
790BCOPY(VG_Z_DYLD, bcopy)
791#endif
sewardj44e495f2005-05-12 17:58:28 +0000792
jseward0845ef82003-12-22 22:31:27 +0000793
sewardj24cb2172007-02-23 09:03:26 +0000794/* glibc 2.5 variant of memmove which checks the dest is big enough.
795 There is no specific part of glibc that this is copied from. */
796#define GLIBC25___MEMMOVE_CHK(soname, fnname) \
797 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
798 (void *dstV, const void *srcV, SizeT n, SizeT destlen); \
799 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
800 (void *dstV, const void *srcV, SizeT n, SizeT destlen) \
801 { \
802 extern void _exit(int status); \
803 SizeT i; \
804 Char* dst = (Char*)dstV; \
805 Char* src = (Char*)srcV; \
806 if (destlen < n) \
807 goto badness; \
808 if (dst < src) { \
809 for (i = 0; i < n; i++) \
810 dst[i] = src[i]; \
811 } \
812 else \
813 if (dst > src) { \
814 for (i = 0; i < n; i++) \
815 dst[n-i-1] = src[n-i-1]; \
816 } \
817 return dst; \
818 badness: \
819 VALGRIND_PRINTF_BACKTRACE( \
820 "*** memmove_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000821 "program terminated\n"); \
sewardj24cb2172007-02-23 09:03:26 +0000822 _exit(127); \
sewardjc271ec82007-02-27 22:36:14 +0000823 /*NOTREACHED*/ \
824 return NULL; \
sewardj24cb2172007-02-23 09:03:26 +0000825 }
826
njne6154662009-02-10 04:23:41 +0000827GLIBC25___MEMMOVE_CHK(VG_Z_LIBC_SONAME, __memmove_chk)
sewardj24cb2172007-02-23 09:03:26 +0000828
829
sewardj4e9a4b62004-11-23 00:20:17 +0000830/* Find the first occurrence of C in S or the final NUL byte. */
njn16eeb4e2005-06-16 03:56:58 +0000831#define GLIBC232_STRCHRNUL(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000832 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in); \
833 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +0000834 { \
835 unsigned char c = (unsigned char) c_in; \
836 unsigned char* char_ptr = (unsigned char *)s; \
837 while (1) { \
838 if (*char_ptr == 0) return char_ptr; \
839 if (*char_ptr == c) return char_ptr; \
840 char_ptr++; \
841 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000842 }
njn16eeb4e2005-06-16 03:56:58 +0000843
njne6154662009-02-10 04:23:41 +0000844GLIBC232_STRCHRNUL(VG_Z_LIBC_SONAME, strchrnul)
sewardj4e9a4b62004-11-23 00:20:17 +0000845
846
847/* Find the first occurrence of C in S. */
njn16eeb4e2005-06-16 03:56:58 +0000848#define GLIBC232_RAWMEMCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000849 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in); \
850 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +0000851 { \
852 unsigned char c = (unsigned char) c_in; \
853 unsigned char* char_ptr = (unsigned char *)s; \
854 while (1) { \
855 if (*char_ptr == c) return char_ptr; \
856 char_ptr++; \
857 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000858 }
njn16eeb4e2005-06-16 03:56:58 +0000859
njne6154662009-02-10 04:23:41 +0000860GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, rawmemchr)
tomd2645142009-10-29 09:27:11 +0000861#if defined (VGO_linux)
862GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, __GI___rawmemchr)
863#endif
sewardj4e9a4b62004-11-23 00:20:17 +0000864
sewardjdc5d8322007-01-28 06:32:01 +0000865/* glibc variant of strcpy that checks the dest is big enough.
866 Copied from glibc-2.5/debug/test-strcpy_chk.c. */
sewardj620e5262006-12-31 00:22:30 +0000867#define GLIBC25___STRCPY_CHK(soname,fnname) \
868 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
869 (char* dst, const char* src, SizeT len); \
870 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
871 (char* dst, const char* src, SizeT len) \
872 { \
873 extern void _exit(int status); \
874 char* ret = dst; \
875 if (! len) \
876 goto badness; \
877 while ((*dst++ = *src++) != '\0') \
878 if (--len == 0) \
879 goto badness; \
880 return ret; \
881 badness: \
882 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +0000883 "*** strcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000884 "program terminated\n"); \
sewardj620e5262006-12-31 00:22:30 +0000885 _exit(127); \
886 /*NOTREACHED*/ \
887 return NULL; \
888 }
889
njne6154662009-02-10 04:23:41 +0000890GLIBC25___STRCPY_CHK(VG_Z_LIBC_SONAME, __strcpy_chk)
sewardj620e5262006-12-31 00:22:30 +0000891
892
sewardjdc5d8322007-01-28 06:32:01 +0000893/* glibc variant of stpcpy that checks the dest is big enough.
894 Copied from glibc-2.5/debug/test-stpcpy_chk.c. */
sewardjb8d03852007-01-27 00:49:44 +0000895#define GLIBC25___STPCPY_CHK(soname,fnname) \
896 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
897 (char* dst, const char* src, SizeT len); \
898 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
899 (char* dst, const char* src, SizeT len) \
900 { \
901 extern void _exit(int status); \
sewardjdc5d8322007-01-28 06:32:01 +0000902 if (! len) \
903 goto badness; \
904 while ((*dst++ = *src++) != '\0') \
905 if (--len == 0) \
sewardjb8d03852007-01-27 00:49:44 +0000906 goto badness; \
sewardjb8d03852007-01-27 00:49:44 +0000907 return dst - 1; \
908 badness: \
909 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +0000910 "*** stpcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000911 "program terminated\n"); \
sewardjb8d03852007-01-27 00:49:44 +0000912 _exit(127); \
913 /*NOTREACHED*/ \
914 return NULL; \
915 }
916
njne6154662009-02-10 04:23:41 +0000917GLIBC25___STPCPY_CHK(VG_Z_LIBC_SONAME, __stpcpy_chk)
sewardjb8d03852007-01-27 00:49:44 +0000918
919
sewardj841b72d2006-12-31 18:55:56 +0000920/* mempcpy */
921#define GLIBC25_MEMPCPY(soname, fnname) \
922 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
923 ( void *dst, const void *src, SizeT len ); \
924 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
925 ( void *dst, const void *src, SizeT len ) \
926 { \
927 register char *d; \
928 register char *s; \
929 SizeT len_saved = len; \
930 \
931 if (len == 0) \
932 return dst; \
933 \
934 if (is_overlap(dst, src, len, len)) \
935 RECORD_OVERLAP_ERROR("mempcpy", dst, src, len); \
936 \
937 if ( dst > src ) { \
938 d = (char *)dst + len - 1; \
939 s = (char *)src + len - 1; \
940 while ( len-- ) { \
941 *d-- = *s--; \
942 } \
943 } else if ( dst < src ) { \
944 d = (char *)dst; \
945 s = (char *)src; \
946 while ( len-- ) { \
947 *d++ = *s++; \
948 } \
949 } \
950 return (void*)( ((char*)dst) + len_saved ); \
951 }
952
njne6154662009-02-10 04:23:41 +0000953GLIBC25_MEMPCPY(VG_Z_LIBC_SONAME, mempcpy)
njnb4cfbc42009-05-04 04:20:02 +0000954#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +0000955GLIBC25_MEMPCPY(VG_Z_LD_SO_1, mempcpy) /* ld.so.1 */
njnb4cfbc42009-05-04 04:20:02 +0000956#endif
sewardj841b72d2006-12-31 18:55:56 +0000957
958
sewardjb6c04032007-11-13 20:52:29 +0000959#define GLIBC26___MEMCPY_CHK(soname, fnname) \
960 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
961 (void* dst, const void* src, SizeT len, SizeT dstlen ); \
962 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
963 (void* dst, const void* src, SizeT len, SizeT dstlen ) \
964 { \
965 extern void _exit(int status); \
966 register char *d; \
967 register char *s; \
968 \
969 if (dstlen < len) goto badness; \
970 \
971 if (len == 0) \
972 return dst; \
973 \
974 if (is_overlap(dst, src, len, len)) \
975 RECORD_OVERLAP_ERROR("memcpy_chk", dst, src, len); \
976 \
977 if ( dst > src ) { \
978 d = (char *)dst + len - 1; \
979 s = (char *)src + len - 1; \
980 while ( len-- ) { \
981 *d-- = *s--; \
982 } \
983 } else if ( dst < src ) { \
984 d = (char *)dst; \
985 s = (char *)src; \
986 while ( len-- ) { \
987 *d++ = *s++; \
988 } \
989 } \
990 return dst; \
991 badness: \
992 VALGRIND_PRINTF_BACKTRACE( \
993 "*** memcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000994 "program terminated\n"); \
sewardjb6c04032007-11-13 20:52:29 +0000995 _exit(127); \
996 /*NOTREACHED*/ \
997 return NULL; \
998 }
999
njne6154662009-02-10 04:23:41 +00001000GLIBC26___MEMCPY_CHK(VG_Z_LIBC_SONAME, __memcpy_chk)
sewardjb6c04032007-11-13 20:52:29 +00001001
1002
sewardja77687c2010-08-19 13:22:34 +00001003#define STRSTR(soname, fnname) \
1004 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1005 (void* haystack, void* needle); \
1006 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1007 (void* haystack, void* needle) \
1008 { \
1009 UChar* h = (UChar*)haystack; \
1010 UChar* n = (UChar*)needle; \
1011 \
1012 /* find the length of n, not including terminating zero */ \
1013 UWord nlen = 0; \
1014 while (n[nlen]) nlen++; \
1015 \
1016 /* if n is the empty string, match immediately. */ \
1017 if (nlen == 0) return h; \
1018 \
1019 /* assert(nlen >= 1); */ \
1020 UChar n0 = n[0]; \
1021 \
1022 while (1) { \
1023 UChar hh = *h; \
1024 if (hh == 0) return NULL; \
1025 if (hh != n0) { h++; continue; } \
1026 \
1027 UWord i; \
1028 for (i = 0; i < nlen; i++) { \
1029 if (n[i] != h[i]) \
1030 break; \
1031 } \
1032 /* assert(i >= 0 && i <= nlen); */ \
1033 if (i == nlen) \
1034 return h; \
1035 \
1036 h++; \
1037 } \
1038 }
1039
1040#if defined(VGO_linux)
1041STRSTR(VG_Z_LIBC_SONAME, strstr)
1042#endif
1043
1044
1045#define STRPBRK(soname, fnname) \
1046 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1047 (void* sV, void* acceptV); \
1048 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1049 (void* sV, void* acceptV) \
1050 { \
1051 UChar* s = (UChar*)sV; \
1052 UChar* accept = (UChar*)acceptV; \
1053 \
1054 /* find the length of 'accept', not including terminating zero */ \
1055 UWord nacc = 0; \
1056 while (accept[nacc]) nacc++; \
1057 \
1058 /* if n is the empty string, fail immediately. */ \
1059 if (nacc == 0) return NULL; \
1060 \
1061 /* assert(nacc >= 1); */ \
1062 while (1) { \
1063 UWord i; \
1064 UChar sc = *s; \
1065 if (sc == 0) \
1066 break; \
1067 for (i = 0; i < nacc; i++) { \
1068 if (sc == accept[i]) \
1069 return s; \
1070 } \
1071 s++; \
1072 } \
1073 \
1074 return NULL; \
1075 }
1076
1077#if defined(VGO_linux)
1078STRPBRK(VG_Z_LIBC_SONAME, strpbrk)
1079#endif
1080
1081
1082#define STRCSPN(soname, fnname) \
1083 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1084 (void* sV, void* rejectV); \
1085 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1086 (void* sV, void* rejectV) \
1087 { \
1088 UChar* s = (UChar*)sV; \
1089 UChar* reject = (UChar*)rejectV; \
1090 \
1091 /* find the length of 'reject', not including terminating zero */ \
1092 UWord nrej = 0; \
1093 while (reject[nrej]) nrej++; \
1094 \
1095 UWord len = 0; \
1096 while (1) { \
1097 UWord i; \
1098 UChar sc = *s; \
1099 if (sc == 0) \
1100 break; \
1101 for (i = 0; i < nrej; i++) { \
1102 if (sc == reject[i]) \
1103 break; \
1104 } \
1105 /* assert(i >= 0 && i <= nrej); */ \
1106 if (i < nrej) \
1107 break; \
1108 s++; \
1109 len++; \
1110 } \
1111 \
1112 return len; \
1113 }
1114
1115#if defined(VGO_linux)
1116STRCSPN(VG_Z_LIBC_SONAME, strcspn)
1117#endif
1118
1119
sewardjba189352010-08-20 18:24:16 +00001120// And here's a validated strspn replacement, should it
1121// become necessary.
1122//UWord mystrspn( UChar* s, UChar* accept )
1123//{
1124// /* find the length of 'accept', not including terminating zero */
1125// UWord nacc = 0;
1126// while (accept[nacc]) nacc++;
1127// if (nacc == 0) return 0;
1128//
1129// UWord len = 0;
1130// while (1) {
1131// UWord i;
1132// UChar sc = *s;
1133// if (sc == 0)
1134// break;
1135// for (i = 0; i < nacc; i++) {
1136// if (sc == accept[i])
1137// break;
1138// }
1139// assert(i >= 0 && i <= nacc);
1140// if (i == nacc)
1141// break;
1142// s++;
1143// len++;
1144// }
1145//
1146// return len;
1147//}
1148
1149
sewardj31b9ce12006-10-17 01:27:13 +00001150/*------------------------------------------------------------*/
dirk09beb9e2007-04-19 09:47:32 +00001151/*--- Improve definedness checking of process environment ---*/
1152/*------------------------------------------------------------*/
1153
sewardjddc00dd2007-11-27 11:42:47 +00001154#if defined(VGO_linux)
1155
dirk09beb9e2007-04-19 09:47:32 +00001156/* putenv */
njne6154662009-02-10 04:23:41 +00001157int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string);
1158int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string)
dirk09beb9e2007-04-19 09:47:32 +00001159{
1160 OrigFn fn;
1161 Word result;
1162 const char* p = string;
1163 VALGRIND_GET_ORIG_FN(fn);
1164 /* Now by walking over the string we magically produce
1165 traces when hitting undefined memory. */
1166 if (p)
1167 while (*p++)
1168 ;
1169 CALL_FN_W_W(result, fn, string);
1170 return result;
1171}
1172
1173/* unsetenv */
njne6154662009-02-10 04:23:41 +00001174int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name);
1175int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name)
dirk09beb9e2007-04-19 09:47:32 +00001176{
1177 OrigFn fn;
1178 Word result;
1179 const char* p = name;
1180 VALGRIND_GET_ORIG_FN(fn);
1181 /* Now by walking over the string we magically produce
1182 traces when hitting undefined memory. */
1183 if (p)
1184 while (*p++)
1185 ;
1186 CALL_FN_W_W(result, fn, name);
1187 return result;
1188}
1189
1190/* setenv */
njne6154662009-02-10 04:23:41 +00001191int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001192 (const char* name, const char* value, int overwrite);
njne6154662009-02-10 04:23:41 +00001193int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001194 (const char* name, const char* value, int overwrite)
1195{
1196 OrigFn fn;
1197 Word result;
1198 const char* p;
1199 VALGRIND_GET_ORIG_FN(fn);
1200 /* Now by walking over the string we magically produce
1201 traces when hitting undefined memory. */
1202 if (name)
1203 for (p = name; *p; p++)
1204 ;
1205 if (value)
1206 for (p = value; *p; p++)
1207 ;
1208 VALGRIND_CHECK_VALUE_IS_DEFINED (overwrite);
1209 CALL_FN_W_WWW(result, fn, name, value, overwrite);
1210 return result;
1211}
1212
sewardjddc00dd2007-11-27 11:42:47 +00001213#endif /* defined(VGO_linux) */
1214
1215
dirk09beb9e2007-04-19 09:47:32 +00001216/*------------------------------------------------------------*/
sewardj31b9ce12006-10-17 01:27:13 +00001217/*--- AIX stuff only after this point ---*/
1218/*------------------------------------------------------------*/
1219
sewardjddc00dd2007-11-27 11:42:47 +00001220/* Generate replacements for strcat, strncat, strcpy, strncpy, strcmp
sewardj31b9ce12006-10-17 01:27:13 +00001221 in the given soname. */
sewardjddc00dd2007-11-27 11:42:47 +00001222#define Str5FNs(_soname) \
sewardj31b9ce12006-10-17 01:27:13 +00001223 STRCAT(_soname, strcat) \
1224 STRNCAT(_soname, strncat) \
1225 STRCPY(_soname, strcpy) \
sewardjddc00dd2007-11-27 11:42:47 +00001226 STRNCPY(_soname, strncpy) \
1227 STRCMP(_soname, strcmp)
sewardj31b9ce12006-10-17 01:27:13 +00001228
1229#if defined(VGP_ppc32_aix5)
sewardjddc00dd2007-11-27 11:42:47 +00001230Str5FNs(NONE) /* in main exe */
1231Str5FNs(libCZdaZLshrcoreZdoZR) /* libC.a(shrcore.o) */
1232Str5FNs(libX11ZdaZLshr4ZdoZR) /* libX11.a(shr4.o) */
1233Str5FNs(libXmZdaZLshrZaZdoZR) /* libXm.a(shr*.o) */
1234Str5FNs(libXtZdaZLshr4ZdoZR) /* libXt.a(shr4.o) */
1235Str5FNs(libppeZurZdaZLdynamicZdoZR) /* libppe_r.a(dynamic.o) */
1236Str5FNs(libodmZdaZLshrZdoZR) /* libodm.a(shr.o) */
1237Str5FNs(libmpiZurZdaZLmpicoreZurZdoZR) /* libmpi_r.a(mpicore_r.o) */
1238Str5FNs(libmpiZurZdaZLmpipoeZurZdoZR) /* libmpi_r.a(mpipoe_r.o) */
1239Str5FNs(libmpiZurZdaZLmpciZurZdoZR) /* libmpi_r.a(mpci_r.o) */
1240Str5FNs(libslurmZdso) /* libslurm.so */
1241Str5FNs(libglibZdso) /* libglib.so */
1242Str5FNs(libIMZdaZLshrZdoZR) /* libIM.a(shr.o) */
1243Str5FNs(libiconvZdaZLshr4ZdoZR) /* libiconv.a(shr4.o) */
1244Str5FNs(libGLZdaZLshrZdoZR) /* libGL.a(shr.o) */
1245Str5FNs(libgdkZdso) /* libgdk.so */
1246Str5FNs(libcursesZdaZLshr42ZdoZR) /* libcurses.a(shr42.o) */
1247Str5FNs(libqtZda) /* libqt.a */
sewardjfd4b6f42007-11-29 03:08:32 +00001248Str5FNs(ZaZLlibglibZhZaZdsoZaZR) /* *(libglib-*.so*) */
1249Str5FNs(ZaZLlibfontconfigZdsoZaZR) /* *(libfontconfig.so*) */
1250Str5FNs(libQtZaa) /* libQt*.a */
sewardj31b9ce12006-10-17 01:27:13 +00001251#endif
1252#if defined(VGP_ppc64_aix5)
sewardjddc00dd2007-11-27 11:42:47 +00001253Str5FNs(NONE) /* in main exe */
1254Str5FNs(libX11ZdaZLshrZu64ZdoZR) /* libX11.a(shr_64.o) */
1255Str5FNs(libiconvZdaZLshr4Zu64ZdoZR) /* libiconv.a(shr4_64.o) */
1256Str5FNs(libGLZdaZLshrZu64ZdoZR) /* libGL.a(shr_64.o) */
1257Str5FNs(libppeZurZdaZLdynamic64ZdoZR) /* libppe_r.a(dynamic64.o) */
1258Str5FNs(libodmZdaZLshrZu64ZdoZR) /* libodm.a(shr_64.o) */
1259Str5FNs(libmpiZurZdaZLmpicore64ZurZdoZR) /* libmpi_r.a(mpicore64_r.o) */
1260Str5FNs(libmpiZurZdaZLmpipoe64ZurZdoZR) /* libmpi_r.a(mpipoe64_r.o) */
1261Str5FNs(libCZdaZLshrcoreZu64ZdoZR) /* libC.a(shrcore_64.o) */
1262Str5FNs(libmpiZurZdaZLmpci64ZurZdoZR) /* libmpi_r.a(mpci64_r.o) */
1263Str5FNs(libqtZda) /* libqt.a */
sewardjfd4b6f42007-11-29 03:08:32 +00001264Str5FNs(ZaZLlibglibZhZaZdsoZaZR) /* *(libglib-*.so*) */
1265Str5FNs(ZaZLlibfontconfigZdsoZaZR) /* *(libfontconfig.so*) */
1266Str5FNs(libQtZaa) /* libQt*.a */
sewardj31b9ce12006-10-17 01:27:13 +00001267#endif
1268
1269
1270/* AIX's libm contains a sqrt implementation which does a nasty thing:
1271 it loads the initial estimate of the root into a FP register, but
1272 only the upper half of the number is initialised data. Hence the
1273 least significant 32 mantissa bits are undefined, and it then uses
1274 Newton-Raphson iteration to compute the final, defined result.
1275 This fools memcheck completely; the only solution I can think of is
1276 provide our own substitute. The _FAST variant is almost right
1277 except the result is not correctly rounded. The _EXACT variant,
1278 which is selected by default, is always right; but it's also pretty
1279 darn slow. */
1280
1281#if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
1282#define SQRT_FAST(soname, fnname) \
1283 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ); \
1284 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ) \
1285 { \
1286 static UInt T1[32] = \
1287 { 0, 1024, 3062, 5746, 9193, 13348, \
1288 18162, 23592, 29598, 36145, 43202, 50740, \
1289 58733, 67158, 75992, 85215, 83599, 71378, \
1290 60428, 50647, 41945, 34246, 27478, 21581, \
1291 16499, 12183, 8588, 5674, 3403, 1742, \
1292 661, 130 }; \
1293 UInt x0, x1, sign, expo, mant0, bIGENDIAN = 1; \
1294 union { UInt w[2]; double d; } u; \
1295 u.d = x; \
1296 x0 = u.w[1 - bIGENDIAN]; /* high half */ \
1297 x1 = u.w[bIGENDIAN]; /* low half */ \
1298 sign = x0 >> 31; \
1299 expo = (x0 >> 20) & 0x7FF; \
1300 mant0 = x0 & 0xFFFFF; \
1301 if ( (sign == 0 && expo >= 1 && expo <= 0x7FE) /* +normal */ \
1302 || (sign == 0 && expo == 0 \
1303 && (mant0 | x1) > 0) /* +denorm */) { \
1304 /* common case; do Newton-Raphson */ \
1305 /* technically k should be signed int32, but since we're \
1306 always entering here with x > 0, doesn't matter that it's \
1307 unsigned. */ \
1308 double y; \
1309 UInt k = (x0>>1) + 0x1ff80000; \
1310 u.w[1 - bIGENDIAN] = k - T1[31&(k>>15)]; \
1311 u.w[bIGENDIAN] = 0; \
1312 y = u.d; \
1313 y = (y+x/y)/2.0 ; \
1314 y = (y+x/y)/2.0 ; \
1315 y = y-(y-x/y)/2.0 ; \
1316 return y; \
1317 } \
1318 if ( (sign == 1 && expo >= 1 && expo <= 0x7FE) /* -normal */ \
1319 || (sign == 1 && expo == 0 \
1320 && (mant0 | x1) > 0) /* -denorm */) { \
1321 u.w[1 - bIGENDIAN] = 0xFFF00000; \
1322 u.w[bIGENDIAN] = 0x1; \
1323 return u.d; /* -Inf -> NaN */ \
1324 } \
1325 if ((expo | mant0 | x1) == 0) \
1326 return x; /* +/-zero -> self */ \
1327 if (expo == 0x7FF && (mant0 | x1) == 0) { \
1328 if (sign == 0) \
1329 return x; /* +Inf -> self */ \
1330 u.w[1 - bIGENDIAN] = 0xFFF00000; \
1331 u.w[bIGENDIAN] = 0x1; \
1332 return u.d; /* -Inf -> NaN */ \
1333 } \
1334 /* must be +/- NaN */ \
1335 return x; /* +/-NaN -> self */ \
1336 }
1337
1338#define SQRT_EXACT(soname, fnname) \
1339 /* \
1340 * ==================================================== \
1341 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. \
1342 * \
1343 * Developed at SunPro, a Sun Microsystems, Inc. business. \
1344 * Permission to use, copy, modify, and distribute this \
1345 * software is freely granted, provided that this notice \
1346 * is preserved. \
1347 * ==================================================== \
1348 */ \
1349 /* \
1350 * Return correctly rounded sqrt. \
1351 * ------------------------------------------ \
1352 * | Use the hardware sqrt if you have one | \
1353 * ------------------------------------------ \
1354 * Method: \
1355 * Bit by bit method using integer arithmetic. (Slow, but portable) \
1356 * 1. Normalization \
1357 * Scale x to y in [1,4) with even powers of 2: \
1358 * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then \
1359 * sqrt(x) = 2^k * sqrt(y) \
1360 * 2. Bit by bit computation \
1361 * Let q = sqrt(y) truncated to i bit after binary point (q = 1), \
1362 * i 0 \
1363 * i+1 2 \
1364 * s = 2*q , and y = 2 * ( y - q ). (1) \
1365 * i i i i \
1366 * \
1367 * To compute q from q , one checks whether \
1368 * i+1 i \
1369 * \
1370 * -(i+1) 2 \
1371 * (q + 2 ) <= y. (2) \
1372 * i \
1373 * -(i+1) \
1374 * If (2) is false, then q = q ; otherwise q = q + 2 . \
1375 * i+1 i i+1 i \
1376 * \
1377 * With some algebric manipulation, it is not difficult to see \
1378 * that (2) is equivalent to \
1379 * -(i+1) \
1380 * s + 2 <= y (3) \
1381 * i i \
1382 * \
1383 * The advantage of (3) is that s and y can be computed by \
1384 * i i \
1385 * the following recurrence formula: \
1386 * if (3) is false \
1387 * \
1388 * s = s , y = y ; (4) \
1389 * i+1 i i+1 i \
1390 * \
1391 * otherwise, \
1392 * -i -(i+1) \
1393 * s = s + 2 , y = y - s - 2 (5) \
1394 * i+1 i i+1 i i \
1395 * \
1396 * \
1397 * One may easily use induction to prove (4) and (5). \
1398 * Note. Since the left hand side of (3) contain only i+2 bits, \
1399 * it does not necessary to do a full (53-bit) comparison \
1400 * in (3). \
1401 * 3. Final rounding \
1402 * After generating the 53 bits result, we compute one more bit. \
1403 * Together with the remainder, we can decide whether the \
1404 * result is exact, bigger than 1/2ulp, or less than 1/2ulp \
1405 * (it will never equal to 1/2ulp). \
1406 * The rounding mode can be detected by checking whether \
1407 * huge + tiny is equal to huge, and whether huge - tiny is \
1408 * equal to huge for some floating point number "huge" and "tiny". \
1409 * \
1410 * Special cases: \
1411 * sqrt(+-0) = +-0 ... exact \
1412 * sqrt(inf) = inf \
1413 * sqrt(-ve) = NaN ... with invalid signal \
1414 * sqrt(NaN) = NaN ... with invalid signal for signaling NaN \
1415 * \
1416 */ \
1417 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ); \
1418 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ) \
1419 { \
1420 const Int bIGENDIAN = 1; \
1421 const double one = 1.0, tiny=1.0e-300; \
1422 double z; \
1423 Int sign = (Int)0x80000000; \
1424 Int ix0,s0,q,m,t,i; \
1425 UInt r,t1,s1,ix1,q1; \
1426 union { UInt w[2]; double d; } u; \
1427 u.d = x; \
1428 ix0 = u.w[1-bIGENDIAN]; \
1429 ix1 = u.w[bIGENDIAN]; \
1430 \
1431 /* take care of Inf and NaN */ \
1432 if((ix0&0x7ff00000)==0x7ff00000) { \
1433 return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf \
1434 sqrt(-inf)=sNaN */ \
1435 } \
1436 /* take care of zero */ \
1437 if(ix0<=0) { \
1438 if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */ \
1439 else if(ix0<0) \
1440 return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ \
1441 } \
1442 /* normalize x */ \
1443 m = (ix0>>20); \
1444 if(m==0) { /* subnormal x */ \
1445 while(ix0==0) { \
1446 m -= 21; \
1447 ix0 |= (ix1>>11); ix1 <<= 21; \
1448 } \
1449 for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1; \
1450 m -= i-1; \
1451 ix0 |= (ix1>>(32-i)); \
1452 ix1 <<= i; \
1453 } \
1454 m -= 1023; /* unbias exponent */ \
1455 ix0 = (ix0&0x000fffff)|0x00100000; \
1456 if(m&1){ /* odd m, double x to make it even */ \
1457 ix0 += ix0 + ((ix1&sign)>>31); \
1458 ix1 += ix1; \
1459 } \
1460 m >>= 1; /* m = [m/2] */ \
1461 /* generate sqrt(x) bit by bit */ \
1462 ix0 += ix0 + ((ix1&sign)>>31); \
1463 ix1 += ix1; \
1464 q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ \
1465 r = 0x00200000; /* r = moving bit from right to left */ \
1466 while(r!=0) { \
1467 t = s0+r; \
1468 if(t<=ix0) { \
1469 s0 = t+r; \
1470 ix0 -= t; \
1471 q += r; \
1472 } \
1473 ix0 += ix0 + ((ix1&sign)>>31); \
1474 ix1 += ix1; \
1475 r>>=1; \
1476 } \
1477 r = sign; \
1478 while(r!=0) { \
1479 t1 = s1+r; \
1480 t = s0; \
1481 if((t<ix0)||((t==ix0)&&(t1<=ix1))) { \
1482 s1 = t1+r; \
1483 if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1; \
1484 ix0 -= t; \
1485 if (ix1 < t1) ix0 -= 1; \
1486 ix1 -= t1; \
1487 q1 += r; \
1488 } \
1489 ix0 += ix0 + ((ix1&sign)>>31); \
1490 ix1 += ix1; \
1491 r>>=1; \
1492 } \
1493 /* use floating add to find out rounding direction */ \
1494 if((ix0|ix1)!=0) { \
1495 z = one-tiny; /* trigger inexact flag */ \
1496 if (z>=one) { \
1497 z = one+tiny; \
1498 if (q1==(UInt)0xffffffff) { q1=0; q += 1;} \
1499 else if (z>one) { \
1500 if (q1==(UInt)0xfffffffe) q+=1; \
1501 q1+=2; \
1502 } else \
1503 q1 += (q1&1); \
1504 } \
1505 } \
1506 ix0 = (q>>1)+0x3fe00000; \
1507 ix1 = q1>>1; \
1508 if ((q&1)==1) ix1 |= sign; \
1509 ix0 += (m <<20); \
1510 ix0 = u.w[1-bIGENDIAN] = ix0; \
1511 ix1 = u.w[bIGENDIAN] = ix1; \
1512 z = u.d; \
1513 return z; \
1514 }
1515
1516#if 0
1517SQRT_FAST(NONE, sqrt) /* xlC generates these */
1518SQRT_FAST(NONE, _sqrt) /* xlf generates these */
1519#else
1520SQRT_EXACT(NONE, sqrt) /* xlC generates these */
1521SQRT_EXACT(NONE, _sqrt) /* xlf generates these */
1522#endif
1523
1524#endif /* defined(VGP_ppc32_aix5) */
1525
njn3e884182003-04-15 13:03:23 +00001526/*--------------------------------------------------------------------*/
njn46275862005-03-24 04:00:03 +00001527/*--- end ---*/
njn3e884182003-04-15 13:03:23 +00001528/*--------------------------------------------------------------------*/