Changeset 178722 in webkit


Ignore:
Timestamp:
Jan 20, 2015 10:27:48 AM (9 years ago)
Author:
ap@apple.com
Message:

Make ASan do bounds checks for WTF::Vector
https://bugs.webkit.org/show_bug.cgi?id=140631
rdar://problem/19437718

Reviewed by Darin Adler.

  • wtf/SizeLimits.cpp: Disable Vector object size checks for ASan enabled builds.
  • wtf/Vector.h:

(WTF::VectorBuffer::endOfBuffer):
(WTF::Vector::Vector):
(WTF::Vector::~Vector):
(WTF::Vector::swap):
(WTF::OverflowHandler>::Vector):
(WTF::=):
(WTF::OverflowHandler>::fill):
(WTF::OverflowHandler>::resize):
(WTF::OverflowHandler>::shrink):
(WTF::OverflowHandler>::grow):
(WTF::OverflowHandler>::asanSetInitialBufferSizeTo):
(WTF::OverflowHandler>::asanSetBufferSizeToFullCapacity):
(WTF::OverflowHandler>::asanBufferSizeWillChangeTo):
(WTF::OverflowHandler>::reserveCapacity):
(WTF::OverflowHandler>::tryReserveCapacity):
(WTF::OverflowHandler>::shrinkCapacity):
(WTF::OverflowHandler>::append):
(WTF::OverflowHandler>::tryAppend):
(WTF::OverflowHandler>::appendSlowCase):
(WTF::OverflowHandler>::uncheckedAppend):
(WTF::OverflowHandler>::insert):
(WTF::OverflowHandler>::remove):
(WTF::OverflowHandler>::releaseBuffer):

  • wtf/Compiler.h: Changed ASAN_ENABLED macro fallback value from false to 0,

MSVC was not happy with false.

