| // Copyright 2018 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <string.h> |
| |
| #include <fuzzer/FuzzedDataProvider.h> |
| |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" |
| #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" |
| #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" |
| #include "components/viz/service/hit_test/hit_test_aggregator.h" |
| #include "components/viz/service/hit_test/hit_test_manager.h" |
| #include "components/viz/test/compositor_frame_helpers.h" |
| #include "components/viz/test/test_latest_local_surface_id_lookup_delegate.h" |
| #include "ui/gfx/geometry/test/fuzzer_util.h" |
| |
| namespace { |
| |
| constexpr uint32_t kMaxDepthAllowed = 255; |
| |
| uint32_t GetNextUInt32NonZero(FuzzedDataProvider* fuzz) { |
| return fuzz->ConsumeIntegralInRange<uint32_t>( |
| 1, std::numeric_limits<uint32_t>::max()); |
| } |
| |
| void SubmitHitTestRegionList( |
| FuzzedDataProvider* fuzz, |
| viz::TestLatestLocalSurfaceIdLookupDelegate* delegate, |
| viz::FrameSinkManagerImpl* frame_sink_manager, |
| const viz::SurfaceId& surface_id, |
| bool support_is_root, |
| const uint32_t depth); |
| |
| void AddHitTestRegion(FuzzedDataProvider* fuzz, |
| std::vector<viz::HitTestRegion>* regions, |
| uint32_t child_count, |
| viz::TestLatestLocalSurfaceIdLookupDelegate* delegate, |
| viz::FrameSinkManagerImpl* frame_sink_manager, |
| const viz::SurfaceId& surface_id, |
| const uint32_t depth) { |
| if (!child_count || depth > kMaxDepthAllowed) |
| return; |
| |
| // If there's not enough space left for a HitTestRegion, then skip. |
| if (fuzz->remaining_bytes() < sizeof(viz::HitTestRegion)) |
| return; |
| |
| viz::HitTestRegion hit_test_region; |
| hit_test_region.flags = fuzz->ConsumeIntegral<uint32_t>(); |
| hit_test_region.async_hit_test_reasons = fuzz->ConsumeIntegral<uint32_t>(); |
| if (fuzz->ConsumeBool()) |
| hit_test_region.flags |= viz::HitTestRegionFlags::kHitTestChildSurface; |
| hit_test_region.frame_sink_id = viz::FrameSinkId( |
| fuzz->ConsumeIntegral<uint32_t>(), fuzz->ConsumeIntegral<uint32_t>()); |
| hit_test_region.rect = |
| gfx::Rect(fuzz->ConsumeIntegral<int>(), fuzz->ConsumeIntegral<int>(), |
| fuzz->ConsumeIntegral<int>(), fuzz->ConsumeIntegral<int>()); |
| hit_test_region.transform = gfx::ConsumeTransform(*fuzz); |
| |
| if (fuzz->ConsumeBool() && |
| (hit_test_region.flags & viz::HitTestRegionFlags::kHitTestChildSurface)) { |
| // If there's not enough space left for a LocalSurfaceId, then skip. |
| if (fuzz->remaining_bytes() < sizeof(viz::LocalSurfaceId)) |
| return; |
| |
| uint32_t last_frame_sink_id_client_id = |
| surface_id.frame_sink_id().client_id(); |
| uint32_t last_frame_sink_id_sink_id = surface_id.frame_sink_id().sink_id(); |
| viz::FrameSinkId frame_sink_id(last_frame_sink_id_client_id + 1, |
| last_frame_sink_id_sink_id + 1); |
| viz::LocalSurfaceId local_surface_id(GetNextUInt32NonZero(fuzz), |
| GetNextUInt32NonZero(fuzz), |
| base::UnguessableToken::Create()); |
| SubmitHitTestRegionList(fuzz, delegate, frame_sink_manager, |
| viz::SurfaceId(frame_sink_id, local_surface_id), |
| false /* support_is_root */, depth + 1); |
| } |
| |
| regions->push_back(std::move(hit_test_region)); |
| AddHitTestRegion(fuzz, regions, child_count - 1, delegate, frame_sink_manager, |
| surface_id, depth + 1); |
| } |
| |
| void SubmitHitTestRegionList( |
| FuzzedDataProvider* fuzz, |
| viz::TestLatestLocalSurfaceIdLookupDelegate* delegate, |
| viz::FrameSinkManagerImpl* frame_sink_manager, |
| const viz::SurfaceId& surface_id, |
| bool support_is_root, |
| const uint32_t depth) { |
| // If there's not enough space left for a HitTestRegionList, then skip. |
| if (fuzz->remaining_bytes() < sizeof(viz::HitTestRegionList) + sizeof(bool) || |
| depth > kMaxDepthAllowed) { |
| return; |
| } |
| |
| absl::optional<viz::HitTestRegionList> hit_test_region_list; |
| if (fuzz->ConsumeBool()) { |
| hit_test_region_list.emplace(); |
| hit_test_region_list->flags = fuzz->ConsumeIntegral<uint32_t>(); |
| hit_test_region_list->async_hit_test_reasons = |
| fuzz->ConsumeIntegral<uint32_t>(); |
| if (fuzz->ConsumeBool()) |
| hit_test_region_list->flags |= |
| viz::HitTestRegionFlags::kHitTestChildSurface; |
| hit_test_region_list->bounds = |
| gfx::Rect(fuzz->ConsumeIntegral<int>(), fuzz->ConsumeIntegral<int>(), |
| fuzz->ConsumeIntegral<int>(), fuzz->ConsumeIntegral<int>()); |
| hit_test_region_list->transform = gfx::ConsumeTransform(*fuzz); |
| |
| uint32_t child_count = fuzz->ConsumeIntegral<uint32_t>(); |
| AddHitTestRegion(fuzz, &hit_test_region_list->regions, child_count, |
| delegate, frame_sink_manager, surface_id, depth + 1); |
| } |
| |
| delegate->SetSurfaceIdMap(surface_id); |
| viz::CompositorFrameSinkSupport support( |
| nullptr /* client */, frame_sink_manager, surface_id.frame_sink_id(), |
| support_is_root); |
| support.SubmitCompositorFrame(surface_id.local_surface_id(), |
| viz::MakeDefaultCompositorFrame(), |
| std::move(hit_test_region_list)); |
| } |
| |
| } // namespace |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t num_bytes) { |
| FuzzedDataProvider fuzz(data, num_bytes); |
| viz::ServerSharedBitmapManager shared_bitmap_manager; |
| viz::FrameSinkManagerImpl frame_sink_manager{ |
| viz::FrameSinkManagerImpl::InitParams(&shared_bitmap_manager)}; |
| viz::TestLatestLocalSurfaceIdLookupDelegate delegate; |
| viz::TestLatestLocalSurfaceIdLookupDelegate* lsi_delegate = |
| fuzz.ConsumeBool() ? &delegate : nullptr; |
| |
| // If there's not enough space left for a LocalSurfaceId, then skip. |
| if (fuzz.remaining_bytes() < sizeof(viz::LocalSurfaceId)) |
| return 0; |
| |
| constexpr uint32_t root_client_id = 1; |
| constexpr uint32_t root_sink_id = 1; |
| viz::FrameSinkId frame_sink_id(root_client_id, root_sink_id); |
| viz::LocalSurfaceId local_surface_id(GetNextUInt32NonZero(&fuzz), |
| GetNextUInt32NonZero(&fuzz), |
| base::UnguessableToken::Create()); |
| viz::SurfaceId surface_id(frame_sink_id, local_surface_id); |
| viz::HitTestAggregator aggregator( |
| frame_sink_manager.hit_test_manager(), &frame_sink_manager, lsi_delegate, |
| frame_sink_id, 10 /* initial_region_size */, 100 /* max_region_size */); |
| |
| SubmitHitTestRegionList(&fuzz, &delegate, &frame_sink_manager, surface_id, |
| true /* support_is_root */, 0 /* depth */); |
| |
| viz::SurfaceId aggregate_surface_id = surface_id; |
| if (fuzz.ConsumeBool() && fuzz.remaining_bytes() >= sizeof(viz::SurfaceId)) { |
| aggregate_surface_id = |
| viz::SurfaceId(viz::FrameSinkId(GetNextUInt32NonZero(&fuzz), |
| GetNextUInt32NonZero(&fuzz)), |
| viz::LocalSurfaceId(GetNextUInt32NonZero(&fuzz), |
| GetNextUInt32NonZero(&fuzz), |
| base::UnguessableToken::Create())); |
| } |
| aggregator.Aggregate(aggregate_surface_id); |
| viz::Surface* surface = frame_sink_manager.surface_manager()->GetSurfaceForId( |
| aggregate_surface_id); |
| if (surface) |
| frame_sink_manager.surface_manager()->SurfaceDestroyed(surface); |
| |
| return 0; |
| } |