Changeset 178722 in webkit
- Timestamp:
- Jan 20, 2015, 10:27:48 AM (10 years ago)
- Location:
- trunk/Source/WTF
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WTF/ChangeLog
r178719 r178722 1 2015-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 1 39 2015-01-20 Csaba Osztrogonác <ossy@webkit.org> 2 40 -
trunk/Source/WTF/wtf/Compiler.h
r178104 r178722 140 140 #define ASAN_ENABLED __has_feature(address_sanitizer) 141 141 #else 142 #define ASAN_ENABLED false142 #define ASAN_ENABLED 0 143 143 #endif 144 144 -
trunk/Source/WTF/wtf/SizeLimits.cpp
r177995 r178722 55 55 }; 56 56 #endif 57 58 static_assert(sizeof(OwnPtr<int>) == sizeof(int*), "OwnPtr should stay small!"); 59 static_assert(sizeof(PassRefPtr<RefCounted<int>>) == sizeof(int*), "PassRefPtr should stay small!"); 60 static_assert(sizeof(RefCounted<int>) == sizeof(SameSizeAsRefCounted), "RefCounted should stay small!"); 61 static_assert(sizeof(RefPtr<RefCounted<int>>) == sizeof(int*), "RefPtr should stay small!"); 62 63 #if !ASAN_ENABLED 57 64 template<typename T, unsigned inlineCapacity = 0> 58 65 struct SameSizeAsVectorWithInlineCapacity; … … 71 78 }; 72 79 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!");77 80 static_assert(sizeof(Vector<int>) == sizeof(SameSizeAsVectorWithInlineCapacity<int>), "Vector should stay small!"); 78 81 static_assert(sizeof(Vector<int, 1>) == sizeof(SameSizeAsVectorWithInlineCapacity<int, 1>), "Vector should stay small!"); 79 82 static_assert(sizeof(Vector<int, 2>) == sizeof(SameSizeAsVectorWithInlineCapacity<int, 2>), "Vector should stay small!"); 80 83 static_assert(sizeof(Vector<int, 3>) == sizeof(SameSizeAsVectorWithInlineCapacity<int, 3>), "Vector should stay small!"); 84 #endif 81 85 } -
trunk/Source/WTF/wtf/Vector.h
r177316 r178722 35 35 #include <wtf/VectorTraits.h> 36 36 37 #if ASAN_ENABLED 38 extern "C" void __sanitizer_annotate_contiguous_container(const void* begin, const void* end, const void* old_mid, const void* new_mid); 39 #endif 40 37 41 namespace WTF { 38 42 … … 381 385 382 386 void restoreInlineBufferIfNeeded() { } 387 388 #if ASAN_ENABLED 389 void* endOfBuffer() 390 { 391 return buffer() + capacity(); 392 } 393 #endif 383 394 384 395 using Base::allocateBuffer; … … 493 504 } 494 505 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 495 519 using Base::buffer; 496 520 using Base::capacity; … … 540 564 const T* inlineBuffer() const { return reinterpret_cast_ptr<const T*>(m_inlineBuffer); } 541 565 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 542 573 typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type m_inlineBuffer[inlineCapacity]; 574 #endif 543 575 }; 544 576 … … 573 605 : Base(size, size) 574 606 { 607 asanSetInitialBufferSizeTo(size); 608 575 609 if (begin()) 576 610 TypeOperations::initialize(begin(), end()); … … 580 614 : Base(size, size) 581 615 { 616 asanSetInitialBufferSizeTo(size); 617 582 618 if (begin()) 583 619 TypeOperations::uninitializedFill(begin(), end(), val); … … 587 623 { 588 624 reserveInitialCapacity(initializerList.size()); 625 626 asanSetInitialBufferSizeTo(initializerList.size()); 627 589 628 for (const auto& element : initializerList) 590 629 uncheckedAppend(element); … … 595 634 if (m_size) 596 635 shrink(0); 636 637 asanSetBufferSizeToFullCapacity(); 597 638 } 598 639 … … 712 753 void swap(Vector<T, inlineCapacity, OverflowHandler>& other) 713 754 { 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 714 764 Base::swap(other, m_size, other.m_size); 715 765 std::swap(m_size, other.m_size); 766 767 asanSetInitialBufferSizeTo(m_size); 768 other.asanSetInitialBufferSizeTo(other.m_size); 716 769 } 717 770 … … 727 780 template<typename U> U* expandCapacity(size_t newMinCapacity, U*); 728 781 template<typename U> void appendSlowCase(U&&); 782 783 void asanSetInitialBufferSizeTo(size_t); 784 void asanSetBufferSizeToFullCapacity(); 785 void asanBufferSizeWillChangeTo(size_t); 729 786 730 787 using Base::m_size; … … 739 796 using Base::restoreInlineBufferIfNeeded; 740 797 using Base::releaseBuffer; 798 #if ASAN_ENABLED 799 using Base::endOfBuffer; 800 #endif 741 801 }; 742 802 … … 745 805 : Base(other.capacity(), other.size()) 746 806 { 807 asanSetInitialBufferSizeTo(other.size()); 808 747 809 if (begin()) 748 810 TypeOperations::uninitializedCopy(other.begin(), other.end(), begin()); … … 754 816 : Base(other.capacity(), other.size()) 755 817 { 818 asanSetInitialBufferSizeTo(other.size()); 819 756 820 if (begin()) 757 821 TypeOperations::uninitializedCopy(other.begin(), other.end(), begin()); … … 771 835 ASSERT(begin()); 772 836 } 773 837 838 asanBufferSizeWillChangeTo(other.size()); 839 774 840 std::copy(other.begin(), other.begin() + size(), begin()); 775 841 TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end()); … … 798 864 } 799 865 866 asanBufferSizeWillChangeTo(other.size()); 867 800 868 std::copy(other.begin(), other.begin() + size(), begin()); 801 869 TypeOperations::uninitializedCopy(other.begin() + size(), other.end(), end()); … … 858 926 ASSERT(begin()); 859 927 } 860 928 929 asanBufferSizeWillChangeTo(newSize); 930 861 931 std::fill(begin(), end(), val); 862 932 TypeOperations::uninitializedFill(end(), begin() + newSize, val); … … 920 990 inline void Vector<T, inlineCapacity, OverflowHandler>::resize(size_t size) 921 991 { 922 if (size <= m_size) 992 if (size <= m_size) { 923 993 TypeOperations::destruct(begin() + size, end()); 924 else { 994 asanBufferSizeWillChangeTo(size); 995 } else { 925 996 if (size > capacity()) 926 997 expandCapacity(size); 998 asanBufferSizeWillChangeTo(size); 927 999 if (begin()) 928 1000 TypeOperations::initialize(end(), begin() + size); … … 944 1016 ASSERT(size <= m_size); 945 1017 TypeOperations::destruct(begin() + size, end()); 1018 asanBufferSizeWillChangeTo(size); 946 1019 m_size = size; 947 1020 } … … 953 1026 if (size > capacity()) 954 1027 expandCapacity(size); 1028 asanBufferSizeWillChangeTo(size); 955 1029 if (begin()) 956 1030 TypeOperations::initialize(end(), begin() + size); 957 1031 m_size = size; 1032 } 1033 1034 template<typename T, size_t inlineCapacity, typename OverflowHandler> 1035 inline 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 1050 template<typename T, size_t inlineCapacity, typename OverflowHandler> 1051 inline 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 1062 template<typename T, size_t inlineCapacity, typename OverflowHandler> 1063 inline 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 958 1074 } 959 1075 … … 965 1081 T* oldBuffer = begin(); 966 1082 T* oldEnd = end(); 1083 1084 asanSetBufferSizeToFullCapacity(); 1085 967 1086 Base::allocateBuffer(newCapacity); 968 1087 ASSERT(begin()); 1088 1089 asanSetInitialBufferSizeTo(size()); 1090 969 1091 TypeOperations::move(oldBuffer, oldEnd, begin()); 970 1092 Base::deallocateBuffer(oldBuffer); … … 978 1100 T* oldBuffer = begin(); 979 1101 T* oldEnd = end(); 980 if (!Base::tryAllocateBuffer(newCapacity)) 1102 1103 asanSetBufferSizeToFullCapacity(); 1104 1105 if (!Base::tryAllocateBuffer(newCapacity)) { 1106 asanSetInitialBufferSizeTo(size()); 981 1107 return false; 1108 } 982 1109 ASSERT(begin()); 1110 1111 asanSetInitialBufferSizeTo(size()); 1112 983 1113 TypeOperations::move(oldBuffer, oldEnd, begin()); 984 1114 Base::deallocateBuffer(oldBuffer); … … 1004 1134 shrink(newCapacity); 1005 1135 1136 asanSetBufferSizeToFullCapacity(); 1137 1006 1138 T* oldBuffer = begin(); 1007 1139 if (newCapacity > 0) { 1008 1140 if (Base::shouldReallocateBuffer(newCapacity)) { 1009 1141 Base::reallocateBuffer(newCapacity); 1142 asanSetInitialBufferSizeTo(size()); 1010 1143 return; 1011 1144 } … … 1019 1152 Base::deallocateBuffer(oldBuffer); 1020 1153 Base::restoreInlineBufferIfNeeded(); 1154 1155 asanSetInitialBufferSizeTo(size()); 1021 1156 } 1022 1157 … … 1034 1169 if (newSize < m_size) 1035 1170 CRASH(); 1171 asanBufferSizeWillChangeTo(newSize); 1036 1172 T* dest = end(); 1037 1173 VectorCopier<std::is_trivial<T>::value, U>::uninitializedCopy(data, &data[dataSize], dest); … … 1051 1187 if (newSize < m_size) 1052 1188 return false; 1189 asanBufferSizeWillChangeTo(newSize); 1053 1190 T* dest = end(); 1054 1191 VectorCopier<std::is_trivial<T>::value, U>::uninitializedCopy(data, &data[dataSize], dest); … … 1061 1198 { 1062 1199 if (size() != capacity()) { 1200 asanBufferSizeWillChangeTo(m_size + 1); 1063 1201 new (NotNull, end()) T(std::forward<U>(value)); 1064 1202 ++m_size; … … 1078 1216 ASSERT(begin()); 1079 1217 1218 asanBufferSizeWillChangeTo(m_size + 1); 1080 1219 new (NotNull, end()) T(std::forward<U>(*ptr)); 1081 1220 ++m_size; … … 1089 1228 { 1090 1229 ASSERT(size() < capacity()); 1230 1231 asanBufferSizeWillChangeTo(m_size + 1); 1091 1232 1092 1233 auto ptr = std::addressof(value); … … 1112 1253 if (newSize < m_size) 1113 1254 CRASH(); 1255 asanBufferSizeWillChangeTo(newSize); 1114 1256 T* spot = begin() + position; 1115 1257 TypeOperations::moveOverlapping(spot, end(), spot + dataSize); … … 1129 1271 } 1130 1272 1273 asanBufferSizeWillChangeTo(m_size + 1); 1274 1131 1275 T* spot = begin() + position; 1132 1276 TypeOperations::moveOverlapping(spot, end(), spot + 1); … … 1148 1292 spot->~T(); 1149 1293 TypeOperations::moveOverlapping(spot + 1, end(), spot); 1294 asanBufferSizeWillChangeTo(m_size - 1); 1150 1295 --m_size; 1151 1296 } … … 1160 1305 TypeOperations::destruct(beginSpot, endSpot); 1161 1306 TypeOperations::moveOverlapping(endSpot, end(), beginSpot); 1307 asanBufferSizeWillChangeTo(m_size - length); 1162 1308 m_size -= length; 1163 1309 } … … 1173 1319 inline MallocPtr<T> Vector<T, inlineCapacity, OverflowHandler>::releaseBuffer() 1174 1320 { 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 1175 1326 auto buffer = Base::releaseBuffer(); 1176 1327 if (inlineCapacity && !buffer && m_size) { … … 1183 1334 } 1184 1335 m_size = 0; 1336 // FIXME: Should we call Base::restoreInlineBufferIfNeeded() here? 1185 1337 return buffer; 1186 1338 }
Note:
See TracChangeset
for help on using the changeset viewer.