This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Is ISO memcmp("abc","ade",10000) safe?


> If this is indeed the case, GCC's current transformation of
> strncmp("abc","ade",10000) into memcmp("abc","ade",10000),

This is not what gcc does.  It transforms it to
memcmp ("abc", "ade", 4), which is safe.  But there are other
cases that are being transformed unsafely:

strncmp ("abcdefghijklmnoprstuvwxyz", str,100) is turned into
memcmp ("abcdefghijklmnoprstuvwxyz", str, 27) .
If the underlying object that str points to is smaller than
27 bytes, references beyond the end of that object can occur.

And this is not something that can only be expected of inefficient
implementations; if you want to compare unaligned memory blocks
word-by-word, it is only natural to fetch a bit more from one
block:

For simplicity, let's assume that the machine is big endian,
signed left shifts use modulo arithmetic like the unsigned ones,
right shifts of signed integer types are actually signed shifts,
a shift of a type by its size in bits works, and the smallest
unit that can be mapped is not smaller than a long, with
alignment sizeof(long).

int
memcmp (const void *s1, const void *s2, size_t n)
{
  long *p1, l1, l2, *last;
  unsigned long *p2, u1, u2;
  size_t d1, d2, d3, shift, lshift, rshift;
  unsigned char *c1, *c2;

  if (n > sizeof (long))
    {
      p1 = (long *)((size_t)s1 & ~sizeof(long));
      d1 = (char *)s1 - (char *)p1;
      shift = d1 * CHAR_BIT;
      l1 = (unsigned long)*p1++ << shift >> shift;
      p2 = (unsigned long *)(((size_t)s2 - d1) & ~sizeof(long));
      d2 = (char *)s2 - (char *)p2;
      shift = d2 * CHAR_BIT;
      if (shift < sizeof (long) * CHAR_BITS)
        {
          u1 = *p2 << shift >> shift;
          u2 = *++p2;
        }
      else
        {
          u1 = 0;
          shift -= sizeof (long) * CHAR_BIT;
          u2 = *++p2 << shift >> shift;
        }
      d3 = d2 - d1;
      lshift = d3 * CHAR_BIT;
      rshift = sizeof (long) * CHAR_BIT - d3;
      last = (long *)((size_t)s1 + n & ~long);
      goto start;
      do
        {
          l1 = *p1++;
          u2 = *++p2;
        start:
          l2 = (u1 << lshift | u2 >> rshift);
          if (l1 != l2)
            return l1 - l2 >> (sizeof (long) - sizeof (int)) * CHAR_BIT;
          u1 = u2;
        }
      while (p1 != last);
      d3 = (char *)last - (char *)s1;
      s1 = (char *)s1 - d3;
      s2 = (char *)s2 - d3;
      n -= d3;
    }
  c1 = s1;
  c2 = s2;
  for (c1 = s1, c2 = s2; n; n--)
    {
      if (*c1 != *c2)
        return *c1 - *c2;
      c1++;
      c2++;
    }
  return 0;
}

-- 
--------------------------
SuperH (UK) Ltd.
2410 Aztec West / Almondsbury / BRISTOL / BS32 4QX
T:+44 1454 465658


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]