mc_replace_strmem.c revision 98abfc7bb7798c4ac4580f7e0bc7171de94a0255
1
2/*--------------------------------------------------------------------*/
3/*--- Replacements for strcpy(), memcpy() et al, which run on the  ---*/
4/*--- simulated CPU.                                               ---*/
5/*---                                         mac_replace_strmem.c ---*/
6/*--------------------------------------------------------------------*/
7
8/*
9   This file is part of MemCheck, a heavyweight Valgrind tool for
10   detecting memory errors.
11
12   Copyright (C) 2000-2003 Julian Seward
13      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
33#include "mc_include.h"
34#include "memcheck.h"
35#include "valgrind.h"
36
37static 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
54/* ---------------------------------------------------------------------
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
60/* 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*/
67static __inline__
68Bool is_overlap ( void* dst, const void* src, UInt dstlen, UInt srclen )
69{
70   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   }
92}
93
94
95static __inline__
96void complain2 ( Char* s, char* dst, const char* src )
97{
98   OverlapExtra extra = {
99      .src = (Addr)src, .dst = (Addr)dst, .len = -1,
100   };
101   init();
102   VALGRIND_NON_SIMD_CALL2( record_overlap_error, s, &extra );
103}
104
105static __inline__
106void complain3 ( Char* s, void* dst, const void* src, int n )
107{
108   /* 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   };
112   init();
113   VALGRIND_NON_SIMD_CALL2( record_overlap_error, s, &extra );
114}
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{
141   const Char* src_orig = src;
142         Char* dst_orig = dst;
143   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. */
149   if (is_overlap(dst_orig,
150                  src_orig,
151                  (Addr)dst-(Addr)dst_orig+1,
152                  (Addr)src-(Addr)src_orig+1))
153      complain2("strcat", dst_orig, src_orig);
154
155   return dst_orig;
156}
157
158char* strncat ( char* dst, const char* src, int n )
159{
160   const Char* src_orig = src;
161         Char* dst_orig = dst;
162   Int   m = 0;
163
164   while (*dst) dst++;
165   while (m   < n && *src) { m++; *dst++ = *src++; } /* concat <= n chars */
166   *dst = 0;                                         /* always add null   */
167
168   /* This checks for overlap after copying, unavoidable without
169      pre-counting lengths... should be ok */
170   if (is_overlap(dst_orig,
171                  src_orig,
172                  (Addr)dst-(Addr)dst_orig+1,
173                  (Addr)src-(Addr)src_orig+1))
174      complain3("strncat", dst_orig, src_orig, n);
175
176   return dst_orig;
177}
178
179unsigned int strlen ( const char* str )
180{
181   UInt i = 0;
182   while (str[i] != 0) i++;
183   return i;
184}
185
186char* strcpy ( char* dst, const char* src )
187{
188   const Char* src_orig = src;
189         Char* dst_orig = dst;
190
191   while (*src) *dst++ = *src++;
192   *dst = 0;
193
194   /* This checks for overlap after copying, unavoidable without
195      pre-counting length... should be ok */
196   if (is_overlap(dst_orig,
197                  src_orig,
198                  (Addr)dst-(Addr)dst_orig+1,
199                  (Addr)src-(Addr)src_orig+1))
200      complain2("strcpy", dst_orig, src_orig);
201
202   return dst_orig;
203}
204
205char* strncpy ( char* dst, const char* src, int n )
206{
207   const Char* src_orig = src;
208         Char* dst_orig = dst;
209   Int   m = 0;
210
211   while (m   < n && *src) { m++; *dst++ = *src++; }
212   /* Check for overlap after copying; all n bytes of dst are relevant,
213      but only m+1 bytes of src if terminator was found */
214   if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n))
215      complain3("strncpy", dst, src, n);
216   while (m++ < n) *dst++ = 0;         /* must pad remainder with nulls */
217
218   return dst_orig;
219}
220
221int strncmp ( const unsigned char* s1, const unsigned char* s2,
222              unsigned int nmax )
223{
224   unsigned int n = 0;
225   while (True) {
226      if (n >= nmax) return 0;
227      if (*s1 == 0 && *s2 == 0) return 0;
228      if (*s1 == 0) return -1;
229      if (*s2 == 0) return 1;
230
231      if (*(unsigned char*)s1 < *(unsigned char*)s2) return -1;
232      if (*(unsigned char*)s1 > *(unsigned char*)s2) return 1;
233
234      s1++; s2++; n++;
235   }
236}
237
238int strcmp ( const char* s1, const char* s2 )
239{
240   register unsigned char c1;
241   register unsigned char c2;
242   while (True) {
243      c1 = *(unsigned char *)s1;
244      c2 = *(unsigned char *)s2;
245      if (c1 != c2) break;
246      if (c1 == 0) break;
247      s1++; s2++;
248   }
249   if ((unsigned char)c1 < (unsigned char)c2) return -1;
250   if ((unsigned char)c1 > (unsigned char)c2) return 1;
251   return 0;
252}
253
254void* memchr(const void *s, int c, unsigned int n)
255{
256   unsigned int i;
257   UChar c0 = (UChar)c;
258   UChar* p = (UChar*)s;
259   for (i = 0; i < n; i++)
260      if (p[i] == c0) return (void*)(&p[i]);
261   return NULL;
262}
263
264void* memcpy( void *dst, const void *src, unsigned int len )
265{
266   register char *d;
267   register char *s;
268
269   if (is_overlap(dst, src, len, len))
270      complain3("memcpy", dst, src, len);
271
272   if ( dst > src ) {
273      d = (char *)dst + len - 1;
274      s = (char *)src + len - 1;
275      while ( len >= 4 ) {
276         *d-- = *s--;
277         *d-- = *s--;
278         *d-- = *s--;
279         *d-- = *s--;
280         len -= 4;
281      }
282      while ( len-- ) {
283         *d-- = *s--;
284      }
285   } else if ( dst < src ) {
286      d = (char *)dst;
287      s = (char *)src;
288      while ( len >= 4 ) {
289         *d++ = *s++;
290         *d++ = *s++;
291         *d++ = *s++;
292         *d++ = *s++;
293         len -= 4;
294      }
295      while ( len-- ) {
296         *d++ = *s++;
297      }
298   }
299   return dst;
300}
301
302int memcmp ( const void *s1V, const void *s2V, unsigned int n )
303{
304   int res;
305   unsigned char a0;
306   unsigned char b0;
307   unsigned char* s1 = (unsigned char*)s1V;
308   unsigned char* s2 = (unsigned char*)s2V;
309
310   while (n != 0) {
311      a0 = s1[0];
312      b0 = s2[0];
313      s1 += 1;
314      s2 += 1;
315      res = ((int)a0) - ((int)b0);
316      if (res != 0)
317         return res;
318      n -= 1;
319   }
320   return 0;
321}
322
323/*--------------------------------------------------------------------*/
324/*--- end                                     mac_replace_strmem.c ---*/
325/*--------------------------------------------------------------------*/
326