| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <lib/zbi-format/graphics.h> |
| |
| #include <map> |
| |
| #include <fuzzer/FuzzedDataProvider.h> |
| |
| #include "gfx/gfx.h" |
| |
| static const unsigned kMaxDimension = 4096; |
| |
| static bool IsBlendable(gfx_surface* a, gfx_surface* b) { |
| if (a->format != b->format) { |
| return false; |
| } |
| |
| switch (a->format) { |
| case ZBI_PIXEL_FORMAT_ARGB_8888: |
| return true; |
| case ZBI_PIXEL_FORMAT_RGB_X888: |
| return true; |
| case ZBI_PIXEL_FORMAT_MONO_8: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| static gfx_surface* LookupSurface(FuzzedDataProvider* input, |
| const std::map<unsigned, gfx_surface*>* surfaces) { |
| auto id = input->ConsumeIntegral<unsigned>(); |
| auto it = surfaces->find(id); |
| if (it == surfaces->end()) { |
| return nullptr; |
| } |
| return it->second; |
| } |
| |
| unsigned ReadPixelFormat(FuzzedDataProvider* input) { |
| static const unsigned LEGAL_PIXEL_FORMATS[] = { |
| ZBI_PIXEL_FORMAT_RGB_565, ZBI_PIXEL_FORMAT_RGB_332, ZBI_PIXEL_FORMAT_RGB_2220, |
| ZBI_PIXEL_FORMAT_ARGB_8888, ZBI_PIXEL_FORMAT_RGB_X888, ZBI_PIXEL_FORMAT_MONO_8, |
| ZBI_PIXEL_FORMAT_NV12, ZBI_PIXEL_FORMAT_RGB_888, |
| }; |
| return LEGAL_PIXEL_FORMATS[input->ConsumeIntegralInRange<uint8_t>( |
| 0, sizeof(LEGAL_PIXEL_FORMATS) / sizeof(*LEGAL_PIXEL_FORMATS) - 1)]; |
| } |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
| FuzzedDataProvider input(data, size); |
| std::map<unsigned, gfx_surface*> surfaces; |
| |
| while (true) { |
| switch (input.ConsumeIntegral<uint8_t>()) { |
| default: |
| case 0: { |
| for (auto [id, surface] : surfaces) { |
| gfx_surface_destroy(surface); |
| } |
| surfaces.clear(); |
| return 0; |
| } |
| |
| case 1: { |
| auto id = input.ConsumeIntegral<unsigned>(); |
| if (surfaces.count(id)) { |
| break; |
| } |
| auto width = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension); |
| auto height = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension); |
| auto stride = width + input.ConsumeIntegral<uint8_t>(); |
| auto pixel_format = ReadPixelFormat(&input); |
| auto flags = input.ConsumeIntegral<unsigned>() & (GFX_FLAG_FLUSH_CPU_CACHE); |
| if (auto* surface = |
| gfx_create_surface(nullptr, width, height, stride, pixel_format, flags)) { |
| surfaces[id] = surface; |
| } |
| break; |
| } |
| |
| case 2: { |
| auto id = input.ConsumeIntegral<unsigned>(); |
| auto it = surfaces.find(id); |
| if (it == surfaces.end()) { |
| break; |
| } |
| gfx_surface_destroy(it->second); |
| surfaces.erase(it); |
| break; |
| } |
| |
| case 3: |
| if (auto* surface = LookupSurface(&input, &surfaces)) { |
| gfx_flush(surface); |
| } |
| break; |
| |
| case 4: |
| if (auto* surface = LookupSurface(&input, &surfaces)) { |
| auto x = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto y = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto width = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension); |
| auto height = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension); |
| auto x2 = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto y2 = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| gfx_copyrect(surface, x, y, width, height, x2, y2); |
| } |
| break; |
| |
| case 5: |
| if (auto* surface = LookupSurface(&input, &surfaces)) { |
| auto x = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto y = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto width = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension); |
| auto height = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension); |
| auto color = input.ConsumeIntegral<unsigned>(); |
| gfx_fillrect(surface, x, y, width, height, color); |
| } |
| break; |
| |
| case 6: |
| if (auto* surface = LookupSurface(&input, &surfaces)) { |
| auto x = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto y = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto color = input.ConsumeIntegral<unsigned>(); |
| gfx_putpixel(surface, x, y, color); |
| } |
| break; |
| |
| case 7: |
| if (auto* surface = LookupSurface(&input, &surfaces)) { |
| auto x = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto y = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto x2 = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto y2 = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto color = input.ConsumeIntegral<unsigned>(); |
| gfx_line(surface, x, y, x2, y2, color); |
| } |
| break; |
| |
| case 8: |
| if (auto* surface1 = LookupSurface(&input, &surfaces)) { |
| if (auto* surface2 = LookupSurface(&input, &surfaces)) { |
| if (!IsBlendable(surface1, surface2)) { |
| break; |
| } |
| auto destx = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto desty = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| gfx_surface_blend(surface1, surface2, destx, desty); |
| } |
| } |
| break; |
| |
| case 9: |
| if (auto* surface1 = LookupSurface(&input, &surfaces)) { |
| if (auto* surface2 = LookupSurface(&input, &surfaces)) { |
| if (!IsBlendable(surface1, surface2)) { |
| break; |
| } |
| auto srcx = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto srcy = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto width = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension); |
| auto height = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension); |
| auto destx = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto desty = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| gfx_blend(surface1, surface2, srcx, srcy, width, height, destx, desty); |
| } |
| } |
| break; |
| |
| case 10: |
| if (auto* surface1 = LookupSurface(&input, &surfaces)) { |
| if (auto* surface2 = LookupSurface(&input, &surfaces)) { |
| auto srcy = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto desty = input.ConsumeIntegralInRange<unsigned>(0, kMaxDimension); |
| auto height = input.ConsumeIntegralInRange<unsigned>(1, kMaxDimension); |
| gfx_copylines(surface1, surface2, srcy, desty, height); |
| } |
| } |
| break; |
| |
| case 11: |
| if (auto* surface = LookupSurface(&input, &surfaces)) { |
| auto color = input.ConsumeIntegral<unsigned>(); |
| gfx_clear(surface, color); |
| } |
| break; |
| } |
| } |
| } |