Changeset 271757 in webkit
- Timestamp:
- Jan 22, 2021 12:40:21 PM (3 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r271751 r271757 1 2021-01-21 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 DisplayList::Replayer should stop replay and inform clients after encountering an invalid item 4 https://bugs.webkit.org/show_bug.cgi?id=220867 5 6 Reviewed by Chris Dumez. 7 8 Make the `DisplayList` item iterator emit `Optional<ItemHandle>` instead of just `ItemHandle`; in the case of 9 client decoding or item validation failures (see #220710), this item handle will be `WTF::nullopt`. The display 10 list replayer will then handle this by halting replay with `StopReplayReason::InvalidItem`. 11 12 This refactoring will eventually enable `RemoteRenderingBackend` (in the GPU process) to terminate the web 13 content process when we fail to decode a display list item during playback (or encounter an invalid inline 14 item). 15 16 Test: DisplayListTests.InlineItemValidationFailure 17 DisplayListTests.OutOfLineItemDecodingFailure 18 19 * platform/graphics/displaylists/DisplayList.cpp: 20 (WebCore::DisplayList::DisplayList::asText const): 21 (WebCore::DisplayList::DisplayList::dump const): 22 (WebCore::DisplayList::DisplayList::iterator::atEnd const): 23 (WebCore::DisplayList::DisplayList::iterator::updateCurrentItem): 24 25 Add an `m_isValid` flag. This flag is set to `true` initially, and is only set to `false` when we encounter an 26 item that is either invalid or unable to be decoded. Additionally, remove release assertions and the FIXMEs 27 regarding handling item decoding failures. 28 29 * platform/graphics/displaylists/DisplayList.h: 30 (WebCore::DisplayList::DisplayList::iterator::operator* const): 31 32 If the `m_isValid` flag above is set, return `WTF::nullopt` for the item handle. 33 34 * platform/graphics/displaylists/DisplayListReplayer.cpp: 35 (WebCore::DisplayList::Replayer::replay): 36 * platform/graphics/displaylists/DisplayListReplayer.h: 37 38 Rename `DecodingFailure` to `InvalidItem`, since it now applies to both items that are invalid (e.g. contain 39 identifier values of 0 when they shouldn't) as well as items that fail decoding (which, in the case of the GPU 40 process, corresponds to IPC decoding failures). 41 1 42 2021-01-22 Chris Dumez <cdumez@apple.com> 2 43 -
trunk/Source/WebCore/platform/graphics/displaylists/DisplayList.cpp
r271741 r271757 116 116 TextStream stream(TextStream::LineMode::MultipleLine, TextStream::Formatting::SVGStyleRect); 117 117 for (auto [item, extent, itemSizeInBuffer] : *this) { 118 if (!shouldDumpForFlags(flags, item))118 if (!shouldDumpForFlags(flags, *item)) 119 119 continue; 120 120 121 121 TextStream::GroupScope group(stream); 122 122 stream << item; 123 if (item .isDrawingItem())123 if (item->isDrawingItem()) 124 124 stream << " extent " << extent; 125 125 } … … 135 135 TextStream::GroupScope group(ts); 136 136 ts << item; 137 if (item .isDrawingItem())137 if (item->isDrawingItem()) 138 138 ts << " extent " << extent; 139 139 } … … 323 323 bool DisplayList::iterator::atEnd() const 324 324 { 325 if (m_displayList.isEmpty() )325 if (m_displayList.isEmpty() || !m_isValid) 326 326 return true; 327 327 … … 353 353 auto* startOfData = m_cursor + 2 * sizeof(uint64_t); 354 354 auto decodedItemHandle = client->decodeItem(startOfData, dataLength, itemType, m_currentBufferForItem); 355 if (!decodedItemHandle) { 356 // FIXME: Instead of crashing, this needs to fail gracefully and inform the caller. 357 // For the time being, this assertion makes bugs in item buffer encoding logic easier 358 // to catch by avoiding mysterious out-of-bounds reads and incorrectly aligned items 359 // down the line. 360 RELEASE_ASSERT_NOT_REACHED(); 361 } 355 if (UNLIKELY(!decodedItemHandle)) 356 m_isValid = false; 357 362 358 m_currentBufferForItem[0] = static_cast<uint8_t>(itemType); 363 359 m_currentItemSizeInBuffer = 2 * sizeof(uint64_t) + roundUpToMultipleOf(alignof(uint64_t), dataLength); 364 360 } else { 365 if (!ItemHandle { m_cursor }.safeCopy({ m_currentBufferForItem })) { 366 // FIXME: Instead of crashing, this needs to fail gracefully and inform the caller. 367 RELEASE_ASSERT_NOT_REACHED(); 368 } 361 if (UNLIKELY(!ItemHandle { m_cursor }.safeCopy({ m_currentBufferForItem }))) 362 m_isValid = false; 363 369 364 m_currentItemSizeInBuffer = paddedSizeOfTypeAndItem; 370 365 } -
trunk/Source/WebCore/platform/graphics/displaylists/DisplayList.h
r270796 r271757 119 119 120 120 struct Value { 121 ItemHandleitem;121 Optional<ItemHandle> item; 122 122 Optional<FloatRect> extent; 123 123 size_t itemSizeInBuffer { 0 }; … … 127 127 { 128 128 return { 129 ItemHandle { m_currentBufferForItem },129 m_isValid ? makeOptional(ItemHandle { m_currentBufferForItem }) : WTF::nullopt, 130 130 m_currentExtent, 131 m_currentItemSizeInBuffer 131 m_currentItemSizeInBuffer, 132 132 }; 133 133 } … … 153 153 Optional<FloatRect> m_currentExtent; 154 154 size_t m_currentItemSizeInBuffer { 0 }; 155 bool m_isValid { true }; 155 156 }; 156 157 -
trunk/Source/WebCore/platform/graphics/displaylists/DisplayListReplayer.cpp
r270725 r271757 142 142 } 143 143 144 LOG_WITH_STREAM(DisplayLists, stream << "applying " << i++ << " " << item); 145 146 if (item.is<MetaCommandChangeDestinationImageBuffer>()) { 147 result.numberOfBytesRead += itemSizeInBuffer; 148 result.reasonForStopping = StopReplayReason::ChangeDestinationImageBuffer; 149 result.nextDestinationImageBuffer = item.get<MetaCommandChangeDestinationImageBuffer>().identifier(); 144 if (!item) { 145 result.reasonForStopping = StopReplayReason::InvalidItem; 150 146 break; 151 147 } 152 148 153 if (auto [reasonForStopping, missingCachedResourceIdentifier] = applyItem(item); reasonForStopping) { 149 LOG_WITH_STREAM(DisplayLists, stream << "applying " << i++ << " " << item); 150 151 if (item->is<MetaCommandChangeDestinationImageBuffer>()) { 152 result.numberOfBytesRead += itemSizeInBuffer; 153 result.reasonForStopping = StopReplayReason::ChangeDestinationImageBuffer; 154 result.nextDestinationImageBuffer = item->get<MetaCommandChangeDestinationImageBuffer>().identifier(); 155 break; 156 } 157 158 if (auto [reasonForStopping, missingCachedResourceIdentifier] = applyItem(*item); reasonForStopping) { 154 159 result.reasonForStopping = *reasonForStopping; 155 160 result.missingCachedResourceIdentifier = WTFMove(missingCachedResourceIdentifier); … … 160 165 161 166 if (UNLIKELY(trackReplayList)) { 162 replayList->append( item);163 if (item .isDrawingItem())167 replayList->append(*item); 168 if (item->isDrawingItem()) 164 169 replayList->addDrawingItemExtent(WTFMove(extent)); 165 170 } -
trunk/Source/WebCore/platform/graphics/displaylists/DisplayListReplayer.h
r270725 r271757 43 43 MissingCachedResource, 44 44 ChangeDestinationImageBuffer, 45 DecodingFailure // FIXME: Propagate decoding errors to display list replay clients through this enum as well.45 InvalidItem 46 46 }; 47 47 -
trunk/Tools/ChangeLog
r271755 r271757 1 2021-01-21 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 DisplayList::Replayer should stop replay and inform clients after encountering an invalid item 4 https://bugs.webkit.org/show_bug.cgi?id=220867 5 6 Reviewed by Chris Dumez. 7 8 * TestWebKitAPI/Tests/WebCore/DisplayListTests.cpp: 9 10 Adjust a few API tests, since the item handle in the `DisplayList` iterator is now optional. 11 12 * TestWebKitAPI/Tests/WebCore/cg/DisplayListTestsCG.cpp: 13 14 Add a couple of new API tests to exercise display list item decoding and validation failures. 15 1 16 2021-01-22 Kimmo Kinnunen <kkinnunen@apple.com> 2 17 -
trunk/Tools/TestWebKitAPI/Tests/WebCore/DisplayListTests.cpp
r270478 r271757 80 80 bool observedUnexpectedItem = false; 81 81 for (auto [handle, extent, size] : list) { 82 switch (handle .type()) {82 switch (handle->type()) { 83 83 case ItemType::SetStrokeThickness: { 84 EXPECT_FALSE(handle .isDrawingItem());85 EXPECT_TRUE(handle .is<SetStrokeThickness>());86 auto& item = handle .get<SetStrokeThickness>();84 EXPECT_FALSE(handle->isDrawingItem()); 85 EXPECT_TRUE(handle->is<SetStrokeThickness>()); 86 auto& item = handle->get<SetStrokeThickness>(); 87 87 EXPECT_EQ(item.thickness(), 1.5); 88 88 break; 89 89 } 90 90 case ItemType::FillPath: { 91 EXPECT_TRUE(handle .isDrawingItem());92 EXPECT_TRUE(handle .is<FillPath>());93 auto& item = handle .get<FillPath>();91 EXPECT_TRUE(handle->isDrawingItem()); 92 EXPECT_TRUE(handle->is<FillPath>()); 93 auto& item = handle->get<FillPath>(); 94 94 EXPECT_EQ(item.path().platformPath(), path.platformPath()); 95 95 break; 96 96 } 97 97 case ItemType::FillRectWithGradient: { 98 EXPECT_TRUE(handle .isDrawingItem());99 EXPECT_TRUE(handle .is<FillRectWithGradient>());100 auto& item = handle .get<FillRectWithGradient>();98 EXPECT_TRUE(handle->isDrawingItem()); 99 EXPECT_TRUE(handle->is<FillRectWithGradient>()); 100 auto& item = handle->get<FillRectWithGradient>(); 101 101 EXPECT_EQ(item.rect(), FloatRect(1., 1., 10., 10.)); 102 102 EXPECT_EQ(&item.gradient(), gradient.ptr()); … … 104 104 } 105 105 case ItemType::SetInlineFillColor: { 106 EXPECT_FALSE(handle .isDrawingItem());107 EXPECT_TRUE(handle .is<SetInlineFillColor>());108 auto& item = handle .get<SetInlineFillColor>();106 EXPECT_FALSE(handle->isDrawingItem()); 107 EXPECT_TRUE(handle->is<SetInlineFillColor>()); 108 auto& item = handle->get<SetInlineFillColor>(); 109 109 EXPECT_EQ(item.color(), Color::red); 110 110 break; … … 112 112 #if ENABLE(INLINE_PATH_DATA) 113 113 case ItemType::StrokeInlinePath: { 114 EXPECT_TRUE(handle .isDrawingItem());115 EXPECT_TRUE(handle .is<StrokeInlinePath>());116 auto& item = handle .get<StrokeInlinePath>();114 EXPECT_TRUE(handle->isDrawingItem()); 115 EXPECT_TRUE(handle->is<StrokeInlinePath>()); 116 auto& item = handle->get<StrokeInlinePath>(); 117 117 const auto path = item.path(); 118 118 auto& line = path.inlineData<LineData>(); … … 149 149 150 150 for (auto [handle, extent, size] : list) { 151 EXPECT_EQ(handle .type(), ItemType::FillRectWithColor);152 EXPECT_TRUE(handle .is<FillRectWithColor>());153 154 auto& item = handle .get<FillRectWithColor>();151 EXPECT_EQ(handle->type(), ItemType::FillRectWithColor); 152 EXPECT_TRUE(handle->is<FillRectWithColor>()); 153 154 auto& item = handle->get<FillRectWithColor>(); 155 155 EXPECT_EQ(item.color().asInline(), Color::black); 156 156 EXPECT_EQ(item.rect(), FloatRect(0, 0, 100, 100)); … … 227 227 Vector<ItemType> itemTypes; 228 228 for (auto [handle, extent, size] : shallowCopy) 229 itemTypes.append(handle .type());229 itemTypes.append(handle->type()); 230 230 231 231 EXPECT_FALSE(shallowCopy.isEmpty()); -
trunk/Tools/TestWebKitAPI/Tests/WebCore/cg/DisplayListTestsCG.cpp
r270556 r271757 38 38 using namespace DisplayList; 39 39 40 constexpr size_t globalItemBufferCapacity = 1 << 12; 41 static uint8_t globalItemBuffer[globalItemBufferCapacity]; 42 constexpr CGFloat contextWidth = 100; 43 constexpr CGFloat contextHeight = 100; 44 40 45 TEST(DisplayListTests, ReplayWithMissingResource) 41 46 { 42 constexpr CGFloat contextWidth = 100;43 constexpr CGFloat contextHeight = 100;44 45 47 FloatRect contextBounds { 0, 0, contextWidth, contextHeight }; 46 48 … … 80 82 } 81 83 84 TEST(DisplayListTests, OutOfLineItemDecodingFailure) 85 { 86 static ItemBufferIdentifier globalBufferIdentifier = ItemBufferIdentifier::generate(); 87 88 class ReadingClient : public ItemBufferReadingClient { 89 private: 90 Optional<ItemHandle> WARN_UNUSED_RETURN decodeItem(const uint8_t*, size_t, ItemType type, uint8_t*) final 91 { 92 EXPECT_EQ(type, ItemType::FillPath); 93 return WTF::nullopt; 94 } 95 }; 96 97 class WritingClient : public ItemBufferWritingClient { 98 private: 99 ItemBufferHandle createItemBuffer(size_t capacity) final 100 { 101 EXPECT_LT(capacity, globalItemBufferCapacity); 102 return { globalBufferIdentifier, globalItemBuffer, globalItemBufferCapacity }; 103 } 104 105 RefPtr<SharedBuffer> encodeItem(ItemHandle) const final { return SharedBuffer::create(); } 106 void didAppendData(const ItemBufferHandle&, size_t, DidChangeItemBuffer) final { } 107 }; 108 109 FloatRect contextBounds { 0, 0, contextWidth, contextHeight }; 110 111 auto colorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); 112 auto cgContext = adoptCF(CGBitmapContextCreate(nullptr, contextWidth, contextHeight, 8, 4 * contextWidth, colorSpace.get(), kCGImageAlphaPremultipliedLast)); 113 GraphicsContext context { cgContext.get() }; 114 115 DisplayList list; 116 WritingClient writer; 117 list.setItemBufferClient(&writer); 118 119 Path path; 120 path.moveTo({ 10., 10. }); 121 path.addLineTo({ 50., 50. }); 122 path.addLineTo({ 10., 10. }); 123 list.append<SetInlineStrokeColor>(Color::blue); 124 list.append<FillPath>(WTFMove(path)); 125 126 DisplayList shallowCopy {{ ItemBufferHandle { globalBufferIdentifier, globalItemBuffer, list.sizeInBytes() } }}; 127 ReadingClient reader; 128 shallowCopy.setItemBufferClient(&reader); 129 130 Replayer replayer { context, list }; 131 auto result = replayer.replay(); 132 EXPECT_GT(result.numberOfBytesRead, 0U); 133 EXPECT_EQ(result.nextDestinationImageBuffer, WTF::nullopt); 134 EXPECT_EQ(result.missingCachedResourceIdentifier, WTF::nullopt); 135 EXPECT_EQ(result.reasonForStopping, StopReplayReason::InvalidItem); 136 } 137 138 TEST(DisplayListTests, InlineItemValidationFailure) 139 { 140 FloatRect contextBounds { 0, 0, contextWidth, contextHeight }; 141 142 auto colorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); 143 auto cgContext = adoptCF(CGBitmapContextCreate(nullptr, contextWidth, contextHeight, 8, 4 * contextWidth, colorSpace.get(), kCGImageAlphaPremultipliedLast)); 144 GraphicsContext context { cgContext.get() }; 145 146 DisplayList list; 147 list.append<FlushContext>(FlushIdentifier { }); 148 149 Replayer replayer { context, list }; 150 auto result = replayer.replay(); 151 EXPECT_EQ(result.numberOfBytesRead, 0U); 152 EXPECT_EQ(result.nextDestinationImageBuffer, WTF::nullopt); 153 EXPECT_EQ(result.missingCachedResourceIdentifier, WTF::nullopt); 154 EXPECT_EQ(result.reasonForStopping, StopReplayReason::InvalidItem); 155 } 156 82 157 } // namespace TestWebKitAPI 83 158
Note: See TracChangeset
for help on using the changeset viewer.