Location:
trunk/Source/WTF
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r178719 r178722  
     12015-01-19  Alexey Proskuryakov  <ap@apple.com>
     2
     3        Make ASan do bounds checks for WTF::Vector
     4        https://bugs.webkit.org/show_bug.cgi?id=140631
     5        rdar://problem/19437718
     6
     7        Reviewed by Darin Adler.
     8
     9        * wtf/SizeLimits.cpp: Disable Vector object size checks for ASan enabled builds.
     10
     11        * wtf/Vector.h:
     12        (WTF::VectorBuffer::endOfBuffer):
     13        (WTF::Vector::Vector):
     14        (WTF::Vector::~Vector):
     15        (WTF::Vector::swap):
     16        (WTF::OverflowHandler>::Vector):
     17        (WTF::=):
     18        (WTF::OverflowHandler>::fill):
     19        (WTF::OverflowHandler>::resize):
     20        (WTF::OverflowHandler>::shrink):
     21        (WTF::OverflowHandler>::grow):
     22        (WTF::OverflowHandler>::asanSetInitialBufferSizeTo):
     23        (WTF::OverflowHandler>::asanSetBufferSizeToFullCapacity):
     24        (WTF::OverflowHandler>::asanBufferSizeWillChangeTo):
     25        (WTF::OverflowHandler>::reserveCapacity):
     26        (WTF::OverflowHandler>::tryReserveCapacity):
     27        (WTF::OverflowHandler>::shrinkCapacity):
     28        (WTF::OverflowHandler>::append):
     29        (WTF::OverflowHandler>::tryAppend):
     30        (WTF::OverflowHandler>::appendSlowCase):
     31        (WTF::OverflowHandler>::uncheckedAppend):
     32        (WTF::OverflowHandler>::insert):
     33        (WTF::OverflowHandler>::remove):
     34        (WTF::OverflowHandler>::releaseBuffer):
     35
     36        * wtf/Compiler.h: Changed ASAN_ENABLED macro fallback value from false to 0,
     37        MSVC was not happy with false.
     38
    1392015-01-20  Csaba Osztrogonác  <ossy@webkit.org>
    240
  • trunk/Source/WTF/wtf/Compiler.h

    r178104 r178722  
    140140#define ASAN_ENABLED __has_feature(address_sanitizer)
    141141#else
    142 #define ASAN_ENABLED false
     142#define ASAN_ENABLED 0
    143143#endif
    144144
  • trunk/Source/WTF/wtf/SizeLimits.cpp

    r177995 r178722  
    5555};
    5656#endif
     57
     58static_assert(sizeof(OwnPtr<int>) == sizeof(int*), "OwnPtr should stay small!");
     59static_assert(sizeof(PassRefPtr<RefCounted<int>>) == sizeof(int*), "PassRefPtr should stay small!");
     60static_assert(sizeof(RefCounted<int>) == sizeof(SameSizeAsRefCounted), "RefCounted should stay small!");
     61static_assert(sizeof(RefPtr<RefCounted<int>>) == sizeof(int*), "RefPtr should stay small!");
     62
     63#if !ASAN_ENABLED
    5764template<typename T, unsigned inlineCapacity = 0>
    5865struct SameSizeAsVectorWithInlineCapacity;
     
    7178};
    7279
    73 static_assert(sizeof(OwnPtr<int>) == sizeof(int*), "OwnPtr should stay small!");
    74 static_assert(sizeof(PassRefPtr<RefCounted<int>>) == sizeof(int*), "PassRefPtr should stay small!");
    75 static_assert(sizeof(RefCounted<int>) == sizeof(SameSizeAsRefCounted), "RefCounted should stay small!");
    76 static_assert(sizeof(RefPtr<RefCounted<int>>) == sizeof(int*), "RefPtr should stay small!");
    7780static_assert(sizeof(Vector<int>) == sizeof(SameSizeAsVectorWithInlineCapacity<int>), "Vector should stay small!");
    7881static_assert(sizeof(Vector<int, 1>) == sizeof(SameSizeAsVectorWithInlineCapacity<int, 1>), "Vector should stay small!");
    7982static_assert(sizeof(Vector<int, 2>) == sizeof(SameSizeAsVectorWithInlineCapacity<int, 2>), "Vector should stay small!");
    8083static_assert(sizeof(Vector<int, 3>) == sizeof(SameSizeAsVectorWithInlineCapacity<int, 3>), "Vector should stay small!");
     84#endif
    8185}
  • trunk/Source/WTF/wtf/Vector.h

    r177316 r178722  
    3535#include <wtf/VectorTraits.h>
    3636
     37#if ASAN_ENABLED
     38extern "C" void __sanitizer_annotate_contiguous_container(const void* begin, const void* end, const void* old_mid, const void* new_mid);
     39#endif
     40
    3741namespace WTF {
    3842
     
    381385   
    382386    void restoreInlineBufferIfNeeded() { }
     387
     388#if ASAN_ENABLED
     389    void* endOfBuffer()
     390    {
     391        return buffer() + capacity();
     392    }
     393#endif
    383394
    384395    using Base::allocateBuffer;
     
    493504    }
    494505
     506#if ASAN_ENABLED
     507    void* endOfBuffer()
     508    {
     509        ASSERT(buffer());
     510        static_assert((offsetof(VectorBuffer, m_inlineBuffer) + sizeof(m_inlineBuffer)) % 8 == 0, "Inline buffer end needs to be on 8 byte boundary for ASan annotations to work.");
     511
     512        if (buffer() == inlineBuffer())
     513            return reinterpret_cast<char*>(m_inlineBuffer) + sizeof(m_inlineBuffer);
     514
     515        return buffer() + capacity();
     516    }
     517#endif
     518
    495519    using Base::buffer;
    496520    using Base::capacity;
     
    540564    const T* inlineBuffer() const { return reinterpret_cast_ptr<const T*>(m_inlineBuffer); }
    541565
     566#if ASAN_ENABLED
     567    // ASan needs the buffer to begin and end on 8-byte boundaries for annotations to work.
     568    // FIXME: Add a redzone before the buffer to catch off by one accesses. We don't need a guard after, because the buffer is the last member variable.
     569    static const size_t asanInlineBufferAlignment = std::alignment_of<T>::value >= 8 ? std::alignment_of<T>::value : 8;
     570    static const size_t asanAdjustedInlineCapacity = ((sizeof(T) * inlineCapacity + 7) & ~7) / sizeof(T);
     571    typename std::aligned_storage<sizeof(T), asanInlineBufferAlignment>::type m_inlineBuffer[asanAdjustedInlineCapacity];
     572#else
    542573    typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type m_inlineBuffer[inlineCapacity];
     574#endif
    543575};
    544576
     
    573605        : Base(size, size)
    574606    {
     607        asanSetInitialBufferSizeTo(size);
     608
    575609        if (begin())
    576610            TypeOperations::initialize(begin(), end());
     
    580614        : Base(size, size)
    581615    {
     616        asanSetInitialBufferSizeTo(size);
     617
    582618        if (begin())
    583619            TypeOperations::uninitializedFill(begin(), end(), val);
     
    587623    {
    588624        reserveInitialCapacity(initializerList.size());
     625
     626        asanSetInitialBufferSizeTo(initializerList.size());
     627
    589628        for (const auto& element : initializerList)
    590629            uncheckedAppend(element);
     
    595634        if (m_size)
    596635            shrink(0);
     636
     637        asanSetBufferSizeToFullCapacity();
    597638    }
    598639
     
    712753    void swap(Vector<T, inlineCapacity, OverflowHandler>& other)
    713754    {
     755#if ASAN_ENABLED
     756        if (this == &other) // ASan will crash if we try to restrict access to the same buffer twice.
     757            return;
     758#endif
     759
     760        // Make it possible to copy inline buffers.
     761        asanSetBufferSizeToFullCapacity();
     762        other.asanSetBufferSizeToFullCapacity();
     763
    714764        Base::swap(other, m_size, other.m_size);
    715765        std::swap(m_size, other.m_size);
     766
     767        asanSetInitialBufferSizeTo(m_size);
     768        other.asanSetInitialBufferSizeTo(other.m_size);
    716769    }
    717770
     
    727780    template<typename U> U* expandCapacity(size_t newMinCapacity, U*);
    728781    template<typename U> void appendSlowCase(U&&);
     782
     783    void asanSetInitialBufferSizeTo(size_t);
     784    void asanSetBufferSizeToFullCapacity();
     785    void asanBufferSizeWillChangeTo(size_t);
    729786
    730787    using Base::m_size;
     
    739796    using Base::restoreInlineBufferIfNeeded;
    740797    using Base::releaseBuffer;
     798#if ASAN_ENABLED
     799    using Base::endOfBuffer;
     800#endif
    741801};
    742802
     
    745805    : Base(other.capacity(), other.size())
    746806{
     807    asanSetInitialBufferSizeTo(other.size());
     808
    747809    if (begin())
    748810        TypeOperations::uninitializedCopy(other.begin(), other.end(), begin());
     
    754816    : Base(other.capacity(), other.size())
    755817{
     818    asanSetInitialBufferSizeTo(other.size());
     819
    756820    if (begin())
    757821        TypeOperations::uninitializedCopy(other.begin(), other.end(), begin());
     
    771835        ASSERT(begin());
    772836    }
    773    
     837
     838    asanBufferSizeWillChangeTo(other.size());
     839
    774840    std::copy(other.begin(), other.begin() + size(), begin());
    775841    TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end());
     
    798864    }
    799865   
     866    asanBufferSizeWillChangeTo(other.size());
     867
    800868    std::copy(other.begin(), other.begin() + size(), begin());
    801869    TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end());
     
    858926        ASSERT(begin());
    859927    }
    860    
     928
     929    asanBufferSizeWillChangeTo(newSize);
     930
    861931    std::fill(begin(), end(), val);
    862932    TypeOperations::uninitializedFill(end(), begin() + newSize, val);
     
    920990inline void Vector<T, inlineCapacity, OverflowHandler>::resize(size_t size)
    921991{
    922     if (size <= m_size)
     992    if (size <= m_size) {
    923993        TypeOperations::destruct(begin() + size, end());
    924     else {
     994        asanBufferSizeWillChangeTo(size);
     995    } else {
    925996        if (size > capacity())
    926997            expandCapacity(size);
     998        asanBufferSizeWillChangeTo(size);
    927999        if (begin())
    9281000            TypeOperations::initialize(end(), begin() + size);
     
    9441016    ASSERT(size <= m_size);
    9451017    TypeOperations::destruct(begin() + size, end());
     1018    asanBufferSizeWillChangeTo(size);
    9461019    m_size = size;
    9471020}
     
    9531026    if (size > capacity())
    9541027        expandCapacity(size);
     1028    asanBufferSizeWillChangeTo(size);
    9551029    if (begin())
    9561030        TypeOperations::initialize(end(), begin() + size);
    9571031    m_size = size;
     1032}
     1033
     1034template<typename T, size_t inlineCapacity, typename OverflowHandler>
     1035inline void Vector<T, inlineCapacity, OverflowHandler>::asanSetInitialBufferSizeTo(size_t size)
     1036{
     1037#if ASAN_ENABLED
     1038    if (!buffer())
     1039        return;
     1040
     1041    // This function resticts buffer access to only elements in [begin(), end()) range, making ASan detect an error
     1042    // when accessing elements in [end(), endOfBuffer()) range.
     1043    // A newly allocated buffer can be accessed without restrictions, so "old_mid" argument equals "end" argument.
     1044    __sanitizer_annotate_contiguous_container(buffer(), endOfBuffer(), endOfBuffer(), buffer() + size);
     1045#else
     1046    UNUSED_PARAM(size);
     1047#endif
     1048}
     1049
     1050template<typename T, size_t inlineCapacity, typename OverflowHandler>
     1051inline void Vector<T, inlineCapacity, OverflowHandler>::asanSetBufferSizeToFullCapacity()
     1052{
     1053#if ASAN_ENABLED
     1054    if (!buffer())
     1055        return;
     1056
     1057    // ASan requires that the annotation is returned to its initial state before deallocation.
     1058    __sanitizer_annotate_contiguous_container(buffer(), endOfBuffer(), buffer() + size(), endOfBuffer());
     1059#endif
     1060}
     1061
     1062template<typename T, size_t inlineCapacity, typename OverflowHandler>
     1063inline void Vector<T, inlineCapacity, OverflowHandler>::asanBufferSizeWillChangeTo(size_t newSize)
     1064{
     1065#if ASAN_ENABLED
     1066    if (!buffer())
     1067        return;
     1068
     1069    // Change allowed range.
     1070    __sanitizer_annotate_contiguous_container(buffer(), endOfBuffer(), buffer() + size(), buffer() + newSize);
     1071#else
     1072    UNUSED_PARAM(newSize);
     1073#endif
    9581074}
    9591075
     
    9651081    T* oldBuffer = begin();
    9661082    T* oldEnd = end();
     1083
     1084    asanSetBufferSizeToFullCapacity();
     1085
    9671086    Base::allocateBuffer(newCapacity);
    9681087    ASSERT(begin());
     1088
     1089    asanSetInitialBufferSizeTo(size());
     1090
    9691091    TypeOperations::move(oldBuffer, oldEnd, begin());
    9701092    Base::deallocateBuffer(oldBuffer);
     
    9781100    T* oldBuffer = begin();
    9791101    T* oldEnd = end();
    980     if (!Base::tryAllocateBuffer(newCapacity))
     1102
     1103    asanSetBufferSizeToFullCapacity();
     1104
     1105    if (!Base::tryAllocateBuffer(newCapacity)) {
     1106        asanSetInitialBufferSizeTo(size());
    9811107        return false;
     1108    }
    9821109    ASSERT(begin());
     1110
     1111    asanSetInitialBufferSizeTo(size());
     1112
    9831113    TypeOperations::move(oldBuffer, oldEnd, begin());
    9841114    Base::deallocateBuffer(oldBuffer);
     
    10041134        shrink(newCapacity);
    10051135
     1136    asanSetBufferSizeToFullCapacity();
     1137
    10061138    T* oldBuffer = begin();
    10071139    if (newCapacity > 0) {
    10081140        if (Base::shouldReallocateBuffer(newCapacity)) {
    10091141            Base::reallocateBuffer(newCapacity);
     1142            asanSetInitialBufferSizeTo(size());
    10101143            return;
    10111144        }
     
    10191152    Base::deallocateBuffer(oldBuffer);
    10201153    Base::restoreInlineBufferIfNeeded();
     1154
     1155    asanSetInitialBufferSizeTo(size());
    10211156}
    10221157
     
    10341169    if (newSize < m_size)
    10351170        CRASH();
     1171    asanBufferSizeWillChangeTo(newSize);
    10361172    T* dest = end();
    10371173    VectorCopier<std::is_trivial<T>::value, U>::uninitializedCopy(data, &data[dataSize], dest);
     
    10511187    if (newSize < m_size)
    10521188        return false;
     1189    asanBufferSizeWillChangeTo(newSize);
    10531190    T* dest = end();
    10541191    VectorCopier<std::is_trivial<T>::value, U>::uninitializedCopy(data, &data[dataSize], dest);
     
    10611198{
    10621199    if (size() != capacity()) {
     1200        asanBufferSizeWillChangeTo(m_size + 1);
    10631201        new (NotNull, end()) T(std::forward<U>(value));
    10641202        ++m_size;
     
    10781216    ASSERT(begin());
    10791217
     1218    asanBufferSizeWillChangeTo(m_size + 1);
    10801219    new (NotNull, end()) T(std::forward<U>(*ptr));
    10811220    ++m_size;
     
    10891228{
    10901229    ASSERT(size() < capacity());
     1230
     1231    asanBufferSizeWillChangeTo(m_size + 1);
    10911232
    10921233    auto ptr = std::addressof(value);
     
    11121253    if (newSize < m_size)
    11131254        CRASH();
     1255    asanBufferSizeWillChangeTo(newSize);
    11141256    T* spot = begin() + position;
    11151257    TypeOperations::moveOverlapping(spot, end(), spot + dataSize);
     
    11291271    }
    11301272
     1273    asanBufferSizeWillChangeTo(m_size + 1);
     1274
    11311275    T* spot = begin() + position;
    11321276    TypeOperations::moveOverlapping(spot, end(), spot + 1);
     
    11481292    spot->~T();
    11491293    TypeOperations::moveOverlapping(spot + 1, end(), spot);
     1294    asanBufferSizeWillChangeTo(m_size - 1);
    11501295    --m_size;
    11511296}
     
    11601305    TypeOperations::destruct(beginSpot, endSpot);
    11611306    TypeOperations::moveOverlapping(endSpot, end(), beginSpot);
     1307    asanBufferSizeWillChangeTo(m_size - length);
    11621308    m_size -= length;
    11631309}
     
    11731319inline MallocPtr<T> Vector<T, inlineCapacity, OverflowHandler>::releaseBuffer()
    11741320{
     1321    // FIXME: Find a way to preserve annotations on the returned buffer.
     1322    // ASan requires that all annotations are removed before deallocation,
     1323    // and MallocPtr doesn't implement that.
     1324    asanSetBufferSizeToFullCapacity();
     1325
    11751326    auto buffer = Base::releaseBuffer();
    11761327    if (inlineCapacity && !buffer && m_size) {
     
    11831334    }
    11841335    m_size = 0;
     1336    // FIXME: Should we call Base::restoreInlineBufferIfNeeded() here?
    11851337    return buffer;
    11861338}
Note: See TracChangeset for help on using the changeset viewer.