Fix undefined behavior in WTF::equal() in StringImpl.h for i386/x86_64
authorddkilzer@apple.com <ddkilzer@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 15 Mar 2014 15:21:06 +0000 (15:21 +0000)
committerddkilzer@apple.com <ddkilzer@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 15 Mar 2014 15:21:06 +0000 (15:21 +0000)
<http://webkit.org/b/130283>
<rdar://problem/16281477>

Reviewed by Geoff Garen.

* wtf/text/StringImpl.h:
(WTF::loadUnaligned): Add template method.
(WTF::equal): Switch to using loadUnaligned<>().

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@165681 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WTF/ChangeLog
Source/WTF/wtf/text/StringImpl.h

index 49c0b402859fd72f4bde398247db7e15e8c35f57..74b40f8383244dc82649fa26a3024e3a64e84797 100644 (file)
@@ -1,3 +1,15 @@
+2014-03-15  David Kilzer  <ddkilzer@apple.com>
+
+        Fix undefined behavior in WTF::equal() in StringImpl.h for i386/x86_64
+        <http://webkit.org/b/130283>
+        <rdar://problem/16281477>
+
+        Reviewed by Geoff Garen.
+
+        * wtf/text/StringImpl.h:
+        (WTF::loadUnaligned): Add template method.
+        (WTF::equal): Switch to using loadUnaligned<>().
+
 2014-03-14  Mark Rowe  <mrowe@apple.com>
 
         Fix the production build.
index 91dab77ad6baa240ff79f697bb65fadecd87f528..0285210d9c371962c6b69070b3e2af8fa8b3b95c 100644 (file)
@@ -915,95 +915,105 @@ inline bool equal(const LChar* a, StringImpl* b) { return equal(b, a); }
 inline bool equal(const char* a, StringImpl* b) { return equal(b, reinterpret_cast<const LChar*>(a)); }
 WTF_EXPORT_STRING_API bool equal(const StringImpl& a, const StringImpl& b);
 
+template<typename T>
+inline T loadUnaligned(const char* s)
+{
+    T tmp;
+    memcpy(&tmp, s, sizeof(T));
+    return tmp;
+}
+
 // Do comparisons 8 or 4 bytes-at-a-time on architectures where it's safe.
 #if CPU(X86_64) || CPU(ARM64)
-ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length)
+ALWAYS_INLINE bool equal(const LChar* aLChar, const LChar* bLChar, unsigned length)
 {
     unsigned dwordLength = length >> 3;
 
-    if (dwordLength) {
-        const uint64_t* aDWordCharacters = reinterpret_cast<const uint64_t*>(a);
-        const uint64_t* bDWordCharacters = reinterpret_cast<const uint64_t*>(b);
+    const char* a = reinterpret_cast<const char*>(aLChar);
+    const char* b = reinterpret_cast<const char*>(bLChar);
 
+    if (dwordLength) {
         for (unsigned i = 0; i != dwordLength; ++i) {
-            if (*aDWordCharacters++ != *bDWordCharacters++)
+            if (loadUnaligned<uint64_t>(a) != loadUnaligned<uint64_t>(b))
                 return false;
-        }
 
-        a = reinterpret_cast<const LChar*>(aDWordCharacters);
-        b = reinterpret_cast<const LChar*>(bDWordCharacters);
+            a += sizeof(uint64_t);
+            b += sizeof(uint64_t);
+        }
     }
 
     if (length & 4) {
-        if (*reinterpret_cast<const uint32_t*>(a) != *reinterpret_cast<const uint32_t*>(b))
+        if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))
             return false;
 
-        a += 4;
-        b += 4;
+        a += sizeof(uint32_t);
+        b += sizeof(uint32_t);
     }
 
     if (length & 2) {
-        if (*reinterpret_cast<const uint16_t*>(a) != *reinterpret_cast<const uint16_t*>(b))
+        if (loadUnaligned<uint16_t>(a) != loadUnaligned<uint16_t>(b))
             return false;
 
-        a += 2;
-        b += 2;
+        a += sizeof(uint16_t);
+        b += sizeof(uint16_t);
     }
 
-    if (length & 1 && (*a != *b))
+    if (length & 1 && (*reinterpret_cast<const LChar*>(a) != *reinterpret_cast<const LChar*>(b)))
         return false;
 
     return true;
 }
 
-ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length)
+ALWAYS_INLINE bool equal(const UChar* aUChar, const UChar* bUChar, unsigned length)
 {
     unsigned dwordLength = length >> 2;
-    
-    if (dwordLength) {
-        const uint64_t* aDWordCharacters = reinterpret_cast<const uint64_t*>(a);
-        const uint64_t* bDWordCharacters = reinterpret_cast<const uint64_t*>(b);
 
+    const char* a = reinterpret_cast<const char*>(aUChar);
+    const char* b = reinterpret_cast<const char*>(bUChar);
+
+    if (dwordLength) {
         for (unsigned i = 0; i != dwordLength; ++i) {
-            if (*aDWordCharacters++ != *bDWordCharacters++)
+            if (loadUnaligned<uint64_t>(a) != loadUnaligned<uint64_t>(b))
                 return false;
-        }
 
-        a = reinterpret_cast<const UChar*>(aDWordCharacters);
-        b = reinterpret_cast<const UChar*>(bDWordCharacters);
+            a += sizeof(uint64_t);
+            b += sizeof(uint64_t);
+        }
     }
 
     if (length & 2) {
-        if (*reinterpret_cast<const uint32_t*>(a) != *reinterpret_cast<const uint32_t*>(b))
+        if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))
             return false;
 
-        a += 2;
-        b += 2;
+        a += sizeof(uint32_t);
+        b += sizeof(uint32_t);
     }
 
-    if (length & 1 && (*a != *b))
+    if (length & 1 && (*reinterpret_cast<const UChar*>(a) != *reinterpret_cast<const UChar*>(b)))
         return false;
 
     return true;
 }
 #elif CPU(X86)
-ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length)
+ALWAYS_INLINE bool equal(const LChar* aLChar, const LChar* bLChar, unsigned length)
 {
-    const uint32_t* aCharacters = reinterpret_cast<const uint32_t*>(a);
-    const uint32_t* bCharacters = reinterpret_cast<const uint32_t*>(b);
+    const char* a = reinterpret_cast<const char*>(aLChar);
+    const char* b = reinterpret_cast<const char*>(bLChar);
 
     unsigned wordLength = length >> 2;
     for (unsigned i = 0; i != wordLength; ++i) {
-        if (*aCharacters++ != *bCharacters++)
+        if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))
             return false;
+        a += sizeof(uint32_t);
+        b += sizeof(uint32_t);
     }
 
     length &= 3;
 
     if (length) {
-        const LChar* aRemainder = reinterpret_cast<const LChar*>(aCharacters);
-        const LChar* bRemainder = reinterpret_cast<const LChar*>(bCharacters);
-        
+        const LChar* aRemainder = reinterpret_cast<const LChar*>(a);
+        const LChar* bRemainder = reinterpret_cast<const LChar*>(b);
+
         for (unsigned i = 0; i <  length; ++i) {
             if (aRemainder[i] != bRemainder[i])
                 return false;
@@ -1013,20 +1023,22 @@ ALWAYS_INLINE bool equal(const LChar* a, const LChar* b, unsigned length)
     return true;
 }
 
-ALWAYS_INLINE bool equal(const UChar* a, const UChar* b, unsigned length)
+ALWAYS_INLINE bool equal(const UChar* aUChar, const UChar* bUChar, unsigned length)
 {
-    const uint32_t* aCharacters = reinterpret_cast<const uint32_t*>(a);
-    const uint32_t* bCharacters = reinterpret_cast<const uint32_t*>(b);
-    
+    const char* a = reinterpret_cast<const char*>(aUChar);
+    const char* b = reinterpret_cast<const char*>(bUChar);
+
     unsigned wordLength = length >> 1;
     for (unsigned i = 0; i != wordLength; ++i) {
-        if (*aCharacters++ != *bCharacters++)
+        if (loadUnaligned<uint32_t>(a) != loadUnaligned<uint32_t>(b))
             return false;
+        a += sizeof(uint32_t);
+        b += sizeof(uint32_t);
     }
-    
-    if (length & 1 && *reinterpret_cast<const UChar*>(aCharacters) != *reinterpret_cast<const UChar*>(bCharacters))
+
+    if (length & 1 && *reinterpret_cast<const UChar*>(a) != *reinterpret_cast<const UChar*>(b))
         return false;
-    
+
     return true;
 }
 #elif PLATFORM(IOS) && WTF_ARM_ARCH_AT_LEAST(7)