blob: 64cb7849c04bf5f73600af76b275e72cf84523f5 [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"
tomce6d0ac2010-11-12 10:03:13 +000038#include "config.h"
njnc7561b92005-06-19 01:24:32 +000039
njn34419c12003-05-02 17:24:29 +000040#include "mc_include.h"
fitzhardinge98abfc72003-12-16 02:05:15 +000041#include "memcheck.h"
njn3e884182003-04-15 13:03:23 +000042
tomce6d0ac2010-11-12 10:03:13 +000043#include <ctype.h>
44
njn3e884182003-04-15 13:03:23 +000045/* ---------------------------------------------------------------------
njn1f8b3e72005-03-22 04:27:14 +000046 We have our own versions of these functions for two reasons:
47 (a) it allows us to do overlap checking
48 (b) some of the normal versions are hyper-optimised, which fools
49 Memcheck and cause spurious value warnings. Our versions are
50 simpler.
51
njn16eeb4e2005-06-16 03:56:58 +000052 Note that overenthusiastic use of PLT bypassing by the glibc people also
53 means that we need to patch multiple versions of some of the functions to
54 our own implementations.
55
njn1f8b3e72005-03-22 04:27:14 +000056 THEY RUN ON THE SIMD CPU!
njn3e884182003-04-15 13:03:23 +000057 ------------------------------------------------------------------ */
58
sewardjdda830a2003-07-20 22:28:42 +000059/* Figure out if [dst .. dst+dstlen-1] overlaps with
60 [src .. src+srclen-1].
61 We assume that the address ranges do not wrap around
62 (which is safe since on Linux addresses >= 0xC0000000
63 are not accessible and the program will segfault in this
64 circumstance, presumably).
65*/
njn3e884182003-04-15 13:03:23 +000066static __inline__
njnc6168192004-11-29 13:54:10 +000067Bool is_overlap ( void* dst, const void* src, SizeT dstlen, SizeT srclen )
njn3e884182003-04-15 13:03:23 +000068{
sewardjdda830a2003-07-20 22:28:42 +000069 Addr loS, hiS, loD, hiD;
70
71 if (dstlen == 0 || srclen == 0)
72 return False;
73
74 loS = (Addr)src;
75 loD = (Addr)dst;
76 hiS = loS + srclen - 1;
77 hiD = loD + dstlen - 1;
78
79 /* So figure out if [loS .. hiS] overlaps with [loD .. hiD]. */
80 if (loS < loD) {
81 return !(hiS < loD);
82 }
83 else if (loD < loS) {
84 return !(hiD < loS);
85 }
86 else {
87 /* They start at same place. Since we know neither of them has
88 zero length, they must overlap. */
89 return True;
90 }
njn3e884182003-04-15 13:03:23 +000091}
92
njn1f8b3e72005-03-22 04:27:14 +000093// This is a macro rather than a function because we don't want to have an
94// extra function in the stack trace.
njn718d3b12006-12-16 00:54:12 +000095#define RECORD_OVERLAP_ERROR(s, src, dst, len) \
njn1f8b3e72005-03-22 04:27:14 +000096{ \
97 Word unused_res; \
sewardj0ec07f32006-01-12 12:32:32 +000098 VALGRIND_DO_CLIENT_REQUEST(unused_res, 0, \
99 _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR, \
njn718d3b12006-12-16 00:54:12 +0000100 s, src, dst, len, 0); \
njn3e884182003-04-15 13:03:23 +0000101}
102
njn16eeb4e2005-06-16 03:56:58 +0000103
104#define STRRCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000105 char* VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* s, int c ); \
106 char* VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000107 { \
108 UChar ch = (UChar)((UInt)c); \
109 UChar* p = (UChar*)s; \
110 UChar* last = NULL; \
111 while (True) { \
112 if (*p == ch) last = p; \
113 if (*p == 0) return last; \
114 p++; \
115 } \
njn3e884182003-04-15 13:03:23 +0000116 }
njn3e884182003-04-15 13:03:23 +0000117
njn16eeb4e2005-06-16 03:56:58 +0000118// Apparently rindex() is the same thing as strrchr()
njne6154662009-02-10 04:23:41 +0000119STRRCHR(VG_Z_LIBC_SONAME, strrchr)
120STRRCHR(VG_Z_LIBC_SONAME, rindex)
njnb4cfbc42009-05-04 04:20:02 +0000121#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000122STRRCHR(VG_Z_LIBC_SONAME, __GI_strrchr)
njne6154662009-02-10 04:23:41 +0000123STRRCHR(VG_Z_LD_LINUX_SO_2, rindex)
njnf76d27a2009-05-28 01:53:07 +0000124#elif defined(VGO_darwin)
125STRRCHR(VG_Z_DYLD, strrchr)
126STRRCHR(VG_Z_DYLD, rindex)
njnb4cfbc42009-05-04 04:20:02 +0000127#endif
njn16eeb4e2005-06-16 03:56:58 +0000128
129
130#define STRCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000131 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ); \
132 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* s, int c ) \
njn16eeb4e2005-06-16 03:56:58 +0000133 { \
134 UChar ch = (UChar)((UInt)c); \
135 UChar* p = (UChar*)s; \
136 while (True) { \
137 if (*p == ch) return p; \
138 if (*p == 0) return NULL; \
139 p++; \
140 } \
njn3e884182003-04-15 13:03:23 +0000141 }
njn3e884182003-04-15 13:03:23 +0000142
njn16eeb4e2005-06-16 03:56:58 +0000143// Apparently index() is the same thing as strchr()
njne6154662009-02-10 04:23:41 +0000144STRCHR(VG_Z_LIBC_SONAME, strchr)
njne6154662009-02-10 04:23:41 +0000145STRCHR(VG_Z_LIBC_SONAME, index)
njnb4cfbc42009-05-04 04:20:02 +0000146#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000147STRCHR(VG_Z_LIBC_SONAME, __GI_strchr)
njnb4cfbc42009-05-04 04:20:02 +0000148STRCHR(VG_Z_LD_LINUX_SO_2, strchr)
njne6154662009-02-10 04:23:41 +0000149STRCHR(VG_Z_LD_LINUX_SO_2, index)
njnb4cfbc42009-05-04 04:20:02 +0000150STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr)
njne6154662009-02-10 04:23:41 +0000151STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index)
njnf76d27a2009-05-28 01:53:07 +0000152#elif defined(VGO_darwin)
153STRCHR(VG_Z_DYLD, strchr)
154STRCHR(VG_Z_DYLD, index)
njnb4cfbc42009-05-04 04:20:02 +0000155#endif
njn3e884182003-04-15 13:03:23 +0000156
njn3e884182003-04-15 13:03:23 +0000157
njn16eeb4e2005-06-16 03:56:58 +0000158#define STRCAT(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000159 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ); \
160 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000161 { \
162 const Char* src_orig = src; \
163 Char* dst_orig = dst; \
164 while (*dst) dst++; \
165 while (*src) *dst++ = *src++; \
166 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000167 \
njn16eeb4e2005-06-16 03:56:58 +0000168 /* This is a bit redundant, I think; any overlap and the strcat will */ \
169 /* go forever... or until a seg fault occurs. */ \
170 if (is_overlap(dst_orig, \
171 src_orig, \
172 (Addr)dst-(Addr)dst_orig+1, \
173 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000174 RECORD_OVERLAP_ERROR("strcat", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000175 \
njn16eeb4e2005-06-16 03:56:58 +0000176 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000177 }
njn3e884182003-04-15 13:03:23 +0000178
njne6154662009-02-10 04:23:41 +0000179STRCAT(VG_Z_LIBC_SONAME, strcat)
tomd2645142009-10-29 09:27:11 +0000180#if defined(VGO_linux)
181STRCAT(VG_Z_LIBC_SONAME, __GI_strcat)
182#endif
njn16eeb4e2005-06-16 03:56:58 +0000183
184#define STRNCAT(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000185 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
186 ( char* dst, const char* src, SizeT n ); \
187 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
188 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000189 { \
190 const Char* src_orig = src; \
191 Char* dst_orig = dst; \
192 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000193 \
njn16eeb4e2005-06-16 03:56:58 +0000194 while (*dst) dst++; \
195 while (m < n && *src) { m++; *dst++ = *src++; } /* concat <= n chars */ \
196 *dst = 0; /* always add null */ \
sewardjb6c04032007-11-13 20:52:29 +0000197 \
njn16eeb4e2005-06-16 03:56:58 +0000198 /* This checks for overlap after copying, unavoidable without */ \
199 /* pre-counting lengths... should be ok */ \
200 if (is_overlap(dst_orig, \
201 src_orig, \
202 (Addr)dst-(Addr)dst_orig+1, \
203 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000204 RECORD_OVERLAP_ERROR("strncat", dst_orig, src_orig, n); \
sewardjb6c04032007-11-13 20:52:29 +0000205 \
njn16eeb4e2005-06-16 03:56:58 +0000206 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000207 }
njn3e884182003-04-15 13:03:23 +0000208
njne6154662009-02-10 04:23:41 +0000209STRNCAT(VG_Z_LIBC_SONAME, strncat)
njnf76d27a2009-05-28 01:53:07 +0000210#if defined(VGO_darwin)
211STRNCAT(VG_Z_DYLD, strncat)
212#endif
213
214
215/* Append src to dst. n is the size of dst's buffer. dst is guaranteed
216 to be nul-terminated after the copy, unless n <= strlen(dst_orig).
217 Returns min(n, strlen(dst_orig)) + strlen(src_orig).
218 Truncation occurred if retval >= n.
219*/
220#define STRLCAT(soname, fnname) \
221 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
222 ( char* dst, const char* src, SizeT n ); \
223 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
224 ( char* dst, const char* src, SizeT n ) \
225 { \
226 const Char* src_orig = src; \
227 Char* dst_orig = dst; \
228 SizeT m = 0; \
229\
230 while (m < n && *dst) { m++; dst++; } \
231 if (m < n) { \
232 /* Fill as far as dst_orig[n-2], then nul-terminate. */ \
233 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
234 *dst = 0; \
235 } else { \
236 /* No space to copy anything to dst. m == n */ \
237 } \
238 /* Finish counting min(n, strlen(dst_orig)) + strlen(src_orig) */ \
239 while (*src) { m++; src++; } \
240 /* This checks for overlap after copying, unavoidable without */ \
241 /* pre-counting lengths... should be ok */ \
242 if (is_overlap(dst_orig, \
243 src_orig, \
244 (Addr)dst-(Addr)dst_orig+1, \
245 (Addr)src-(Addr)src_orig+1)) \
246 RECORD_OVERLAP_ERROR("strlcat", dst_orig, src_orig, n); \
247\
248 return m; \
249 }
250
251#if defined(VGO_darwin)
252STRLCAT(VG_Z_LIBC_SONAME, strlcat)
253STRLCAT(VG_Z_DYLD, strlcat)
254#endif
sewardj31b9ce12006-10-17 01:27:13 +0000255
njn3e884182003-04-15 13:03:23 +0000256
njn16eeb4e2005-06-16 03:56:58 +0000257#define STRNLEN(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000258 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* str, SizeT n ); \
259 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) ( const char* str, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000260 { \
261 SizeT i = 0; \
262 while (i < n && str[i] != 0) i++; \
263 return i; \
njn3e884182003-04-15 13:03:23 +0000264 }
njn3e884182003-04-15 13:03:23 +0000265
njne6154662009-02-10 04:23:41 +0000266STRNLEN(VG_Z_LIBC_SONAME, strnlen)
tomd2645142009-10-29 09:27:11 +0000267#if defined(VGO_linux)
268STRNLEN(VG_Z_LIBC_SONAME, __GI_strnlen)
269#endif
njn16eeb4e2005-06-16 03:56:58 +0000270
sewardj3ceec242003-07-30 21:24:25 +0000271
njn5ec15ed2005-08-24 19:55:51 +0000272// Note that this replacement often doesn't get used because gcc inlines
273// calls to strlen() with its own built-in version. This can be very
274// confusing if you aren't expecting it. Other small functions in this file
275// may also be inline by gcc.
njn16eeb4e2005-06-16 03:56:58 +0000276#define STRLEN(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000277 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ); \
278 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname)( const char* str ) \
njn16eeb4e2005-06-16 03:56:58 +0000279 { \
280 SizeT i = 0; \
281 while (str[i] != 0) i++; \
282 return i; \
sewardj3ceec242003-07-30 21:24:25 +0000283 }
njn16eeb4e2005-06-16 03:56:58 +0000284
njnb4cfbc42009-05-04 04:20:02 +0000285STRLEN(VG_Z_LIBC_SONAME, strlen)
286#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000287STRLEN(VG_Z_LIBC_SONAME, __GI_strlen)
njne6154662009-02-10 04:23:41 +0000288STRLEN(VG_Z_LD_LINUX_SO_2, strlen)
289STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen)
njnb4cfbc42009-05-04 04:20:02 +0000290#endif
sewardj31b9ce12006-10-17 01:27:13 +0000291
njn16eeb4e2005-06-16 03:56:58 +0000292
293#define STRCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000294 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ); \
295 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000296 { \
297 const Char* src_orig = src; \
298 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000299 \
njn16eeb4e2005-06-16 03:56:58 +0000300 while (*src) *dst++ = *src++; \
301 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000302 \
njn16eeb4e2005-06-16 03:56:58 +0000303 /* This checks for overlap after copying, unavoidable without */ \
304 /* pre-counting length... should be ok */ \
305 if (is_overlap(dst_orig, \
306 src_orig, \
307 (Addr)dst-(Addr)dst_orig+1, \
308 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000309 RECORD_OVERLAP_ERROR("strcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000310 \
njn16eeb4e2005-06-16 03:56:58 +0000311 return dst_orig; \
312 }
313
njne6154662009-02-10 04:23:41 +0000314STRCPY(VG_Z_LIBC_SONAME, strcpy)
tomd2645142009-10-29 09:27:11 +0000315#if defined(VGO_linux)
316STRCPY(VG_Z_LIBC_SONAME, __GI_strcpy)
317#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000318STRCPY(VG_Z_DYLD, strcpy)
319#endif
njn16eeb4e2005-06-16 03:56:58 +0000320
321
322#define STRNCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000323 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) \
324 ( char* dst, const char* src, SizeT n ); \
325 char* VG_REPLACE_FUNCTION_ZU(soname, fnname) \
326 ( char* dst, const char* src, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000327 { \
328 const Char* src_orig = src; \
329 Char* dst_orig = dst; \
330 SizeT m = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000331 \
njn16eeb4e2005-06-16 03:56:58 +0000332 while (m < n && *src) { m++; *dst++ = *src++; } \
333 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
334 /* but only m+1 bytes of src if terminator was found */ \
335 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
njn718d3b12006-12-16 00:54:12 +0000336 RECORD_OVERLAP_ERROR("strncpy", dst, src, n); \
njn16eeb4e2005-06-16 03:56:58 +0000337 while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */ \
338 \
339 return dst_orig; \
340 }
341
njne6154662009-02-10 04:23:41 +0000342STRNCPY(VG_Z_LIBC_SONAME, strncpy)
tomd2645142009-10-29 09:27:11 +0000343#if defined(VGO_linux)
344STRNCPY(VG_Z_LIBC_SONAME, __GI_strncpy)
345#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000346STRNCPY(VG_Z_DYLD, strncpy)
347#endif
348
349
350/* Copy up to n-1 bytes from src to dst. Then nul-terminate dst if n > 0.
351 Returns strlen(src). Does not zero-fill the remainder of dst. */
352#define STRLCPY(soname, fnname) \
353 SizeT VG_REPLACE_FUNCTION_ZU(soname, fnname) \
354 ( char* dst, const char* src, SizeT n ); \
355 SizeT VG_REPLACE_FUNCTION_ZU(soname, fnname) \
356 ( char* dst, const char* src, SizeT n ) \
357 { \
358 const char* src_orig = src; \
359 char* dst_orig = dst; \
360 SizeT m = 0; \
361\
362 while (m < n-1 && *src) { m++; *dst++ = *src++; } \
363 /* m non-nul bytes have now been copied, and m <= n-1. */ \
364 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
365 /* but only m+1 bytes of src if terminator was found */ \
366 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
367 RECORD_OVERLAP_ERROR("strlcpy", dst, src, n); \
368 /* Nul-terminate dst. */ \
369 if (n > 0) *dst = 0; \
370 /* Finish counting strlen(src). */ \
371 while (*src) src++; \
372 return src - src_orig; \
373 }
374
375#if defined(VGO_darwin)
376STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
377STRLCPY(VG_Z_DYLD, strlcpy)
378#endif
njn16eeb4e2005-06-16 03:56:58 +0000379
380
381#define STRNCMP(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000382 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
383 ( const char* s1, const char* s2, SizeT nmax ); \
384 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
385 ( const char* s1, const char* s2, SizeT nmax ) \
njn16eeb4e2005-06-16 03:56:58 +0000386 { \
387 SizeT n = 0; \
388 while (True) { \
389 if (n >= nmax) return 0; \
390 if (*s1 == 0 && *s2 == 0) return 0; \
391 if (*s1 == 0) return -1; \
392 if (*s2 == 0) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000393 \
njn16eeb4e2005-06-16 03:56:58 +0000394 if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1; \
395 if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1; \
sewardjb6c04032007-11-13 20:52:29 +0000396 \
njn16eeb4e2005-06-16 03:56:58 +0000397 s1++; s2++; n++; \
398 } \
399 }
400
njne6154662009-02-10 04:23:41 +0000401STRNCMP(VG_Z_LIBC_SONAME, strncmp)
tomd2645142009-10-29 09:27:11 +0000402#if defined(VGO_linux)
403STRNCMP(VG_Z_LIBC_SONAME, __GI_strncmp)
404#elif defined(VGO_darwin)
njnf76d27a2009-05-28 01:53:07 +0000405STRNCMP(VG_Z_DYLD, strncmp)
406#endif
njn16eeb4e2005-06-16 03:56:58 +0000407
408
tomce6d0ac2010-11-12 10:03:13 +0000409#define STRCASECMP(soname, fnname) \
410 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
411 ( const char* s1, const char* s2 ); \
412 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
413 ( const char* s1, const char* s2 ) \
414 { \
415 register unsigned char c1; \
416 register unsigned char c2; \
417 while (True) { \
418 c1 = tolower(*(unsigned char *)s1); \
419 c2 = tolower(*(unsigned char *)s2); \
420 if (c1 != c2) break; \
421 if (c1 == 0) break; \
422 s1++; s2++; \
423 } \
424 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
425 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
426 return 0; \
427 }
428
429STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp)
430#if defined(VGO_linux)
431STRCASECMP(VG_Z_LIBC_SONAME, __GI_strcasecmp)
432#endif
433
434
435#define STRNCASECMP(soname, fnname) \
436 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
437 ( const char* s1, const char* s2, SizeT nmax ); \
438 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
439 ( const char* s1, const char* s2, SizeT nmax ) \
440 { \
441 SizeT n = 0; \
442 while (True) { \
443 if (n >= nmax) return 0; \
444 if (*s1 == 0 && *s2 == 0) return 0; \
445 if (*s1 == 0) return -1; \
446 if (*s2 == 0) return 1; \
447 \
448 if (tolower(*(unsigned char*)s1) < tolower(*(unsigned char*)s2)) return -1; \
449 if (tolower(*(unsigned char*)s1) > tolower(*(unsigned char*)s2)) return 1; \
450 \
451 s1++; s2++; n++; \
452 } \
453 }
454
455STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp)
456#if defined(VGO_linux)
457STRNCASECMP(VG_Z_LIBC_SONAME, __GI_strncasecmp)
458#elif defined(VGO_darwin)
459STRNCASECMP(VG_Z_DYLD, strncasecmp)
460#endif
461
462
463#ifdef HAVE_TOLOWER_L
464
465
466#define STRCASECMP_L(soname, fnname) \
467 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
468 ( const char* s1, const char* s2, locale_t locale ); \
469 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
470 ( const char* s1, const char* s2, locale_t locale ) \
471 { \
472 register unsigned char c1; \
473 register unsigned char c2; \
474 while (True) { \
475 c1 = tolower_l(*(unsigned char *)s1, locale); \
476 c2 = tolower_l(*(unsigned char *)s2, locale); \
477 if (c1 != c2) break; \
478 if (c1 == 0) break; \
479 s1++; s2++; \
480 } \
481 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
482 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
483 return 0; \
484 }
485
486STRCASECMP_L(VG_Z_LIBC_SONAME, strcasecmp_l)
487#if defined(VGO_linux)
488STRCASECMP_L(VG_Z_LIBC_SONAME, __GI_strcasecmp_l)
489#endif
490
491
492#define STRNCASECMP_L(soname, fnname) \
493 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
494 ( const char* s1, const char* s2, SizeT nmax, locale_t locale ); \
495 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
496 ( const char* s1, const char* s2, SizeT nmax, locale_t locale ) \
497 { \
498 SizeT n = 0; \
499 while (True) { \
500 if (n >= nmax) return 0; \
501 if (*s1 == 0 && *s2 == 0) return 0; \
502 if (*s1 == 0) return -1; \
503 if (*s2 == 0) return 1; \
504 \
505 if (tolower_l(*(unsigned char*)s1, locale) < tolower_l(*(unsigned char*)s2, locale)) return -1; \
506 if (tolower_l(*(unsigned char*)s1, locale) > tolower_l(*(unsigned char*)s2, locale)) return 1; \
507 \
508 s1++; s2++; n++; \
509 } \
510 }
511
512STRNCASECMP_L(VG_Z_LIBC_SONAME, strncasecmp_l)
513#if defined(VGO_linux)
514STRNCASECMP_L(VG_Z_LIBC_SONAME, __GI_strncasecmp_l)
515#elif defined(VGO_darwin)
516STRNCASECMP_L(VG_Z_DYLD, strncasecmp_l)
517#endif
518
519
520#endif
521
522
njn16eeb4e2005-06-16 03:56:58 +0000523#define STRCMP(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000524 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
525 ( const char* s1, const char* s2 ); \
526 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
527 ( const char* s1, const char* s2 ) \
njn16eeb4e2005-06-16 03:56:58 +0000528 { \
529 register unsigned char c1; \
530 register unsigned char c2; \
531 while (True) { \
532 c1 = *(unsigned char *)s1; \
533 c2 = *(unsigned char *)s2; \
534 if (c1 != c2) break; \
535 if (c1 == 0) break; \
536 s1++; s2++; \
537 } \
538 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
539 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
540 return 0; \
541 }
542
njne6154662009-02-10 04:23:41 +0000543STRCMP(VG_Z_LIBC_SONAME, strcmp)
njnb4cfbc42009-05-04 04:20:02 +0000544#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000545STRCMP(VG_Z_LIBC_SONAME, __GI_strcmp)
njne6154662009-02-10 04:23:41 +0000546STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp)
547STRCMP(VG_Z_LD64_SO_1, strcmp)
njnb4cfbc42009-05-04 04:20:02 +0000548#endif
njn16eeb4e2005-06-16 03:56:58 +0000549
550
551#define MEMCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000552 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const void *s, int c, SizeT n); \
553 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const void *s, int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000554 { \
555 SizeT i; \
556 UChar c0 = (UChar)c; \
557 UChar* p = (UChar*)s; \
558 for (i = 0; i < n; i++) \
559 if (p[i] == c0) return (void*)(&p[i]); \
560 return NULL; \
561 }
562
njne6154662009-02-10 04:23:41 +0000563MEMCHR(VG_Z_LIBC_SONAME, memchr)
njnf76d27a2009-05-28 01:53:07 +0000564#if defined(VGO_darwin)
565MEMCHR(VG_Z_DYLD, memchr)
566#endif
njn16eeb4e2005-06-16 03:56:58 +0000567
568
569#define MEMCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000570 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
571 ( void *dst, const void *src, SizeT len ); \
572 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
573 ( void *dst, const void *src, SizeT len ) \
njn16eeb4e2005-06-16 03:56:58 +0000574 { \
njn16eeb4e2005-06-16 03:56:58 +0000575 if (is_overlap(dst, src, len, len)) \
njn718d3b12006-12-16 00:54:12 +0000576 RECORD_OVERLAP_ERROR("memcpy", dst, src, len); \
sewardjb6c04032007-11-13 20:52:29 +0000577 \
sewardj7b4e00b2010-08-24 09:05:52 +0000578 const Addr WS = sizeof(UWord); /* 8 or 4 */ \
579 const Addr WM = WS - 1; /* 7 or 3 */ \
580 \
581 if (dst < src) { \
582 \
583 /* Copying backwards. */ \
584 SizeT n = len; \
585 Addr d = (Addr)dst; \
586 Addr s = (Addr)src; \
587 \
588 if (((s^d) & WM) == 0) { \
589 /* s and d have same UWord alignment. */ \
590 /* Pull up to a UWord boundary. */ \
591 while ((s & WM) != 0 && n >= 1) \
592 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
593 /* Copy UWords. */ \
594 while (n >= WS) \
595 { *(UWord*)d = *(UWord*)s; s += WS; d += WS; n -= WS; } \
596 if (n == 0) \
597 return dst; \
njn16eeb4e2005-06-16 03:56:58 +0000598 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000599 if (((s|d) & 1) == 0) { \
600 /* Both are 16-aligned; copy what we can thusly. */ \
601 while (n >= 2) \
602 { *(UShort*)d = *(UShort*)s; s += 2; d += 2; n -= 2; } \
njn16eeb4e2005-06-16 03:56:58 +0000603 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000604 /* Copy leftovers, or everything if misaligned. */ \
605 while (n >= 1) \
606 { *(UChar*)d = *(UChar*)s; s += 1; d += 1; n -= 1; } \
607 \
608 } else if (dst > src) { \
609 \
610 SizeT n = len; \
611 Addr d = ((Addr)dst) + n; \
612 Addr s = ((Addr)src) + n; \
613 \
614 /* Copying forwards. */ \
615 if (((s^d) & WM) == 0) { \
616 /* s and d have same UWord alignment. */ \
617 /* Back down to a UWord boundary. */ \
618 while ((s & WM) != 0 && n >= 1) \
619 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
620 /* Copy UWords. */ \
621 while (n >= WS) \
622 { s -= WS; d -= WS; *(UWord*)d = *(UWord*)s; n -= WS; } \
623 if (n == 0) \
624 return dst; \
njn16eeb4e2005-06-16 03:56:58 +0000625 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000626 if (((s|d) & 1) == 0) { \
627 /* Both are 16-aligned; copy what we can thusly. */ \
628 while (n >= 2) \
629 { s -= 2; d -= 2; *(UShort*)d = *(UShort*)s; n -= 2; } \
njn16eeb4e2005-06-16 03:56:58 +0000630 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000631 /* Copy leftovers, or everything if misaligned. */ \
632 while (n >= 1) \
633 { s -= 1; d -= 1; *(UChar*)d = *(UChar*)s; n -= 1; } \
634 \
njn16eeb4e2005-06-16 03:56:58 +0000635 } \
sewardj7b4e00b2010-08-24 09:05:52 +0000636 \
njn16eeb4e2005-06-16 03:56:58 +0000637 return dst; \
638 }
639
njne6154662009-02-10 04:23:41 +0000640MEMCPY(VG_Z_LIBC_SONAME, memcpy)
njnb4cfbc42009-05-04 04:20:02 +0000641#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +0000642MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */
643MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */
njnf76d27a2009-05-28 01:53:07 +0000644#elif defined(VGO_darwin)
645MEMCPY(VG_Z_DYLD, memcpy)
njnb4cfbc42009-05-04 04:20:02 +0000646#endif
sewardjf0b34322007-01-16 21:42:28 +0000647/* icc9 blats these around all over the place. Not only in the main
648 executable but various .so's. They are highly tuned and read
649 memory beyond the source boundary (although work correctly and
650 never go across page boundaries), so give errors when run natively,
651 at least for misaligned source arg. Just intercepting in the exe
652 only until we understand more about the problem. See
653 http://bugs.kde.org/show_bug.cgi?id=139776
654 */
655MEMCPY(NONE, _intel_fast_memcpy)
sewardj31b9ce12006-10-17 01:27:13 +0000656
njn16eeb4e2005-06-16 03:56:58 +0000657
658#define MEMCMP(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000659 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
660 ( const void *s1V, const void *s2V, SizeT n ); \
661 int VG_REPLACE_FUNCTION_ZU(soname,fnname) \
662 ( const void *s1V, const void *s2V, SizeT n ) \
njn16eeb4e2005-06-16 03:56:58 +0000663 { \
664 int res; \
665 unsigned char a0; \
666 unsigned char b0; \
667 unsigned char* s1 = (unsigned char*)s1V; \
668 unsigned char* s2 = (unsigned char*)s2V; \
sewardjb6c04032007-11-13 20:52:29 +0000669 \
njn16eeb4e2005-06-16 03:56:58 +0000670 while (n != 0) { \
671 a0 = s1[0]; \
672 b0 = s2[0]; \
673 s1 += 1; \
674 s2 += 1; \
675 res = ((int)a0) - ((int)b0); \
676 if (res != 0) \
677 return res; \
678 n -= 1; \
679 } \
680 return 0; \
681 }
682
njne6154662009-02-10 04:23:41 +0000683MEMCMP(VG_Z_LIBC_SONAME, memcmp)
684MEMCMP(VG_Z_LIBC_SONAME, bcmp)
njnb4cfbc42009-05-04 04:20:02 +0000685#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +0000686MEMCMP(VG_Z_LD_SO_1, bcmp)
njnf76d27a2009-05-28 01:53:07 +0000687#elif defined(VGO_darwin)
688MEMCMP(VG_Z_DYLD, memcmp)
689MEMCMP(VG_Z_DYLD, bcmp)
njnb4cfbc42009-05-04 04:20:02 +0000690#endif
njn3e884182003-04-15 13:03:23 +0000691
jseward0845ef82003-12-22 22:31:27 +0000692
693/* Copy SRC to DEST, returning the address of the terminating '\0' in
694 DEST. (minor variant of strcpy) */
njn16eeb4e2005-06-16 03:56:58 +0000695#define STPCPY(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000696 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ); \
697 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( char* dst, const char* src ) \
njn16eeb4e2005-06-16 03:56:58 +0000698 { \
699 const Char* src_orig = src; \
700 Char* dst_orig = dst; \
sewardjb6c04032007-11-13 20:52:29 +0000701 \
njn16eeb4e2005-06-16 03:56:58 +0000702 while (*src) *dst++ = *src++; \
703 *dst = 0; \
sewardjb6c04032007-11-13 20:52:29 +0000704 \
njn16eeb4e2005-06-16 03:56:58 +0000705 /* This checks for overlap after copying, unavoidable without */ \
706 /* pre-counting length... should be ok */ \
707 if (is_overlap(dst_orig, \
708 src_orig, \
709 (Addr)dst-(Addr)dst_orig+1, \
710 (Addr)src-(Addr)src_orig+1)) \
njn718d3b12006-12-16 00:54:12 +0000711 RECORD_OVERLAP_ERROR("stpcpy", dst_orig, src_orig, 0); \
sewardjb6c04032007-11-13 20:52:29 +0000712 \
njn16eeb4e2005-06-16 03:56:58 +0000713 return dst; \
sewardj44e495f2005-05-12 17:58:28 +0000714 }
njn16eeb4e2005-06-16 03:56:58 +0000715
njne6154662009-02-10 04:23:41 +0000716STPCPY(VG_Z_LIBC_SONAME, stpcpy)
njnb4cfbc42009-05-04 04:20:02 +0000717#if defined(VGO_linux)
tomd2645142009-10-29 09:27:11 +0000718STPCPY(VG_Z_LIBC_SONAME, __GI_stpcpy)
njne6154662009-02-10 04:23:41 +0000719STPCPY(VG_Z_LD_LINUX_SO_2, stpcpy)
720STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy)
njnf76d27a2009-05-28 01:53:07 +0000721#elif defined(VGO_darwin)
722STPCPY(VG_Z_DYLD, stpcpy)
njnb4cfbc42009-05-04 04:20:02 +0000723#endif
724
njn16eeb4e2005-06-16 03:56:58 +0000725
726#define MEMSET(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000727 void* VG_REPLACE_FUNCTION_ZU(soname,fnname)(void *s, Int c, SizeT n); \
728 void* VG_REPLACE_FUNCTION_ZU(soname,fnname)(void *s, Int c, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000729 { \
sewardj7b4e00b2010-08-24 09:05:52 +0000730 Addr a = (Addr)s; \
731 UInt c4 = (c & 0xFF); \
732 c4 = (c4 << 8) | c4; \
733 c4 = (c4 << 16) | c4; \
734 while ((a & 3) != 0 && n >= 1) \
735 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
736 while (n >= 4) \
737 { *(UInt*)a = c4; a += 4; n -= 4; } \
738 while (n >= 1) \
739 { *(UChar*)a = (UChar)c; a += 1; n -= 1; } \
njn16eeb4e2005-06-16 03:56:58 +0000740 return s; \
sewardj44e495f2005-05-12 17:58:28 +0000741 }
njn16eeb4e2005-06-16 03:56:58 +0000742
njne6154662009-02-10 04:23:41 +0000743MEMSET(VG_Z_LIBC_SONAME, memset)
njnf76d27a2009-05-28 01:53:07 +0000744#if defined(VGO_darwin)
745MEMSET(VG_Z_DYLD, memset)
746#endif
njn16eeb4e2005-06-16 03:56:58 +0000747
748
749#define MEMMOVE(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000750 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
751 (void *dstV, const void *srcV, SizeT n); \
752 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
753 (void *dstV, const void *srcV, SizeT n) \
njn16eeb4e2005-06-16 03:56:58 +0000754 { \
755 SizeT i; \
756 Char* dst = (Char*)dstV; \
757 Char* src = (Char*)srcV; \
758 if (dst < src) { \
759 for (i = 0; i < n; i++) \
760 dst[i] = src[i]; \
761 } \
762 else \
763 if (dst > src) { \
764 for (i = 0; i < n; i++) \
765 dst[n-i-1] = src[n-i-1]; \
766 } \
767 return dst; \
768 }
769
njne6154662009-02-10 04:23:41 +0000770MEMMOVE(VG_Z_LIBC_SONAME, memmove)
njnf76d27a2009-05-28 01:53:07 +0000771#if defined(VGO_darwin)
772MEMMOVE(VG_Z_DYLD, memmove)
773#endif
774
775
776#define BCOPY(soname, fnname) \
777 void VG_REPLACE_FUNCTION_ZU(soname,fnname) \
778 (const void *srcV, void *dstV, SizeT n); \
779 void VG_REPLACE_FUNCTION_ZU(soname,fnname) \
780 (const void *srcV, void *dstV, SizeT n) \
781 { \
782 SizeT i; \
783 Char* dst = (Char*)dstV; \
784 Char* src = (Char*)srcV; \
785 if (dst < src) { \
786 for (i = 0; i < n; i++) \
787 dst[i] = src[i]; \
788 } \
789 else \
790 if (dst > src) { \
791 for (i = 0; i < n; i++) \
792 dst[n-i-1] = src[n-i-1]; \
793 } \
794 }
795
796#if defined(VGO_darwin)
797BCOPY(VG_Z_LIBC_SONAME, bcopy)
798BCOPY(VG_Z_DYLD, bcopy)
799#endif
sewardj44e495f2005-05-12 17:58:28 +0000800
jseward0845ef82003-12-22 22:31:27 +0000801
sewardj24cb2172007-02-23 09:03:26 +0000802/* glibc 2.5 variant of memmove which checks the dest is big enough.
803 There is no specific part of glibc that this is copied from. */
804#define GLIBC25___MEMMOVE_CHK(soname, fnname) \
805 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
806 (void *dstV, const void *srcV, SizeT n, SizeT destlen); \
807 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
808 (void *dstV, const void *srcV, SizeT n, SizeT destlen) \
809 { \
810 extern void _exit(int status); \
811 SizeT i; \
812 Char* dst = (Char*)dstV; \
813 Char* src = (Char*)srcV; \
814 if (destlen < n) \
815 goto badness; \
816 if (dst < src) { \
817 for (i = 0; i < n; i++) \
818 dst[i] = src[i]; \
819 } \
820 else \
821 if (dst > src) { \
822 for (i = 0; i < n; i++) \
823 dst[n-i-1] = src[n-i-1]; \
824 } \
825 return dst; \
826 badness: \
827 VALGRIND_PRINTF_BACKTRACE( \
828 "*** memmove_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000829 "program terminated\n"); \
sewardj24cb2172007-02-23 09:03:26 +0000830 _exit(127); \
sewardjc271ec82007-02-27 22:36:14 +0000831 /*NOTREACHED*/ \
832 return NULL; \
sewardj24cb2172007-02-23 09:03:26 +0000833 }
834
njne6154662009-02-10 04:23:41 +0000835GLIBC25___MEMMOVE_CHK(VG_Z_LIBC_SONAME, __memmove_chk)
sewardj24cb2172007-02-23 09:03:26 +0000836
837
sewardj4e9a4b62004-11-23 00:20:17 +0000838/* Find the first occurrence of C in S or the final NUL byte. */
njn16eeb4e2005-06-16 03:56:58 +0000839#define GLIBC232_STRCHRNUL(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000840 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in); \
841 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +0000842 { \
843 unsigned char c = (unsigned char) c_in; \
844 unsigned char* char_ptr = (unsigned char *)s; \
845 while (1) { \
846 if (*char_ptr == 0) return char_ptr; \
847 if (*char_ptr == c) return char_ptr; \
848 char_ptr++; \
849 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000850 }
njn16eeb4e2005-06-16 03:56:58 +0000851
njne6154662009-02-10 04:23:41 +0000852GLIBC232_STRCHRNUL(VG_Z_LIBC_SONAME, strchrnul)
sewardj4e9a4b62004-11-23 00:20:17 +0000853
854
855/* Find the first occurrence of C in S. */
njn16eeb4e2005-06-16 03:56:58 +0000856#define GLIBC232_RAWMEMCHR(soname, fnname) \
sewardj0ec07f32006-01-12 12:32:32 +0000857 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in); \
858 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) (const char* s, int c_in) \
njn16eeb4e2005-06-16 03:56:58 +0000859 { \
860 unsigned char c = (unsigned char) c_in; \
861 unsigned char* char_ptr = (unsigned char *)s; \
862 while (1) { \
863 if (*char_ptr == c) return char_ptr; \
864 char_ptr++; \
865 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000866 }
njn16eeb4e2005-06-16 03:56:58 +0000867
njne6154662009-02-10 04:23:41 +0000868GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, rawmemchr)
tomd2645142009-10-29 09:27:11 +0000869#if defined (VGO_linux)
870GLIBC232_RAWMEMCHR(VG_Z_LIBC_SONAME, __GI___rawmemchr)
871#endif
sewardj4e9a4b62004-11-23 00:20:17 +0000872
sewardjdc5d8322007-01-28 06:32:01 +0000873/* glibc variant of strcpy that checks the dest is big enough.
874 Copied from glibc-2.5/debug/test-strcpy_chk.c. */
sewardj620e5262006-12-31 00:22:30 +0000875#define GLIBC25___STRCPY_CHK(soname,fnname) \
876 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
877 (char* dst, const char* src, SizeT len); \
878 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
879 (char* dst, const char* src, SizeT len) \
880 { \
881 extern void _exit(int status); \
882 char* ret = dst; \
883 if (! len) \
884 goto badness; \
885 while ((*dst++ = *src++) != '\0') \
886 if (--len == 0) \
887 goto badness; \
888 return ret; \
889 badness: \
890 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +0000891 "*** strcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000892 "program terminated\n"); \
sewardj620e5262006-12-31 00:22:30 +0000893 _exit(127); \
894 /*NOTREACHED*/ \
895 return NULL; \
896 }
897
njne6154662009-02-10 04:23:41 +0000898GLIBC25___STRCPY_CHK(VG_Z_LIBC_SONAME, __strcpy_chk)
sewardj620e5262006-12-31 00:22:30 +0000899
900
sewardjdc5d8322007-01-28 06:32:01 +0000901/* glibc variant of stpcpy that checks the dest is big enough.
902 Copied from glibc-2.5/debug/test-stpcpy_chk.c. */
sewardjb8d03852007-01-27 00:49:44 +0000903#define GLIBC25___STPCPY_CHK(soname,fnname) \
904 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
905 (char* dst, const char* src, SizeT len); \
906 char* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
907 (char* dst, const char* src, SizeT len) \
908 { \
909 extern void _exit(int status); \
sewardjdc5d8322007-01-28 06:32:01 +0000910 if (! len) \
911 goto badness; \
912 while ((*dst++ = *src++) != '\0') \
913 if (--len == 0) \
sewardjb8d03852007-01-27 00:49:44 +0000914 goto badness; \
sewardjb8d03852007-01-27 00:49:44 +0000915 return dst - 1; \
916 badness: \
917 VALGRIND_PRINTF_BACKTRACE( \
sewardj24cb2172007-02-23 09:03:26 +0000918 "*** stpcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +0000919 "program terminated\n"); \
sewardjb8d03852007-01-27 00:49:44 +0000920 _exit(127); \
921 /*NOTREACHED*/ \
922 return NULL; \
923 }
924
njne6154662009-02-10 04:23:41 +0000925GLIBC25___STPCPY_CHK(VG_Z_LIBC_SONAME, __stpcpy_chk)
sewardjb8d03852007-01-27 00:49:44 +0000926
927
sewardj841b72d2006-12-31 18:55:56 +0000928/* mempcpy */
929#define GLIBC25_MEMPCPY(soname, fnname) \
930 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
931 ( void *dst, const void *src, SizeT len ); \
932 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
933 ( void *dst, const void *src, SizeT len ) \
934 { \
935 register char *d; \
936 register char *s; \
937 SizeT len_saved = len; \
938 \
939 if (len == 0) \
940 return dst; \
941 \
942 if (is_overlap(dst, src, len, len)) \
943 RECORD_OVERLAP_ERROR("mempcpy", dst, src, len); \
944 \
945 if ( dst > src ) { \
946 d = (char *)dst + len - 1; \
947 s = (char *)src + len - 1; \
948 while ( len-- ) { \
949 *d-- = *s--; \
950 } \
951 } else if ( dst < src ) { \
952 d = (char *)dst; \
953 s = (char *)src; \
954 while ( len-- ) { \
955 *d++ = *s++; \
956 } \
957 } \
958 return (void*)( ((char*)dst) + len_saved ); \
959 }
960
njne6154662009-02-10 04:23:41 +0000961GLIBC25_MEMPCPY(VG_Z_LIBC_SONAME, mempcpy)
njnb4cfbc42009-05-04 04:20:02 +0000962#if defined(VGO_linux)
njne6154662009-02-10 04:23:41 +0000963GLIBC25_MEMPCPY(VG_Z_LD_SO_1, mempcpy) /* ld.so.1 */
njnb4cfbc42009-05-04 04:20:02 +0000964#endif
sewardj841b72d2006-12-31 18:55:56 +0000965
966
sewardjb6c04032007-11-13 20:52:29 +0000967#define GLIBC26___MEMCPY_CHK(soname, fnname) \
968 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
969 (void* dst, const void* src, SizeT len, SizeT dstlen ); \
970 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
971 (void* dst, const void* src, SizeT len, SizeT dstlen ) \
972 { \
973 extern void _exit(int status); \
974 register char *d; \
975 register char *s; \
976 \
977 if (dstlen < len) goto badness; \
978 \
979 if (len == 0) \
980 return dst; \
981 \
982 if (is_overlap(dst, src, len, len)) \
983 RECORD_OVERLAP_ERROR("memcpy_chk", dst, src, len); \
984 \
985 if ( dst > src ) { \
986 d = (char *)dst + len - 1; \
987 s = (char *)src + len - 1; \
988 while ( len-- ) { \
989 *d-- = *s--; \
990 } \
991 } else if ( dst < src ) { \
992 d = (char *)dst; \
993 s = (char *)src; \
994 while ( len-- ) { \
995 *d++ = *s++; \
996 } \
997 } \
998 return dst; \
999 badness: \
1000 VALGRIND_PRINTF_BACKTRACE( \
1001 "*** memcpy_chk: buffer overflow detected ***: " \
njnd55f0d92009-08-03 01:38:56 +00001002 "program terminated\n"); \
sewardjb6c04032007-11-13 20:52:29 +00001003 _exit(127); \
1004 /*NOTREACHED*/ \
1005 return NULL; \
1006 }
1007
njne6154662009-02-10 04:23:41 +00001008GLIBC26___MEMCPY_CHK(VG_Z_LIBC_SONAME, __memcpy_chk)
sewardjb6c04032007-11-13 20:52:29 +00001009
1010
sewardja77687c2010-08-19 13:22:34 +00001011#define STRSTR(soname, fnname) \
1012 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1013 (void* haystack, void* needle); \
1014 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1015 (void* haystack, void* needle) \
1016 { \
1017 UChar* h = (UChar*)haystack; \
1018 UChar* n = (UChar*)needle; \
1019 \
1020 /* find the length of n, not including terminating zero */ \
1021 UWord nlen = 0; \
1022 while (n[nlen]) nlen++; \
1023 \
1024 /* if n is the empty string, match immediately. */ \
1025 if (nlen == 0) return h; \
1026 \
1027 /* assert(nlen >= 1); */ \
1028 UChar n0 = n[0]; \
1029 \
1030 while (1) { \
1031 UChar hh = *h; \
1032 if (hh == 0) return NULL; \
1033 if (hh != n0) { h++; continue; } \
1034 \
1035 UWord i; \
1036 for (i = 0; i < nlen; i++) { \
1037 if (n[i] != h[i]) \
1038 break; \
1039 } \
1040 /* assert(i >= 0 && i <= nlen); */ \
1041 if (i == nlen) \
1042 return h; \
1043 \
1044 h++; \
1045 } \
1046 }
1047
1048#if defined(VGO_linux)
1049STRSTR(VG_Z_LIBC_SONAME, strstr)
1050#endif
1051
1052
1053#define STRPBRK(soname, fnname) \
1054 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1055 (void* sV, void* acceptV); \
1056 void* VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1057 (void* sV, void* acceptV) \
1058 { \
1059 UChar* s = (UChar*)sV; \
1060 UChar* accept = (UChar*)acceptV; \
1061 \
1062 /* find the length of 'accept', not including terminating zero */ \
1063 UWord nacc = 0; \
1064 while (accept[nacc]) nacc++; \
1065 \
1066 /* if n is the empty string, fail immediately. */ \
1067 if (nacc == 0) return NULL; \
1068 \
1069 /* assert(nacc >= 1); */ \
1070 while (1) { \
1071 UWord i; \
1072 UChar sc = *s; \
1073 if (sc == 0) \
1074 break; \
1075 for (i = 0; i < nacc; i++) { \
1076 if (sc == accept[i]) \
1077 return s; \
1078 } \
1079 s++; \
1080 } \
1081 \
1082 return NULL; \
1083 }
1084
1085#if defined(VGO_linux)
1086STRPBRK(VG_Z_LIBC_SONAME, strpbrk)
1087#endif
1088
1089
1090#define STRCSPN(soname, fnname) \
1091 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1092 (void* sV, void* rejectV); \
1093 SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
1094 (void* sV, void* rejectV) \
1095 { \
1096 UChar* s = (UChar*)sV; \
1097 UChar* reject = (UChar*)rejectV; \
1098 \
1099 /* find the length of 'reject', not including terminating zero */ \
1100 UWord nrej = 0; \
1101 while (reject[nrej]) nrej++; \
1102 \
1103 UWord len = 0; \
1104 while (1) { \
1105 UWord i; \
1106 UChar sc = *s; \
1107 if (sc == 0) \
1108 break; \
1109 for (i = 0; i < nrej; i++) { \
1110 if (sc == reject[i]) \
1111 break; \
1112 } \
1113 /* assert(i >= 0 && i <= nrej); */ \
1114 if (i < nrej) \
1115 break; \
1116 s++; \
1117 len++; \
1118 } \
1119 \
1120 return len; \
1121 }
1122
1123#if defined(VGO_linux)
1124STRCSPN(VG_Z_LIBC_SONAME, strcspn)
1125#endif
1126
1127
sewardjba189352010-08-20 18:24:16 +00001128// And here's a validated strspn replacement, should it
1129// become necessary.
1130//UWord mystrspn( UChar* s, UChar* accept )
1131//{
1132// /* find the length of 'accept', not including terminating zero */
1133// UWord nacc = 0;
1134// while (accept[nacc]) nacc++;
1135// if (nacc == 0) return 0;
1136//
1137// UWord len = 0;
1138// while (1) {
1139// UWord i;
1140// UChar sc = *s;
1141// if (sc == 0)
1142// break;
1143// for (i = 0; i < nacc; i++) {
1144// if (sc == accept[i])
1145// break;
1146// }
1147// assert(i >= 0 && i <= nacc);
1148// if (i == nacc)
1149// break;
1150// s++;
1151// len++;
1152// }
1153//
1154// return len;
1155//}
1156
1157
sewardj31b9ce12006-10-17 01:27:13 +00001158/*------------------------------------------------------------*/
dirk09beb9e2007-04-19 09:47:32 +00001159/*--- Improve definedness checking of process environment ---*/
1160/*------------------------------------------------------------*/
1161
sewardjddc00dd2007-11-27 11:42:47 +00001162#if defined(VGO_linux)
1163
dirk09beb9e2007-04-19 09:47:32 +00001164/* putenv */
njne6154662009-02-10 04:23:41 +00001165int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string);
1166int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, putenv) (char* string)
dirk09beb9e2007-04-19 09:47:32 +00001167{
1168 OrigFn fn;
1169 Word result;
1170 const char* p = string;
1171 VALGRIND_GET_ORIG_FN(fn);
1172 /* Now by walking over the string we magically produce
1173 traces when hitting undefined memory. */
1174 if (p)
1175 while (*p++)
1176 ;
1177 CALL_FN_W_W(result, fn, string);
1178 return result;
1179}
1180
1181/* unsetenv */
njne6154662009-02-10 04:23:41 +00001182int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name);
1183int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, unsetenv) (const char* name)
dirk09beb9e2007-04-19 09:47:32 +00001184{
1185 OrigFn fn;
1186 Word result;
1187 const char* p = name;
1188 VALGRIND_GET_ORIG_FN(fn);
1189 /* Now by walking over the string we magically produce
1190 traces when hitting undefined memory. */
1191 if (p)
1192 while (*p++)
1193 ;
1194 CALL_FN_W_W(result, fn, name);
1195 return result;
1196}
1197
1198/* setenv */
njne6154662009-02-10 04:23:41 +00001199int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001200 (const char* name, const char* value, int overwrite);
njne6154662009-02-10 04:23:41 +00001201int VG_WRAP_FUNCTION_ZU(VG_Z_LIBC_SONAME, setenv)
dirk09beb9e2007-04-19 09:47:32 +00001202 (const char* name, const char* value, int overwrite)
1203{
1204 OrigFn fn;
1205 Word result;
1206 const char* p;
1207 VALGRIND_GET_ORIG_FN(fn);
1208 /* Now by walking over the string we magically produce
1209 traces when hitting undefined memory. */
1210 if (name)
1211 for (p = name; *p; p++)
1212 ;
1213 if (value)
1214 for (p = value; *p; p++)
1215 ;
1216 VALGRIND_CHECK_VALUE_IS_DEFINED (overwrite);
1217 CALL_FN_W_WWW(result, fn, name, value, overwrite);
1218 return result;
1219}
1220
sewardjddc00dd2007-11-27 11:42:47 +00001221#endif /* defined(VGO_linux) */
1222
1223
dirk09beb9e2007-04-19 09:47:32 +00001224/*------------------------------------------------------------*/
sewardj31b9ce12006-10-17 01:27:13 +00001225/*--- AIX stuff only after this point ---*/
1226/*------------------------------------------------------------*/
1227
sewardjddc00dd2007-11-27 11:42:47 +00001228/* Generate replacements for strcat, strncat, strcpy, strncpy, strcmp
sewardj31b9ce12006-10-17 01:27:13 +00001229 in the given soname. */
sewardjddc00dd2007-11-27 11:42:47 +00001230#define Str5FNs(_soname) \
sewardj31b9ce12006-10-17 01:27:13 +00001231 STRCAT(_soname, strcat) \
1232 STRNCAT(_soname, strncat) \
1233 STRCPY(_soname, strcpy) \
sewardjddc00dd2007-11-27 11:42:47 +00001234 STRNCPY(_soname, strncpy) \
1235 STRCMP(_soname, strcmp)
sewardj31b9ce12006-10-17 01:27:13 +00001236
1237#if defined(VGP_ppc32_aix5)
sewardjddc00dd2007-11-27 11:42:47 +00001238Str5FNs(NONE) /* in main exe */
1239Str5FNs(libCZdaZLshrcoreZdoZR) /* libC.a(shrcore.o) */
1240Str5FNs(libX11ZdaZLshr4ZdoZR) /* libX11.a(shr4.o) */
1241Str5FNs(libXmZdaZLshrZaZdoZR) /* libXm.a(shr*.o) */
1242Str5FNs(libXtZdaZLshr4ZdoZR) /* libXt.a(shr4.o) */
1243Str5FNs(libppeZurZdaZLdynamicZdoZR) /* libppe_r.a(dynamic.o) */
1244Str5FNs(libodmZdaZLshrZdoZR) /* libodm.a(shr.o) */
1245Str5FNs(libmpiZurZdaZLmpicoreZurZdoZR) /* libmpi_r.a(mpicore_r.o) */
1246Str5FNs(libmpiZurZdaZLmpipoeZurZdoZR) /* libmpi_r.a(mpipoe_r.o) */
1247Str5FNs(libmpiZurZdaZLmpciZurZdoZR) /* libmpi_r.a(mpci_r.o) */
1248Str5FNs(libslurmZdso) /* libslurm.so */
1249Str5FNs(libglibZdso) /* libglib.so */
1250Str5FNs(libIMZdaZLshrZdoZR) /* libIM.a(shr.o) */
1251Str5FNs(libiconvZdaZLshr4ZdoZR) /* libiconv.a(shr4.o) */
1252Str5FNs(libGLZdaZLshrZdoZR) /* libGL.a(shr.o) */
1253Str5FNs(libgdkZdso) /* libgdk.so */
1254Str5FNs(libcursesZdaZLshr42ZdoZR) /* libcurses.a(shr42.o) */
1255Str5FNs(libqtZda) /* libqt.a */
sewardjfd4b6f42007-11-29 03:08:32 +00001256Str5FNs(ZaZLlibglibZhZaZdsoZaZR) /* *(libglib-*.so*) */
1257Str5FNs(ZaZLlibfontconfigZdsoZaZR) /* *(libfontconfig.so*) */
1258Str5FNs(libQtZaa) /* libQt*.a */
sewardj31b9ce12006-10-17 01:27:13 +00001259#endif
1260#if defined(VGP_ppc64_aix5)
sewardjddc00dd2007-11-27 11:42:47 +00001261Str5FNs(NONE) /* in main exe */
1262Str5FNs(libX11ZdaZLshrZu64ZdoZR) /* libX11.a(shr_64.o) */
1263Str5FNs(libiconvZdaZLshr4Zu64ZdoZR) /* libiconv.a(shr4_64.o) */
1264Str5FNs(libGLZdaZLshrZu64ZdoZR) /* libGL.a(shr_64.o) */
1265Str5FNs(libppeZurZdaZLdynamic64ZdoZR) /* libppe_r.a(dynamic64.o) */
1266Str5FNs(libodmZdaZLshrZu64ZdoZR) /* libodm.a(shr_64.o) */
1267Str5FNs(libmpiZurZdaZLmpicore64ZurZdoZR) /* libmpi_r.a(mpicore64_r.o) */
1268Str5FNs(libmpiZurZdaZLmpipoe64ZurZdoZR) /* libmpi_r.a(mpipoe64_r.o) */
1269Str5FNs(libCZdaZLshrcoreZu64ZdoZR) /* libC.a(shrcore_64.o) */
1270Str5FNs(libmpiZurZdaZLmpci64ZurZdoZR) /* libmpi_r.a(mpci64_r.o) */
1271Str5FNs(libqtZda) /* libqt.a */
sewardjfd4b6f42007-11-29 03:08:32 +00001272Str5FNs(ZaZLlibglibZhZaZdsoZaZR) /* *(libglib-*.so*) */
1273Str5FNs(ZaZLlibfontconfigZdsoZaZR) /* *(libfontconfig.so*) */
1274Str5FNs(libQtZaa) /* libQt*.a */
sewardj31b9ce12006-10-17 01:27:13 +00001275#endif
1276
1277
1278/* AIX's libm contains a sqrt implementation which does a nasty thing:
1279 it loads the initial estimate of the root into a FP register, but
1280 only the upper half of the number is initialised data. Hence the
1281 least significant 32 mantissa bits are undefined, and it then uses
1282 Newton-Raphson iteration to compute the final, defined result.
1283 This fools memcheck completely; the only solution I can think of is
1284 provide our own substitute. The _FAST variant is almost right
1285 except the result is not correctly rounded. The _EXACT variant,
1286 which is selected by default, is always right; but it's also pretty
1287 darn slow. */
1288
1289#if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
1290#define SQRT_FAST(soname, fnname) \
1291 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ); \
1292 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ) \
1293 { \
1294 static UInt T1[32] = \
1295 { 0, 1024, 3062, 5746, 9193, 13348, \
1296 18162, 23592, 29598, 36145, 43202, 50740, \
1297 58733, 67158, 75992, 85215, 83599, 71378, \
1298 60428, 50647, 41945, 34246, 27478, 21581, \
1299 16499, 12183, 8588, 5674, 3403, 1742, \
1300 661, 130 }; \
1301 UInt x0, x1, sign, expo, mant0, bIGENDIAN = 1; \
1302 union { UInt w[2]; double d; } u; \
1303 u.d = x; \
1304 x0 = u.w[1 - bIGENDIAN]; /* high half */ \
1305 x1 = u.w[bIGENDIAN]; /* low half */ \
1306 sign = x0 >> 31; \
1307 expo = (x0 >> 20) & 0x7FF; \
1308 mant0 = x0 & 0xFFFFF; \
1309 if ( (sign == 0 && expo >= 1 && expo <= 0x7FE) /* +normal */ \
1310 || (sign == 0 && expo == 0 \
1311 && (mant0 | x1) > 0) /* +denorm */) { \
1312 /* common case; do Newton-Raphson */ \
1313 /* technically k should be signed int32, but since we're \
1314 always entering here with x > 0, doesn't matter that it's \
1315 unsigned. */ \
1316 double y; \
1317 UInt k = (x0>>1) + 0x1ff80000; \
1318 u.w[1 - bIGENDIAN] = k - T1[31&(k>>15)]; \
1319 u.w[bIGENDIAN] = 0; \
1320 y = u.d; \
1321 y = (y+x/y)/2.0 ; \
1322 y = (y+x/y)/2.0 ; \
1323 y = y-(y-x/y)/2.0 ; \
1324 return y; \
1325 } \
1326 if ( (sign == 1 && expo >= 1 && expo <= 0x7FE) /* -normal */ \
1327 || (sign == 1 && expo == 0 \
1328 && (mant0 | x1) > 0) /* -denorm */) { \
1329 u.w[1 - bIGENDIAN] = 0xFFF00000; \
1330 u.w[bIGENDIAN] = 0x1; \
1331 return u.d; /* -Inf -> NaN */ \
1332 } \
1333 if ((expo | mant0 | x1) == 0) \
1334 return x; /* +/-zero -> self */ \
1335 if (expo == 0x7FF && (mant0 | x1) == 0) { \
1336 if (sign == 0) \
1337 return x; /* +Inf -> self */ \
1338 u.w[1 - bIGENDIAN] = 0xFFF00000; \
1339 u.w[bIGENDIAN] = 0x1; \
1340 return u.d; /* -Inf -> NaN */ \
1341 } \
1342 /* must be +/- NaN */ \
1343 return x; /* +/-NaN -> self */ \
1344 }
1345
1346#define SQRT_EXACT(soname, fnname) \
1347 /* \
1348 * ==================================================== \
1349 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. \
1350 * \
1351 * Developed at SunPro, a Sun Microsystems, Inc. business. \
1352 * Permission to use, copy, modify, and distribute this \
1353 * software is freely granted, provided that this notice \
1354 * is preserved. \
1355 * ==================================================== \
1356 */ \
1357 /* \
1358 * Return correctly rounded sqrt. \
1359 * ------------------------------------------ \
1360 * | Use the hardware sqrt if you have one | \
1361 * ------------------------------------------ \
1362 * Method: \
1363 * Bit by bit method using integer arithmetic. (Slow, but portable) \
1364 * 1. Normalization \
1365 * Scale x to y in [1,4) with even powers of 2: \
1366 * find an integer k such that 1 <= (y=x*2^(2k)) < 4, then \
1367 * sqrt(x) = 2^k * sqrt(y) \
1368 * 2. Bit by bit computation \
1369 * Let q = sqrt(y) truncated to i bit after binary point (q = 1), \
1370 * i 0 \
1371 * i+1 2 \
1372 * s = 2*q , and y = 2 * ( y - q ). (1) \
1373 * i i i i \
1374 * \
1375 * To compute q from q , one checks whether \
1376 * i+1 i \
1377 * \
1378 * -(i+1) 2 \
1379 * (q + 2 ) <= y. (2) \
1380 * i \
1381 * -(i+1) \
1382 * If (2) is false, then q = q ; otherwise q = q + 2 . \
1383 * i+1 i i+1 i \
1384 * \
1385 * With some algebric manipulation, it is not difficult to see \
1386 * that (2) is equivalent to \
1387 * -(i+1) \
1388 * s + 2 <= y (3) \
1389 * i i \
1390 * \
1391 * The advantage of (3) is that s and y can be computed by \
1392 * i i \
1393 * the following recurrence formula: \
1394 * if (3) is false \
1395 * \
1396 * s = s , y = y ; (4) \
1397 * i+1 i i+1 i \
1398 * \
1399 * otherwise, \
1400 * -i -(i+1) \
1401 * s = s + 2 , y = y - s - 2 (5) \
1402 * i+1 i i+1 i i \
1403 * \
1404 * \
1405 * One may easily use induction to prove (4) and (5). \
1406 * Note. Since the left hand side of (3) contain only i+2 bits, \
1407 * it does not necessary to do a full (53-bit) comparison \
1408 * in (3). \
1409 * 3. Final rounding \
1410 * After generating the 53 bits result, we compute one more bit. \
1411 * Together with the remainder, we can decide whether the \
1412 * result is exact, bigger than 1/2ulp, or less than 1/2ulp \
1413 * (it will never equal to 1/2ulp). \
1414 * The rounding mode can be detected by checking whether \
1415 * huge + tiny is equal to huge, and whether huge - tiny is \
1416 * equal to huge for some floating point number "huge" and "tiny". \
1417 * \
1418 * Special cases: \
1419 * sqrt(+-0) = +-0 ... exact \
1420 * sqrt(inf) = inf \
1421 * sqrt(-ve) = NaN ... with invalid signal \
1422 * sqrt(NaN) = NaN ... with invalid signal for signaling NaN \
1423 * \
1424 */ \
1425 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ); \
1426 double VG_REPLACE_FUNCTION_ZU(soname,fnname)( double x ) \
1427 { \
1428 const Int bIGENDIAN = 1; \
1429 const double one = 1.0, tiny=1.0e-300; \
1430 double z; \
1431 Int sign = (Int)0x80000000; \
1432 Int ix0,s0,q,m,t,i; \
1433 UInt r,t1,s1,ix1,q1; \
1434 union { UInt w[2]; double d; } u; \
1435 u.d = x; \
1436 ix0 = u.w[1-bIGENDIAN]; \
1437 ix1 = u.w[bIGENDIAN]; \
1438 \
1439 /* take care of Inf and NaN */ \
1440 if((ix0&0x7ff00000)==0x7ff00000) { \
1441 return x*x+x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf \
1442 sqrt(-inf)=sNaN */ \
1443 } \
1444 /* take care of zero */ \
1445 if(ix0<=0) { \
1446 if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */ \
1447 else if(ix0<0) \
1448 return (x-x)/(x-x); /* sqrt(-ve) = sNaN */ \
1449 } \
1450 /* normalize x */ \
1451 m = (ix0>>20); \
1452 if(m==0) { /* subnormal x */ \
1453 while(ix0==0) { \
1454 m -= 21; \
1455 ix0 |= (ix1>>11); ix1 <<= 21; \
1456 } \
1457 for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1; \
1458 m -= i-1; \
1459 ix0 |= (ix1>>(32-i)); \
1460 ix1 <<= i; \
1461 } \
1462 m -= 1023; /* unbias exponent */ \
1463 ix0 = (ix0&0x000fffff)|0x00100000; \
1464 if(m&1){ /* odd m, double x to make it even */ \
1465 ix0 += ix0 + ((ix1&sign)>>31); \
1466 ix1 += ix1; \
1467 } \
1468 m >>= 1; /* m = [m/2] */ \
1469 /* generate sqrt(x) bit by bit */ \
1470 ix0 += ix0 + ((ix1&sign)>>31); \
1471 ix1 += ix1; \
1472 q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */ \
1473 r = 0x00200000; /* r = moving bit from right to left */ \
1474 while(r!=0) { \
1475 t = s0+r; \
1476 if(t<=ix0) { \
1477 s0 = t+r; \
1478 ix0 -= t; \
1479 q += r; \
1480 } \
1481 ix0 += ix0 + ((ix1&sign)>>31); \
1482 ix1 += ix1; \
1483 r>>=1; \
1484 } \
1485 r = sign; \
1486 while(r!=0) { \
1487 t1 = s1+r; \
1488 t = s0; \
1489 if((t<ix0)||((t==ix0)&&(t1<=ix1))) { \
1490 s1 = t1+r; \
1491 if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1; \
1492 ix0 -= t; \
1493 if (ix1 < t1) ix0 -= 1; \
1494 ix1 -= t1; \
1495 q1 += r; \
1496 } \
1497 ix0 += ix0 + ((ix1&sign)>>31); \
1498 ix1 += ix1; \
1499 r>>=1; \
1500 } \
1501 /* use floating add to find out rounding direction */ \
1502 if((ix0|ix1)!=0) { \
1503 z = one-tiny; /* trigger inexact flag */ \
1504 if (z>=one) { \
1505 z = one+tiny; \
1506 if (q1==(UInt)0xffffffff) { q1=0; q += 1;} \
1507 else if (z>one) { \
1508 if (q1==(UInt)0xfffffffe) q+=1; \
1509 q1+=2; \
1510 } else \
1511 q1 += (q1&1); \
1512 } \
1513 } \
1514 ix0 = (q>>1)+0x3fe00000; \
1515 ix1 = q1>>1; \
1516 if ((q&1)==1) ix1 |= sign; \
1517 ix0 += (m <<20); \
1518 ix0 = u.w[1-bIGENDIAN] = ix0; \
1519 ix1 = u.w[bIGENDIAN] = ix1; \
1520 z = u.d; \
1521 return z; \
1522 }
1523
1524#if 0
1525SQRT_FAST(NONE, sqrt) /* xlC generates these */
1526SQRT_FAST(NONE, _sqrt) /* xlf generates these */
1527#else
1528SQRT_EXACT(NONE, sqrt) /* xlC generates these */
1529SQRT_EXACT(NONE, _sqrt) /* xlf generates these */
1530#endif
1531
1532#endif /* defined(VGP_ppc32_aix5) */
1533
njn3e884182003-04-15 13:03:23 +00001534/*--------------------------------------------------------------------*/
njn46275862005-03-24 04:00:03 +00001535/*--- end ---*/
njn3e884182003-04-15 13:03:23 +00001536/*--------------------------------------------------------------------*/