blob: d8b37d5899ca9c7474d5a07015a073d25ec5dbda [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
njn34419c12003-05-02 17:24:29 +000033#include "mc_include.h"
fitzhardinge98abfc72003-12-16 02:05:15 +000034#include "memcheck.h"
njn3e884182003-04-15 13:03:23 +000035#include "valgrind.h"
36
njn3e884182003-04-15 13:03:23 +000037/* ---------------------------------------------------------------------
njn1f8b3e72005-03-22 04:27:14 +000038 We have our own versions of these functions for two reasons:
39 (a) it allows us to do overlap checking
40 (b) some of the normal versions are hyper-optimised, which fools
41 Memcheck and cause spurious value warnings. Our versions are
42 simpler.
43
44 THEY RUN ON THE SIMD CPU!
njn3e884182003-04-15 13:03:23 +000045 ------------------------------------------------------------------ */
46
sewardjdda830a2003-07-20 22:28:42 +000047/* Figure out if [dst .. dst+dstlen-1] overlaps with
48 [src .. src+srclen-1].
49 We assume that the address ranges do not wrap around
50 (which is safe since on Linux addresses >= 0xC0000000
51 are not accessible and the program will segfault in this
52 circumstance, presumably).
53*/
njn3e884182003-04-15 13:03:23 +000054static __inline__
njnc6168192004-11-29 13:54:10 +000055Bool is_overlap ( void* dst, const void* src, SizeT dstlen, SizeT srclen )
njn3e884182003-04-15 13:03:23 +000056{
sewardjdda830a2003-07-20 22:28:42 +000057 Addr loS, hiS, loD, hiD;
58
59 if (dstlen == 0 || srclen == 0)
60 return False;
61
62 loS = (Addr)src;
63 loD = (Addr)dst;
64 hiS = loS + srclen - 1;
65 hiD = loD + dstlen - 1;
66
67 /* So figure out if [loS .. hiS] overlaps with [loD .. hiD]. */
68 if (loS < loD) {
69 return !(hiS < loD);
70 }
71 else if (loD < loS) {
72 return !(hiD < loS);
73 }
74 else {
75 /* They start at same place. Since we know neither of them has
76 zero length, they must overlap. */
77 return True;
78 }
njn3e884182003-04-15 13:03:23 +000079}
80
njn1f8b3e72005-03-22 04:27:14 +000081// This is a macro rather than a function because we don't want to have an
82// extra function in the stack trace.
83#define RECORD_OVERLAP_ERROR(s, p_extra) \
84{ \
85 Word unused_res; \
86 VALGRIND_MAGIC_SEQUENCE(unused_res, 0, \
87 _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR, \
88 s, p_extra, 0, 0); \
89}
sewardjdda830a2003-07-20 22:28:42 +000090
njn3e884182003-04-15 13:03:23 +000091static __inline__
92void complain2 ( Char* s, char* dst, const char* src )
93{
njnb6cae9f2003-09-04 20:50:47 +000094 OverlapExtra extra = {
95 .src = (Addr)src, .dst = (Addr)dst, .len = -1,
96 };
njn1f8b3e72005-03-22 04:27:14 +000097 RECORD_OVERLAP_ERROR( s, &extra );
njn3e884182003-04-15 13:03:23 +000098}
99
100static __inline__
101void complain3 ( Char* s, void* dst, const void* src, int n )
102{
njnb6cae9f2003-09-04 20:50:47 +0000103 /* Must wrap it up here, because we cannot pass 4 args to core */
104 OverlapExtra extra = {
105 .src = (Addr)src, .dst = (Addr)dst, .len = n,
106 };
njn1f8b3e72005-03-22 04:27:14 +0000107 RECORD_OVERLAP_ERROR( s, &extra );
njn3e884182003-04-15 13:03:23 +0000108}
109
njn46275862005-03-24 04:00:03 +0000110// GCC complains if we have a non-static function without a previous
111// declaration. We don't really need such declarations for these functions
112// because we're overriding standard system functions, but this macro puts
113// them in anyway just to shut GCC up.
114#define DECL(a) a; a
115
116DECL( char* strrchr ( const char* s, int c ) )
njn3e884182003-04-15 13:03:23 +0000117{
118 UChar ch = (UChar)((UInt)c);
119 UChar* p = (UChar*)s;
120 UChar* last = NULL;
121 while (True) {
122 if (*p == ch) last = p;
123 if (*p == 0) return last;
124 p++;
125 }
126}
127
njn46275862005-03-24 04:00:03 +0000128DECL( char* strchr ( const char* s, int c ) )
njn3e884182003-04-15 13:03:23 +0000129{
130 UChar ch = (UChar)((UInt)c);
131 UChar* p = (UChar*)s;
132 while (True) {
133 if (*p == ch) return p;
134 if (*p == 0) return NULL;
135 p++;
136 }
137}
138
njn46275862005-03-24 04:00:03 +0000139DECL( char* strcat ( char* dst, const char* src ) )
njn3e884182003-04-15 13:03:23 +0000140{
njn34419c12003-05-02 17:24:29 +0000141 const Char* src_orig = src;
142 Char* dst_orig = dst;
njn3e884182003-04-15 13:03:23 +0000143 while (*dst) dst++;
144 while (*src) *dst++ = *src++;
145 *dst = 0;
146
147 /* This is a bit redundant, I think; any overlap and the strcat will
148 go forever... or until a seg fault occurs. */
sewardjdda830a2003-07-20 22:28:42 +0000149 if (is_overlap(dst_orig,
150 src_orig,
151 (Addr)dst-(Addr)dst_orig+1,
152 (Addr)src-(Addr)src_orig+1))
njn34419c12003-05-02 17:24:29 +0000153 complain2("strcat", dst_orig, src_orig);
njn3e884182003-04-15 13:03:23 +0000154
155 return dst_orig;
156}
157
njn46275862005-03-24 04:00:03 +0000158DECL( char* strncat ( char* dst, const char* src, SizeT n ) )
njn3e884182003-04-15 13:03:23 +0000159{
njn34419c12003-05-02 17:24:29 +0000160 const Char* src_orig = src;
161 Char* dst_orig = dst;
njnc6168192004-11-29 13:54:10 +0000162 SizeT m = 0;
njn3e884182003-04-15 13:03:23 +0000163
164 while (*dst) dst++;
njn9a90c7b2003-04-25 21:37:20 +0000165 while (m < n && *src) { m++; *dst++ = *src++; } /* concat <= n chars */
njnb6483f82003-04-25 21:38:23 +0000166 *dst = 0; /* always add null */
njn3e884182003-04-15 13:03:23 +0000167
168 /* This checks for overlap after copying, unavoidable without
169 pre-counting lengths... should be ok */
sewardjdda830a2003-07-20 22:28:42 +0000170 if (is_overlap(dst_orig,
171 src_orig,
172 (Addr)dst-(Addr)dst_orig+1,
173 (Addr)src-(Addr)src_orig+1))
njn34419c12003-05-02 17:24:29 +0000174 complain3("strncat", dst_orig, src_orig, n);
njn3e884182003-04-15 13:03:23 +0000175
176 return dst_orig;
177}
178
njn46275862005-03-24 04:00:03 +0000179DECL( SizeT strnlen ( const char* str, SizeT n ) )
jsewardb19cff62003-12-22 22:39:15 +0000180{
njnc6168192004-11-29 13:54:10 +0000181 SizeT i = 0;
jsewardb19cff62003-12-22 22:39:15 +0000182 while (i < n && str[i] != 0) i++;
183 return i;
184}
185
njn46275862005-03-24 04:00:03 +0000186DECL( SizeT strlen ( const char* str ) )
njn3e884182003-04-15 13:03:23 +0000187{
njnc6168192004-11-29 13:54:10 +0000188 SizeT i = 0;
njn3e884182003-04-15 13:03:23 +0000189 while (str[i] != 0) i++;
190 return i;
191}
192
njn46275862005-03-24 04:00:03 +0000193DECL( char* strcpy ( char* dst, const char* src ) )
njn3e884182003-04-15 13:03:23 +0000194{
njn34419c12003-05-02 17:24:29 +0000195 const Char* src_orig = src;
196 Char* dst_orig = dst;
njn3e884182003-04-15 13:03:23 +0000197
198 while (*src) *dst++ = *src++;
199 *dst = 0;
200
201 /* This checks for overlap after copying, unavoidable without
202 pre-counting length... should be ok */
sewardjdda830a2003-07-20 22:28:42 +0000203 if (is_overlap(dst_orig,
204 src_orig,
205 (Addr)dst-(Addr)dst_orig+1,
206 (Addr)src-(Addr)src_orig+1))
njn34419c12003-05-02 17:24:29 +0000207 complain2("strcpy", dst_orig, src_orig);
njn3e884182003-04-15 13:03:23 +0000208
209 return dst_orig;
210}
211
njn46275862005-03-24 04:00:03 +0000212DECL( char* strncpy ( char* dst, const char* src, SizeT n ) )
njn3e884182003-04-15 13:03:23 +0000213{
nethercote1e6d7652003-11-02 17:43:27 +0000214 const Char* src_orig = src;
215 Char* dst_orig = dst;
njnc6168192004-11-29 13:54:10 +0000216 SizeT m = 0;
njn3e884182003-04-15 13:03:23 +0000217
njn9a90c7b2003-04-25 21:37:20 +0000218 while (m < n && *src) { m++; *dst++ = *src++; }
nethercote1e6d7652003-11-02 17:43:27 +0000219 /* Check for overlap after copying; all n bytes of dst are relevant,
220 but only m+1 bytes of src if terminator was found */
221 if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n))
222 complain3("strncpy", dst, src, n);
njn3e884182003-04-15 13:03:23 +0000223 while (m++ < n) *dst++ = 0; /* must pad remainder with nulls */
224
225 return dst_orig;
226}
227
njn46275862005-03-24 04:00:03 +0000228DECL( int strncmp ( const char* s1, const char* s2, SizeT nmax ) )
njn3e884182003-04-15 13:03:23 +0000229{
njnc6168192004-11-29 13:54:10 +0000230 SizeT n = 0;
njn3e884182003-04-15 13:03:23 +0000231 while (True) {
232 if (n >= nmax) return 0;
233 if (*s1 == 0 && *s2 == 0) return 0;
234 if (*s1 == 0) return -1;
235 if (*s2 == 0) return 1;
236
237 if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1;
238 if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1;
239
240 s1++; s2++; n++;
241 }
242}
243
njn46275862005-03-24 04:00:03 +0000244DECL( int strcmp ( const char* s1, const char* s2 ) )
njn3e884182003-04-15 13:03:23 +0000245{
246 register unsigned char c1;
247 register unsigned char c2;
248 while (True) {
249 c1 = *(unsigned char *)s1;
250 c2 = *(unsigned char *)s2;
251 if (c1 != c2) break;
252 if (c1 == 0) break;
253 s1++; s2++;
254 }
255 if ((unsigned char)c1 < (unsigned char)c2) return -1;
256 if ((unsigned char)c1 > (unsigned char)c2) return 1;
257 return 0;
258}
259
njn46275862005-03-24 04:00:03 +0000260DECL( void* memchr(const void *s, int c, SizeT n) )
njn3e884182003-04-15 13:03:23 +0000261{
njnc6168192004-11-29 13:54:10 +0000262 SizeT i;
njn3e884182003-04-15 13:03:23 +0000263 UChar c0 = (UChar)c;
264 UChar* p = (UChar*)s;
265 for (i = 0; i < n; i++)
266 if (p[i] == c0) return (void*)(&p[i]);
267 return NULL;
268}
269
njn46275862005-03-24 04:00:03 +0000270DECL( void* memcpy( void *dst, const void *src, SizeT len ) )
njn3e884182003-04-15 13:03:23 +0000271{
272 register char *d;
273 register char *s;
274
thughes7bddb342004-08-23 18:39:09 +0000275 if (len == 0)
276 return dst;
277
sewardjdda830a2003-07-20 22:28:42 +0000278 if (is_overlap(dst, src, len, len))
njn3e884182003-04-15 13:03:23 +0000279 complain3("memcpy", dst, src, len);
thughes7bddb342004-08-23 18:39:09 +0000280
njn3e884182003-04-15 13:03:23 +0000281 if ( dst > src ) {
282 d = (char *)dst + len - 1;
283 s = (char *)src + len - 1;
284 while ( len >= 4 ) {
285 *d-- = *s--;
286 *d-- = *s--;
287 *d-- = *s--;
288 *d-- = *s--;
289 len -= 4;
290 }
291 while ( len-- ) {
292 *d-- = *s--;
293 }
294 } else if ( dst < src ) {
295 d = (char *)dst;
296 s = (char *)src;
297 while ( len >= 4 ) {
298 *d++ = *s++;
299 *d++ = *s++;
300 *d++ = *s++;
301 *d++ = *s++;
302 len -= 4;
303 }
304 while ( len-- ) {
305 *d++ = *s++;
306 }
307 }
308 return dst;
309}
310
njn46275862005-03-24 04:00:03 +0000311DECL( int memcmp ( const void *s1V, const void *s2V, SizeT n ) )
sewardj3ceec242003-07-30 21:24:25 +0000312{
313 int res;
314 unsigned char a0;
315 unsigned char b0;
316 unsigned char* s1 = (unsigned char*)s1V;
317 unsigned char* s2 = (unsigned char*)s2V;
318
319 while (n != 0) {
320 a0 = s1[0];
321 b0 = s2[0];
322 s1 += 1;
323 s2 += 1;
324 res = ((int)a0) - ((int)b0);
325 if (res != 0)
326 return res;
327 n -= 1;
328 }
329 return 0;
330}
njn3e884182003-04-15 13:03:23 +0000331
jseward0845ef82003-12-22 22:31:27 +0000332
333/* Copy SRC to DEST, returning the address of the terminating '\0' in
334 DEST. (minor variant of strcpy) */
335
njn46275862005-03-24 04:00:03 +0000336DECL( char* stpcpy ( char* dst, const char* src ) )
jsewarddc8778a2003-12-21 23:29:16 +0000337{
jseward0845ef82003-12-22 22:31:27 +0000338 const Char* src_orig = src;
339 Char* dst_orig = dst;
jsewarddc8778a2003-12-21 23:29:16 +0000340
jseward0845ef82003-12-22 22:31:27 +0000341 while (*src) *dst++ = *src++;
342 *dst = 0;
jsewarddc8778a2003-12-21 23:29:16 +0000343
jseward0845ef82003-12-22 22:31:27 +0000344 /* This checks for overlap after copying, unavoidable without
345 pre-counting length... should be ok */
346 if (is_overlap(dst_orig,
347 src_orig,
348 (Addr)dst-(Addr)dst_orig+1,
349 (Addr)src-(Addr)src_orig+1))
350 complain2("stpcpy", dst_orig, src_orig);
351
352 return dst;
jsewarddc8778a2003-12-21 23:29:16 +0000353}
354
njn46275862005-03-24 04:00:03 +0000355DECL( void *memset(void *s, Int c, SizeT n) )
sewardjb5f6f512005-03-10 23:59:00 +0000356{
357 unsigned char *cp = s;
358
359 while(n--)
360 *cp++ = c;
361
362 return s;
363}
364
jseward0845ef82003-12-22 22:31:27 +0000365
sewardj4e9a4b62004-11-23 00:20:17 +0000366/* Find the first occurrence of C in S or the final NUL byte. */
367
njn46275862005-03-24 04:00:03 +0000368DECL( char* glibc232_strchrnul (const char* s, int c_in) )
sewardj4e9a4b62004-11-23 00:20:17 +0000369{
370 unsigned char c = (unsigned char) c_in;
371 unsigned char* char_ptr = (unsigned char *)s;
372 while (1) {
373 if (*char_ptr == 0) return char_ptr;
374 if (*char_ptr == c) return char_ptr;
375 char_ptr++;
376 }
377}
378
379
380/* Find the first occurrence of C in S. */
381
njn46275862005-03-24 04:00:03 +0000382DECL( char* glibc232_rawmemchr (const char* s, int c_in) )
sewardj4e9a4b62004-11-23 00:20:17 +0000383{
384 unsigned char c = (unsigned char) c_in;
385 unsigned char* char_ptr = (unsigned char *)s;
386 while (1) {
387 if (*char_ptr == c) return char_ptr;
388 char_ptr++;
389 }
390}
391
392
njn3e884182003-04-15 13:03:23 +0000393/*--------------------------------------------------------------------*/
njn46275862005-03-24 04:00:03 +0000394/*--- end ---*/
njn3e884182003-04-15 13:03:23 +0000395/*--------------------------------------------------------------------*/