blob: aae64cc012056042f1a01e2d4da1446ce16d6fce [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. ---*/
njn66fe05a2003-07-22 09:12:33 +00005/*--- mac_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
njn53612422005-03-12 16:22:54 +000012 Copyright (C) 2000-2005 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.
92#define RECORD_OVERLAP_ERROR(s, p_extra) \
93{ \
94 Word unused_res; \
95 VALGRIND_MAGIC_SEQUENCE(unused_res, 0, \
96 _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR, \
97 s, p_extra, 0, 0); \
98}
sewardjdda830a2003-07-20 22:28:42 +000099
njn3e884182003-04-15 13:03:23 +0000100static __inline__
101void complain2 ( Char* s, char* dst, const char* src )
102{
njnb6cae9f2003-09-04 20:50:47 +0000103 OverlapExtra extra = {
104 .src = (Addr)src, .dst = (Addr)dst, .len = -1,
105 };
njn1f8b3e72005-03-22 04:27:14 +0000106 RECORD_OVERLAP_ERROR( s, &extra );
njn3e884182003-04-15 13:03:23 +0000107}
108
109static __inline__
110void complain3 ( Char* s, void* dst, const void* src, int n )
111{
njnb6cae9f2003-09-04 20:50:47 +0000112 /* Must wrap it up here, because we cannot pass 4 args to core */
113 OverlapExtra extra = {
114 .src = (Addr)src, .dst = (Addr)dst, .len = n,
115 };
njn1f8b3e72005-03-22 04:27:14 +0000116 RECORD_OVERLAP_ERROR( s, &extra );
njn3e884182003-04-15 13:03:23 +0000117}
118
njn16eeb4e2005-06-16 03:56:58 +0000119// Some handy Z-encoded names
tom8f924092005-10-13 15:51:12 +0000120#define m_libc_so_star libcZdsoZa // libc.so*
njn16eeb4e2005-06-16 03:56:58 +0000121#define m_ld_linux_so_2 ldZhlinuxZdsoZd2 // ld-linux.so.2
122#define m_ld_linux_x86_64_so_2 ldZhlinuxZhx86Zh64ZdsoZd2 // ld-linux-x86-64.so.2
njn46275862005-03-24 04:00:03 +0000123
njn16eeb4e2005-06-16 03:56:58 +0000124
125#define STRRCHR(soname, fnname) \
126 char* VG_REPLACE_FUNCTION(soname,fnname)( const char* s, int c ); \
127 char* VG_REPLACE_FUNCTION(soname,fnname)( const char* s, int c ) \
128 { \
129 UChar ch = (UChar)((UInt)c); \
130 UChar* p = (UChar*)s; \
131 UChar* last = NULL; \
132 while (True) { \
133 if (*p == ch) last = p; \
134 if (*p == 0) return last; \
135 p++; \
136 } \
njn3e884182003-04-15 13:03:23 +0000137 }
njn3e884182003-04-15 13:03:23 +0000138
njn16eeb4e2005-06-16 03:56:58 +0000139// Apparently rindex() is the same thing as strrchr()
tom8f924092005-10-13 15:51:12 +0000140STRRCHR(m_libc_so_star, strrchr)
141STRRCHR(m_libc_so_star, rindex)
njn16eeb4e2005-06-16 03:56:58 +0000142STRRCHR(m_ld_linux_so_2, rindex)
143
144
145#define STRCHR(soname, fnname) \
146 char* VG_REPLACE_FUNCTION(soname,fnname) ( const char* s, int c ); \
147 char* VG_REPLACE_FUNCTION(soname,fnname) ( const char* s, int c ) \
148 { \
149 UChar ch = (UChar)((UInt)c); \
150 UChar* p = (UChar*)s; \
151 while (True) { \
152 if (*p == ch) return p; \
153 if (*p == 0) return NULL; \
154 p++; \
155 } \
njn3e884182003-04-15 13:03:23 +0000156 }
njn3e884182003-04-15 13:03:23 +0000157
njn16eeb4e2005-06-16 03:56:58 +0000158// Apparently index() is the same thing as strchr()
tom8f924092005-10-13 15:51:12 +0000159STRCHR(m_libc_so_star, strchr)
njn16eeb4e2005-06-16 03:56:58 +0000160STRCHR(m_ld_linux_so_2, strchr)
tom10e1beb2005-07-21 15:25:04 +0000161STRCHR(m_ld_linux_x86_64_so_2, strchr)
tom8f924092005-10-13 15:51:12 +0000162STRCHR(m_libc_so_star, index)
njn16eeb4e2005-06-16 03:56:58 +0000163STRCHR(m_ld_linux_so_2, index)
164STRCHR(m_ld_linux_x86_64_so_2, index)
njn3e884182003-04-15 13:03:23 +0000165
njn3e884182003-04-15 13:03:23 +0000166
njn16eeb4e2005-06-16 03:56:58 +0000167#define STRCAT(soname, fnname) \
168 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src ); \
169 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src ) \
170 { \
171 const Char* src_orig = src; \
172 Char* dst_orig = dst; \
173 while (*dst) dst++; \
174 while (*src) *dst++ = *src++; \
175 *dst = 0; \
176 \
177 /* This is a bit redundant, I think; any overlap and the strcat will */ \
178 /* go forever... or until a seg fault occurs. */ \
179 if (is_overlap(dst_orig, \
180 src_orig, \
181 (Addr)dst-(Addr)dst_orig+1, \
182 (Addr)src-(Addr)src_orig+1)) \
183 complain2("strcat", dst_orig, src_orig); \
184 \
185 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000186 }
njn3e884182003-04-15 13:03:23 +0000187
tom8f924092005-10-13 15:51:12 +0000188STRCAT(m_libc_so_star, strcat)
njn16eeb4e2005-06-16 03:56:58 +0000189
190
191#define STRNCAT(soname, fnname) \
192 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src, SizeT n ); \
193 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src, SizeT n ) \
194 { \
195 const Char* src_orig = src; \
196 Char* dst_orig = dst; \
197 SizeT m = 0; \
198 \
199 while (*dst) dst++; \
200 while (m < n && *src) { m++; *dst++ = *src++; } /* concat <= n chars */ \
201 *dst = 0; /* always add null */ \
202 \
203 /* This checks for overlap after copying, unavoidable without */ \
204 /* pre-counting lengths... should be ok */ \
205 if (is_overlap(dst_orig, \
206 src_orig, \
207 (Addr)dst-(Addr)dst_orig+1, \
208 (Addr)src-(Addr)src_orig+1)) \
209 complain3("strncat", dst_orig, src_orig, n); \
210 \
211 return dst_orig; \
njn3e884182003-04-15 13:03:23 +0000212 }
njn3e884182003-04-15 13:03:23 +0000213
tom8f924092005-10-13 15:51:12 +0000214STRNCAT(m_libc_so_star, strncat)
njn16eeb4e2005-06-16 03:56:58 +0000215
njn3e884182003-04-15 13:03:23 +0000216
njn16eeb4e2005-06-16 03:56:58 +0000217#define STRNLEN(soname, fnname) \
218 SizeT VG_REPLACE_FUNCTION(soname,fnname) ( const char* str, SizeT n ); \
219 SizeT VG_REPLACE_FUNCTION(soname,fnname) ( const char* str, SizeT n ) \
220 { \
221 SizeT i = 0; \
222 while (i < n && str[i] != 0) i++; \
223 return i; \
njn3e884182003-04-15 13:03:23 +0000224 }
njn3e884182003-04-15 13:03:23 +0000225
tom8f924092005-10-13 15:51:12 +0000226STRNLEN(m_libc_so_star, strnlen)
njn16eeb4e2005-06-16 03:56:58 +0000227
sewardj3ceec242003-07-30 21:24:25 +0000228
njn5ec15ed2005-08-24 19:55:51 +0000229// Note that this replacement often doesn't get used because gcc inlines
230// calls to strlen() with its own built-in version. This can be very
231// confusing if you aren't expecting it. Other small functions in this file
232// may also be inline by gcc.
njn16eeb4e2005-06-16 03:56:58 +0000233#define STRLEN(soname, fnname) \
234 SizeT VG_REPLACE_FUNCTION(soname,fnname)( const char* str ); \
235 SizeT VG_REPLACE_FUNCTION(soname,fnname)( const char* str ) \
236 { \
237 SizeT i = 0; \
238 while (str[i] != 0) i++; \
239 return i; \
sewardj3ceec242003-07-30 21:24:25 +0000240 }
njn16eeb4e2005-06-16 03:56:58 +0000241
tom8f924092005-10-13 15:51:12 +0000242STRLEN(m_libc_so_star, strlen)
njn16eeb4e2005-06-16 03:56:58 +0000243STRLEN(m_ld_linux_so_2, strlen)
244STRLEN(m_ld_linux_x86_64_so_2, strlen)
245
246
247#define STRCPY(soname, fnname) \
248 char* VG_REPLACE_FUNCTION(soname, fnname) ( char* dst, const char* src ); \
249 char* VG_REPLACE_FUNCTION(soname, fnname) ( char* dst, const char* src ) \
250 { \
251 const Char* src_orig = src; \
252 Char* dst_orig = dst; \
253 \
254 while (*src) *dst++ = *src++; \
255 *dst = 0; \
256 \
257 /* This checks for overlap after copying, unavoidable without */ \
258 /* pre-counting length... should be ok */ \
259 if (is_overlap(dst_orig, \
260 src_orig, \
261 (Addr)dst-(Addr)dst_orig+1, \
262 (Addr)src-(Addr)src_orig+1)) \
263 complain2("strcpy", dst_orig, src_orig); \
264 \
265 return dst_orig; \
266 }
267
tom8f924092005-10-13 15:51:12 +0000268STRCPY(m_libc_so_star, strcpy)
njn16eeb4e2005-06-16 03:56:58 +0000269
270
271#define STRNCPY(soname, fnname) \
272 char* VG_REPLACE_FUNCTION(soname, fnname) ( char* dst, const char* src, SizeT n ); \
273 char* VG_REPLACE_FUNCTION(soname, fnname) ( char* dst, const char* src, SizeT n ) \
274 { \
275 const Char* src_orig = src; \
276 Char* dst_orig = dst; \
277 SizeT m = 0; \
278 \
279 while (m < n && *src) { m++; *dst++ = *src++; } \
280 /* Check for overlap after copying; all n bytes of dst are relevant, */ \
281 /* but only m+1 bytes of src if terminator was found */ \
282 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
283 complain3("strncpy", dst, src, n); \
284 while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */ \
285 \
286 return dst_orig; \
287 }
288
tom8f924092005-10-13 15:51:12 +0000289STRNCPY(m_libc_so_star, strncpy)
njn16eeb4e2005-06-16 03:56:58 +0000290
291
292#define STRNCMP(soname, fnname) \
293 int VG_REPLACE_FUNCTION(soname,fnname) ( const char* s1, const char* s2, SizeT nmax ); \
294 int VG_REPLACE_FUNCTION(soname,fnname) ( const char* s1, const char* s2, SizeT nmax ) \
295 { \
296 SizeT n = 0; \
297 while (True) { \
298 if (n >= nmax) return 0; \
299 if (*s1 == 0 && *s2 == 0) return 0; \
300 if (*s1 == 0) return -1; \
301 if (*s2 == 0) return 1; \
302 \
303 if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1; \
304 if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1; \
305 \
306 s1++; s2++; n++; \
307 } \
308 }
309
tom8f924092005-10-13 15:51:12 +0000310STRNCMP(m_libc_so_star, strncmp)
njn16eeb4e2005-06-16 03:56:58 +0000311
312
313#define STRCMP(soname, fnname) \
314 int VG_REPLACE_FUNCTION(soname,fnname) ( const char* s1, const char* s2 ); \
315 int VG_REPLACE_FUNCTION(soname,fnname) ( const char* s1, const char* s2 ) \
316 { \
317 register unsigned char c1; \
318 register unsigned char c2; \
319 while (True) { \
320 c1 = *(unsigned char *)s1; \
321 c2 = *(unsigned char *)s2; \
322 if (c1 != c2) break; \
323 if (c1 == 0) break; \
324 s1++; s2++; \
325 } \
326 if ((unsigned char)c1 < (unsigned char)c2) return -1; \
327 if ((unsigned char)c1 > (unsigned char)c2) return 1; \
328 return 0; \
329 }
330
tom8f924092005-10-13 15:51:12 +0000331STRCMP(m_libc_so_star, strcmp)
njn16eeb4e2005-06-16 03:56:58 +0000332STRCMP(m_ld_linux_x86_64_so_2, strcmp)
333
334
335#define MEMCHR(soname, fnname) \
336 void* VG_REPLACE_FUNCTION(soname,fnname) (const void *s, int c, SizeT n); \
337 void* VG_REPLACE_FUNCTION(soname,fnname) (const void *s, int c, SizeT n) \
338 { \
339 SizeT i; \
340 UChar c0 = (UChar)c; \
341 UChar* p = (UChar*)s; \
342 for (i = 0; i < n; i++) \
343 if (p[i] == c0) return (void*)(&p[i]); \
344 return NULL; \
345 }
346
tom8f924092005-10-13 15:51:12 +0000347MEMCHR(m_libc_so_star, memchr)
njn16eeb4e2005-06-16 03:56:58 +0000348
349
350#define MEMCPY(soname, fnname) \
351 void* VG_REPLACE_FUNCTION(soname,fnname)( void *dst, const void *src, SizeT len ); \
352 void* VG_REPLACE_FUNCTION(soname,fnname)( void *dst, const void *src, SizeT len ) \
353 { \
354 register char *d; \
355 register char *s; \
356 \
357 if (len == 0) \
358 return dst; \
359 \
360 if (is_overlap(dst, src, len, len)) \
361 complain3("memcpy", dst, src, len); \
362 \
363 if ( dst > src ) { \
364 d = (char *)dst + len - 1; \
365 s = (char *)src + len - 1; \
366 while ( len >= 4 ) { \
367 *d-- = *s--; \
368 *d-- = *s--; \
369 *d-- = *s--; \
370 *d-- = *s--; \
371 len -= 4; \
372 } \
373 while ( len-- ) { \
374 *d-- = *s--; \
375 } \
376 } else if ( dst < src ) { \
377 d = (char *)dst; \
378 s = (char *)src; \
379 while ( len >= 4 ) { \
380 *d++ = *s++; \
381 *d++ = *s++; \
382 *d++ = *s++; \
383 *d++ = *s++; \
384 len -= 4; \
385 } \
386 while ( len-- ) { \
387 *d++ = *s++; \
388 } \
389 } \
390 return dst; \
391 }
392
tom8f924092005-10-13 15:51:12 +0000393MEMCPY(m_libc_so_star, memcpy)
njn16eeb4e2005-06-16 03:56:58 +0000394
395
396#define MEMCMP(soname, fnname) \
397 int VG_REPLACE_FUNCTION(soname,fnname)( const void *s1V, const void *s2V, SizeT n ); \
398 int VG_REPLACE_FUNCTION(soname,fnname)( const void *s1V, const void *s2V, SizeT n ) \
399 { \
400 int res; \
401 unsigned char a0; \
402 unsigned char b0; \
403 unsigned char* s1 = (unsigned char*)s1V; \
404 unsigned char* s2 = (unsigned char*)s2V; \
405 \
406 while (n != 0) { \
407 a0 = s1[0]; \
408 b0 = s2[0]; \
409 s1 += 1; \
410 s2 += 1; \
411 res = ((int)a0) - ((int)b0); \
412 if (res != 0) \
413 return res; \
414 n -= 1; \
415 } \
416 return 0; \
417 }
418
tom8f924092005-10-13 15:51:12 +0000419MEMCMP(m_libc_so_star, memcmp)
420MEMCMP(m_libc_so_star, bcmp)
njn3e884182003-04-15 13:03:23 +0000421
jseward0845ef82003-12-22 22:31:27 +0000422
423/* Copy SRC to DEST, returning the address of the terminating '\0' in
424 DEST. (minor variant of strcpy) */
njn16eeb4e2005-06-16 03:56:58 +0000425#define STPCPY(soname, fnname) \
426 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src ); \
427 char* VG_REPLACE_FUNCTION(soname,fnname) ( char* dst, const char* src ) \
428 { \
429 const Char* src_orig = src; \
430 Char* dst_orig = dst; \
431 \
432 while (*src) *dst++ = *src++; \
433 *dst = 0; \
434 \
435 /* This checks for overlap after copying, unavoidable without */ \
436 /* pre-counting length... should be ok */ \
437 if (is_overlap(dst_orig, \
438 src_orig, \
439 (Addr)dst-(Addr)dst_orig+1, \
440 (Addr)src-(Addr)src_orig+1)) \
441 complain2("stpcpy", dst_orig, src_orig); \
442 \
443 return dst; \
sewardj44e495f2005-05-12 17:58:28 +0000444 }
njn16eeb4e2005-06-16 03:56:58 +0000445
tom8f924092005-10-13 15:51:12 +0000446STPCPY(m_libc_so_star, stpcpy)
tom10e1beb2005-07-21 15:25:04 +0000447STPCPY(m_ld_linux_so_2, stpcpy)
448STPCPY(m_ld_linux_x86_64_so_2, stpcpy)
njn16eeb4e2005-06-16 03:56:58 +0000449
450
451#define MEMSET(soname, fnname) \
452 void* VG_REPLACE_FUNCTION(soname,fnname)(void *s, Int c, SizeT n); \
453 void* VG_REPLACE_FUNCTION(soname,fnname)(void *s, Int c, SizeT n) \
454 { \
455 unsigned char *cp = s; \
456 \
457 while(n--) \
458 *cp++ = c; \
459 \
460 return s; \
sewardj44e495f2005-05-12 17:58:28 +0000461 }
njn16eeb4e2005-06-16 03:56:58 +0000462
tom8f924092005-10-13 15:51:12 +0000463MEMSET(m_libc_so_star, memset)
njn16eeb4e2005-06-16 03:56:58 +0000464
465
466#define MEMMOVE(soname, fnname) \
467 void* VG_REPLACE_FUNCTION(soname,fnname)(void *dstV, const void *srcV, SizeT n); \
468 void* VG_REPLACE_FUNCTION(soname,fnname)(void *dstV, const void *srcV, SizeT n) \
469 { \
470 SizeT i; \
471 Char* dst = (Char*)dstV; \
472 Char* src = (Char*)srcV; \
473 if (dst < src) { \
474 for (i = 0; i < n; i++) \
475 dst[i] = src[i]; \
476 } \
477 else \
478 if (dst > src) { \
479 for (i = 0; i < n; i++) \
480 dst[n-i-1] = src[n-i-1]; \
481 } \
482 return dst; \
483 }
484
tom8f924092005-10-13 15:51:12 +0000485MEMMOVE(m_libc_so_star, memmove)
sewardj44e495f2005-05-12 17:58:28 +0000486
jseward0845ef82003-12-22 22:31:27 +0000487
sewardj4e9a4b62004-11-23 00:20:17 +0000488/* Find the first occurrence of C in S or the final NUL byte. */
njn16eeb4e2005-06-16 03:56:58 +0000489#define GLIBC232_STRCHRNUL(soname, fnname) \
490 char* VG_REPLACE_FUNCTION(soname,fnname) (const char* s, int c_in); \
491 char* VG_REPLACE_FUNCTION(soname,fnname) (const char* s, int c_in) \
492 { \
493 unsigned char c = (unsigned char) c_in; \
494 unsigned char* char_ptr = (unsigned char *)s; \
495 while (1) { \
496 if (*char_ptr == 0) return char_ptr; \
497 if (*char_ptr == c) return char_ptr; \
498 char_ptr++; \
499 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000500 }
njn16eeb4e2005-06-16 03:56:58 +0000501
tom8f924092005-10-13 15:51:12 +0000502GLIBC232_STRCHRNUL(m_libc_so_star, strchrnul)
sewardj4e9a4b62004-11-23 00:20:17 +0000503
504
505/* Find the first occurrence of C in S. */
njn16eeb4e2005-06-16 03:56:58 +0000506#define GLIBC232_RAWMEMCHR(soname, fnname) \
507 char* VG_REPLACE_FUNCTION(soname,fnname) (const char* s, int c_in); \
508 char* VG_REPLACE_FUNCTION(soname,fnname) (const char* s, int c_in) \
509 { \
510 unsigned char c = (unsigned char) c_in; \
511 unsigned char* char_ptr = (unsigned char *)s; \
512 while (1) { \
513 if (*char_ptr == c) return char_ptr; \
514 char_ptr++; \
515 } \
sewardj4e9a4b62004-11-23 00:20:17 +0000516 }
njn16eeb4e2005-06-16 03:56:58 +0000517
tom8f924092005-10-13 15:51:12 +0000518GLIBC232_RAWMEMCHR(m_libc_so_star, rawmemchr)
sewardj4e9a4b62004-11-23 00:20:17 +0000519
520
njn3e884182003-04-15 13:03:23 +0000521/*--------------------------------------------------------------------*/
njn46275862005-03-24 04:00:03 +0000522/*--- end ---*/
njn3e884182003-04-15 13:03:23 +0000523/*--------------------------------------------------------------------*/