blob: 560343089c71189f468a9e82a49accc711464064 [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
nethercotebb1c9912004-01-04 16:43:23 +000012 Copyright (C) 2000-2004 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
fitzhardinge98abfc72003-12-16 02:05:15 +000037static Addr record_overlap_error;
38
39static int init_done;
40
41/* Startup hook - called as init section */
42static void init(void) __attribute__((constructor));
43static void init(void)
44{
45 if (init_done)
46 return;
47
48 VALGRIND_MAGIC_SEQUENCE(record_overlap_error, 0,
49 _VG_USERREQ__MEMCHECK_GET_RECORD_OVERLAP,
50 0, 0, 0, 0);
51 init_done = 1;
52}
53
njn3e884182003-04-15 13:03:23 +000054/* ---------------------------------------------------------------------
55 The normal versions of these functions are hyper-optimised, which fools
56 Memcheck and cause spurious value warnings. So we replace them with
57 simpler versions. THEY RUN ON SIMD CPU!
58 ------------------------------------------------------------------ */
59
sewardjdda830a2003-07-20 22:28:42 +000060/* Figure out if [dst .. dst+dstlen-1] overlaps with
61 [src .. src+srclen-1].
62 We assume that the address ranges do not wrap around
63 (which is safe since on Linux addresses >= 0xC0000000
64 are not accessible and the program will segfault in this
65 circumstance, presumably).
66*/
njn3e884182003-04-15 13:03:23 +000067static __inline__
sewardjdda830a2003-07-20 22:28:42 +000068Bool is_overlap ( void* dst, const void* src, UInt dstlen, UInt srclen )
njn3e884182003-04-15 13:03:23 +000069{
sewardjdda830a2003-07-20 22:28:42 +000070 Addr loS, hiS, loD, hiD;
71
72 if (dstlen == 0 || srclen == 0)
73 return False;
74
75 loS = (Addr)src;
76 loD = (Addr)dst;
77 hiS = loS + srclen - 1;
78 hiD = loD + dstlen - 1;
79
80 /* So figure out if [loS .. hiS] overlaps with [loD .. hiD]. */
81 if (loS < loD) {
82 return !(hiS < loD);
83 }
84 else if (loD < loS) {
85 return !(hiD < loS);
86 }
87 else {
88 /* They start at same place. Since we know neither of them has
89 zero length, they must overlap. */
90 return True;
91 }
njn3e884182003-04-15 13:03:23 +000092}
93
sewardjdda830a2003-07-20 22:28:42 +000094
njn3e884182003-04-15 13:03:23 +000095static __inline__
96void complain2 ( Char* s, char* dst, const char* src )
97{
njnb6cae9f2003-09-04 20:50:47 +000098 OverlapExtra extra = {
99 .src = (Addr)src, .dst = (Addr)dst, .len = -1,
100 };
fitzhardinge98abfc72003-12-16 02:05:15 +0000101 init();
102 VALGRIND_NON_SIMD_CALL2( record_overlap_error, s, &extra );
njn3e884182003-04-15 13:03:23 +0000103}
104
105static __inline__
106void complain3 ( Char* s, void* dst, const void* src, int n )
107{
njnb6cae9f2003-09-04 20:50:47 +0000108 /* Must wrap it up here, because we cannot pass 4 args to core */
109 OverlapExtra extra = {
110 .src = (Addr)src, .dst = (Addr)dst, .len = n,
111 };
fitzhardinge98abfc72003-12-16 02:05:15 +0000112 init();
113 VALGRIND_NON_SIMD_CALL2( record_overlap_error, s, &extra );
njn3e884182003-04-15 13:03:23 +0000114}
115
116char* strrchr ( const char* s, int c )
117{
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
128char* strchr ( const char* s, int c )
129{
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
139char* strcat ( char* dst, const char* src )
140{
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
158char* strncat ( char* dst, const char* src, int n )
159{
njn34419c12003-05-02 17:24:29 +0000160 const Char* src_orig = src;
161 Char* dst_orig = dst;
njn3e884182003-04-15 13:03:23 +0000162 Int m = 0;
163
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
jsewardb19cff62003-12-22 22:39:15 +0000179unsigned int strnlen ( const char* str, unsigned int n )
180{
181 UInt i = 0;
182 while (i < n && str[i] != 0) i++;
183 return i;
184}
185
njn3e884182003-04-15 13:03:23 +0000186unsigned int strlen ( const char* str )
187{
188 UInt i = 0;
189 while (str[i] != 0) i++;
190 return i;
191}
192
193char* strcpy ( char* dst, const char* src )
194{
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
212char* strncpy ( char* dst, const char* src, int n )
213{
nethercote1e6d7652003-11-02 17:43:27 +0000214 const Char* src_orig = src;
215 Char* dst_orig = dst;
njn3e884182003-04-15 13:03:23 +0000216 Int m = 0;
217
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
228int strncmp ( const unsigned char* s1, const unsigned char* s2,
229 unsigned int nmax )
230{
231 unsigned int n = 0;
232 while (True) {
233 if (n >= nmax) return 0;
234 if (*s1 == 0 && *s2 == 0) return 0;
235 if (*s1 == 0) return -1;
236 if (*s2 == 0) return 1;
237
238 if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1;
239 if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1;
240
241 s1++; s2++; n++;
242 }
243}
244
245int strcmp ( const char* s1, const char* s2 )
246{
247 register unsigned char c1;
248 register unsigned char c2;
249 while (True) {
250 c1 = *(unsigned char *)s1;
251 c2 = *(unsigned char *)s2;
252 if (c1 != c2) break;
253 if (c1 == 0) break;
254 s1++; s2++;
255 }
256 if ((unsigned char)c1 < (unsigned char)c2) return -1;
257 if ((unsigned char)c1 > (unsigned char)c2) return 1;
258 return 0;
259}
260
261void* memchr(const void *s, int c, unsigned int n)
262{
263 unsigned int i;
264 UChar c0 = (UChar)c;
265 UChar* p = (UChar*)s;
266 for (i = 0; i < n; i++)
267 if (p[i] == c0) return (void*)(&p[i]);
268 return NULL;
269}
270
271void* memcpy( void *dst, const void *src, unsigned int len )
272{
273 register char *d;
274 register char *s;
275
sewardjdda830a2003-07-20 22:28:42 +0000276 if (is_overlap(dst, src, len, len))
njn3e884182003-04-15 13:03:23 +0000277 complain3("memcpy", dst, src, len);
278
279 if ( dst > src ) {
280 d = (char *)dst + len - 1;
281 s = (char *)src + len - 1;
282 while ( len >= 4 ) {
283 *d-- = *s--;
284 *d-- = *s--;
285 *d-- = *s--;
286 *d-- = *s--;
287 len -= 4;
288 }
289 while ( len-- ) {
290 *d-- = *s--;
291 }
292 } else if ( dst < src ) {
293 d = (char *)dst;
294 s = (char *)src;
295 while ( len >= 4 ) {
296 *d++ = *s++;
297 *d++ = *s++;
298 *d++ = *s++;
299 *d++ = *s++;
300 len -= 4;
301 }
302 while ( len-- ) {
303 *d++ = *s++;
304 }
305 }
306 return dst;
307}
308
sewardj3ceec242003-07-30 21:24:25 +0000309int memcmp ( const void *s1V, const void *s2V, unsigned int n )
310{
311 int res;
312 unsigned char a0;
313 unsigned char b0;
314 unsigned char* s1 = (unsigned char*)s1V;
315 unsigned char* s2 = (unsigned char*)s2V;
316
317 while (n != 0) {
318 a0 = s1[0];
319 b0 = s2[0];
320 s1 += 1;
321 s2 += 1;
322 res = ((int)a0) - ((int)b0);
323 if (res != 0)
324 return res;
325 n -= 1;
326 }
327 return 0;
328}
njn3e884182003-04-15 13:03:23 +0000329
jseward0845ef82003-12-22 22:31:27 +0000330
331/* Copy SRC to DEST, returning the address of the terminating '\0' in
332 DEST. (minor variant of strcpy) */
333
334char* stpcpy ( char* dst, const char* src )
jsewarddc8778a2003-12-21 23:29:16 +0000335{
jseward0845ef82003-12-22 22:31:27 +0000336 const Char* src_orig = src;
337 Char* dst_orig = dst;
jsewarddc8778a2003-12-21 23:29:16 +0000338
jseward0845ef82003-12-22 22:31:27 +0000339 while (*src) *dst++ = *src++;
340 *dst = 0;
jsewarddc8778a2003-12-21 23:29:16 +0000341
jseward0845ef82003-12-22 22:31:27 +0000342 /* This checks for overlap after copying, unavoidable without
343 pre-counting length... should be ok */
344 if (is_overlap(dst_orig,
345 src_orig,
346 (Addr)dst-(Addr)dst_orig+1,
347 (Addr)src-(Addr)src_orig+1))
348 complain2("stpcpy", dst_orig, src_orig);
349
350 return dst;
jsewarddc8778a2003-12-21 23:29:16 +0000351}
352
jseward0845ef82003-12-22 22:31:27 +0000353
njn3e884182003-04-15 13:03:23 +0000354/*--------------------------------------------------------------------*/
njn66fe05a2003-07-22 09:12:33 +0000355/*--- end mac_replace_strmem.c ---*/
njn3e884182003-04-15 13:03:23 +0000356/*--------------------------------------------------------------------*/