• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <stddef.h>
6 #include <stdint.h>
7 
8 #include <dawn/dawn_proc.h>
9 #include <dawn/webgpu_cpp.h>
10 #include <memory>
11 #include <vector>
12 
13 #include "base/base_switches.h"
14 #include "base/check_op.h"
15 #include "base/command_line.h"
16 #include "base/containers/span.h"
17 #include "base/functional/bind.h"
18 #include "base/functional/callback_forward.h"
19 #include "base/i18n/icu_util.h"
20 #include "base/logging.h"
21 #include "base/test/test_suite.h"
22 #include "build/build_config.h"
23 #include "command_buffer/common/constants.h"
24 #include "command_buffer/common/sync_token.h"
25 #include "content/public/common/content_switches.h"
26 #include "gpu/command_buffer/client/shared_memory_limits.h"
27 #include "gpu/command_buffer/client/webgpu_cmd_helper.h"
28 #include "gpu/command_buffer/client/webgpu_implementation.h"
29 #include "gpu/command_buffer/common/context_creation_attribs.h"
30 #include "gpu/command_buffer/service/gpu_switches.h"
31 #include "gpu/config/gpu_preferences.h"
32 #include "gpu/config/gpu_switches.h"
33 #include "gpu/ipc/host/gpu_memory_buffer_support.h"
34 #include "gpu/ipc/in_process_command_buffer.h"
35 #include "gpu/ipc/webgpu_in_process_context.h"
36 #include "mojo/core/embedder/embedder.h"
37 #include "ui/gl/gl_switches.h"
38 #include "ui/gl/init/gl_factory.h"
39 #include "ui/gl/test/gl_surface_test_support.h"
40 
41 #include "testing/libfuzzer/fuzzers/command_buffer_lpm_fuzzer/cmd_buf_lpm_fuzz.h"
42 #include "testing/libfuzzer/fuzzers/command_buffer_lpm_fuzzer/cmd_buf_lpm_fuzz.pb.h"
43 #include "testing/libfuzzer/fuzzers/command_buffer_lpm_fuzzer/webgpu_support.h"
44 #include "testing/libfuzzer/libfuzzer_exports.h"
45 #include "testing/libfuzzer/proto/lpm_interface.h"
46 
47 namespace gpu::cmdbuf::fuzzing {
48 
49 /* One-time fuzzer initialization. Called only once during fuzzer startup. */
CmdBufFuzz()50 CmdBufFuzz::CmdBufFuzz() : base::TestSuite(0, (char**)nullptr) {
51   CommandLineInit();
52   GfxInit();
53 }
54 
55 /* Enable WebGPU features and disable GPU hardware acceleration. */
CommandLineInit()56 void CmdBufFuzz::CommandLineInit() {
57   [[maybe_unused]] auto* command_line = base::CommandLine::ForCurrentProcess();
58   //--disable-gpu to force software rendering
59   command_line->AppendSwitchASCII(switches::kDisableGpu, "1");
60   // --use-webgpu-adapter=swiftshader
61   command_line->AppendSwitchASCII(
62       switches::kUseWebGPUAdapter,
63       switches::kVulkanImplementationNameSwiftshader);
64 #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && BUILDFLAG(USE_DAWN)
65   //--enable-features=Vulkan
66   command_line->AppendSwitchASCII(switches::kEnableFeatures,
67                                   gl::kANGLEImplementationVulkanName);
68   //--use-vulkan=swiftshader
69   command_line->AppendSwitchASCII(
70       switches::kUseVulkan, switches::kVulkanImplementationNameSwiftshader);
71 #endif
72 }
73 
74 /* Initialize the graphics stack in single-process mode with WebGPU. */
GfxInit()75 void CmdBufFuzz::GfxInit() {
76   VLOG(3) << "GfxInit() started";
77 
78   VLOG(3) << "Detecting platform specific features and setting preferences "
79              "accordingly";
80   gpu::GpuPreferences preferences;
81   preferences.enable_webgpu = true;
82   preferences.disable_software_rasterizer = false;
83 #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && BUILDFLAG(USE_DAWN)
84   preferences.gr_context_type = gpu::GrContextType::kVulkan;
85   // Use SwiftShader so fuzzing can work without a physical GPU.
86   preferences.use_vulkan = gpu::VulkanImplementationName::kSwiftshader;
87 #endif
88   preferences.use_webgpu_adapter = WebGPUAdapterName::kSwiftShader;
89   preferences.enable_unsafe_webgpu = true;
90   preferences.enable_gpu_service_logging_gpu = true;
91 
92   // Initializing some portion of Chromium's windowing feature seems to be
93   // required to use gpu::CreateBufferUsageAndFormatExceptionList().
94 
95   // TODO(bookholt): It's not obvious whether having legit values from
96   // gpu::CreateBufferUsageAndFormatExceptionList() is really desired for
97   // fuzzing, but it's a starting point.
98 
99   // TODO(bookholt): OS specific windowing init.
100   VLOG(3) << "Aura + Ozone init";
101   gl_display_ = gl::GLSurfaceTestSupport::InitializeOneOffWithStubBindings();
102   CHECK(gl_display_);
103   preferences.texture_target_exception_list =
104       gpu::CreateBufferUsageAndFormatExceptionList();
105   VLOG(3) << "TestGpuServiceHolder: starting GPU threads";
106   gpu_service_holder_ =
107       std::make_unique<viz::TestGpuServiceHolder>(preferences);
108 
109   VLOG(3) << "Init WebGPU context";
110   // TODO(bookholt): We might want to fuzz or tune some Context attributes, but
111   // for now we set them to enable initialization of a valid WebGPU context.
112   ContextCreationAttribs attributes;
113   attributes.bind_generates_resource = false;
114   attributes.enable_gles2_interface = false;
115   attributes.context_type = CONTEXT_TYPE_WEBGPU;
116   shared_memory_limits_ = std::make_unique<SharedMemoryLimits>(
117       SharedMemoryLimits::ForWebGPUContext());
118   /*
119      WebGPUInProcessContext does a lot of handy setup and uses threads to
120      simulate cross-process communication in a single process binary, but it's
121      not a 100% match to a real browser instance. E.g. it uses a char* as
122      backing memory for the CommandBuffer's RingBuffer instead of a
123      platform-specific shared memory implementation, and it bypasses Mojo
124      entirely, but it's compatible with our single-process fuzze_test build
125      target, so it's a decent starting point.
126 
127      The thinking is to let WebGPUInProcessContext create a working WebGPU
128      Context with associated data structures and then we'll tune or replace
129      anything we want to fuzz. However, starting from data structures with
130      benign properties may turn out to unnecessarily limit mischief, so in the
131      future it may be necessary to do more of our own Context init.
132 
133      Data structures of particular interest to fuzzing include:
134      - CommandBuffer and associated TransferBuffers
135      - WebGPUDecoder / DecoderContext
136   */
137   webgpu_context_ = std::make_unique<WebGPUInProcessContext>();
138   ContextResult webgpu_context_result = webgpu_context_->Initialize(
139       gpu_service_holder_->task_executor(), attributes, *shared_memory_limits_);
140   CHECK_EQ(webgpu_context_result, ContextResult::kSuccess);
141 
142   VLOG(3) << "Wire protocol setup";
143   wire_channel_ = webgpu()->GetAPIChannel();
144   dawn_procs_ = std::make_unique<DawnProcTable>(wire_channel_->GetProcs());
145   dawnProcSetProcs(dawn_procs_.get());
146   dawn_wire_services_ =
147       static_cast<webgpu::DawnWireServices*>(wire_channel_.get());
148   dawn_wire_serializer_ = dawn_wire_services_->serializer();
149   wire_descriptor_ = std::make_unique<dawn::wire::WireServerDescriptor>();
150   wire_descriptor_->procs = dawn_procs_.get();
151   wire_descriptor_->serializer = dawn_wire_serializer_.get();
152   wire_server_ = std::make_unique<dawn::wire::WireServer>(*wire_descriptor_);
153   dawn_instance_ = std::make_unique<dawn::native::Instance>();
154   wire_server_->InjectInstance(dawn_instance_->Get(), 1, 0);
155 
156   VLOG(3) << "Populate data structure grab bag";
157   command_buffer_ = webgpu_context_->GetCommandBufferForTest();
158   command_buffer_service_ =
159       std::make_unique<CommandBufferService>(command_buffer_, nullptr);
160   cmd_helper_ = webgpu_context_->GetCommandBufferHelperForTest();
161   webgpu_cmd_helper_ =
162       std::make_unique<webgpu::WebGPUCmdHelper>(command_buffer_.get());
163   task_executor_ = command_buffer_->service_for_testing();
164   // task_executor_->GetSharedContextState()->surface();
165   surface_ = gl::init::CreateOffscreenGLSurface(gl_display_, gfx::Size());
166   CHECK(surface_.get());
167   decoder_ = command_buffer_->GetWebGPUDecoderForTest();
168   webgpu_instance_ =
169       std::make_unique<wgpu::Instance>(wire_channel_->GetWGPUInstance());
170   buffer_ = cmd_helper_->get_ring_buffer();
171   CHECK(buffer_);
172   command_buffer_id_ = cmd_helper_->get_ring_buffer_id();
173   // command_buffer_->SetGetBuffer(command_buffer_id_);
174   webgpu_impl_ = webgpu_context_->GetImplementation();
175 
176   VLOG(3) << "GfxInit complete";
177 }
178 
179 CmdBufFuzz::~CmdBufFuzz() = default;
180 
181 /* Per-test case setup. */
RuntimeInit()182 void CmdBufFuzz::RuntimeInit() {
183   // Verify command buffer is ready for the new test case.
184   if (!cmd_helper_->HaveRingBuffer()) {
185     VLOG(3) << "CommandBuffer (re-)init";
186     cmd_helper_->Initialize(shared_memory_limits_->command_buffer_size);
187 
188     buffer_ = cmd_helper_->get_ring_buffer();
189     CHECK(buffer_);
190     command_buffer_id_ = cmd_helper_->get_ring_buffer_id();
191     command_buffer_->SetGetBuffer(command_buffer_id_);
192   }
193 }
194 
195 /* Deserialize a proto message from a test case into a gpu::SyncToken. */
SyncTokenFromProto(fuzzing::SyncToken token_proto)196 gpu::SyncToken CmdBufFuzz::SyncTokenFromProto(fuzzing::SyncToken token_proto) {
197   // TODO(bookholt): Pick buffer_id from a narrower range of sensible values.
198   CommandBufferId buffer_id =
199       CommandBufferId::FromUnsafeValue(token_proto.command_buffer_id());
200   uint64_t release_count = token_proto.release_count();
201 
202   // Limit the range of CommandBufferNamespaceId values because this fuzzer
203   // bypasses Mojo trait validation, but a real renderer cannot.
204   CommandBufferNamespace ns = static_cast<CommandBufferNamespace>(
205       token_proto.namespace_id() %
206       gpu::cmdbuf::fuzzing::CommandBufferNamespaceIds::MAX_VALID);
207 
208   gpu::SyncToken sync_token(ns, buffer_id, release_count);
209   return sync_token;
210 }
211 
212 /* Dummy SignalSyncToken callback function. */
SignalSyncTokenCallback()213 void CmdBufFuzz::SignalSyncTokenCallback() {}
214 
215 /* Fuzzing happens here. */
RunCommandBuffer(fuzzing::CmdBufSession session)216 void CmdBufFuzz::RunCommandBuffer(fuzzing::CmdBufSession session) {
217   if (!session.actions_size()) {
218     VLOG(3) << "Empty test case :(";
219     return;
220   }
221 
222   RuntimeInit();
223 
224   while (action_index_ < session.actions_size()) {
225     const auto& action = session.actions(action_index_);
226     switch (action.action_case()) {
227       case fuzzing::Action::kCmdBufOp: {
228         auto op = action.cmdbufop();
229         switch (op.cmd_buf_ops_case()) {
230           case fuzzing::InProcessCommandBufferOp::kGetLastState: {
231             VLOG(3) << "kGetLastState";
232             command_buffer_->GetLastState();
233             break;
234           }
235 
236           case fuzzing::InProcessCommandBufferOp::kFlush: {
237             VLOG(3) << "kFlush";
238             command_buffer_->Flush(op.flush().put_offset());
239             break;
240           }
241 
242           case fuzzing::InProcessCommandBufferOp::kOrderingBarrier: {
243             VLOG(3) << "kOrderingBarrier";
244             command_buffer_->OrderingBarrier(op.orderingbarrier().put_offset());
245             break;
246           }
247 
248           case fuzzing::InProcessCommandBufferOp::kWaitForTokenInRange: {
249             VLOG(3) << "kWaitForTokenInRange";
250             // It'd be nice to fuzz this, but it's currently too slow.
251             break;
252           }
253 
254           case fuzzing::InProcessCommandBufferOp::kWaitForGetOffsetInRange: {
255             VLOG(3) << "kWaitForGetOffsetInRange";
256             // It'd be nice to fuzz this, but it's currently too slow.
257             break;
258           }
259 
260           case fuzzing::InProcessCommandBufferOp::kSetGetBuffer: {
261             VLOG(3) << "kSetGetBuffer";
262             // TODO(bookholt): Random shm_id is probably unwise.
263             command_buffer_->SetGetBuffer(op.setgetbuffer().shm_id());
264             break;
265           }
266 
267           case fuzzing::InProcessCommandBufferOp::kCreateTransferBuffer: {
268             VLOG(3) << "kCreateTransferBuffer";
269             // TODO(bookholt): Add to vector for use in kDestroyTransferBuffer.
270             int id = -1;
271             command_buffer_->CreateTransferBuffer(
272                 op.createtransferbuffer().size(), &id);
273             break;
274           }
275 
276           case fuzzing::InProcessCommandBufferOp::kDestroyTransferBuffer: {
277             VLOG(3) << "kDestroyTransferBuffer";
278             // TODO(bookholt): Make a way to identify all TransferBuffers
279             // created during GfxInit(), then add those to the TB vector.
280             //
281             // TODO(bookholt): Pull TB IDs from the vector rather than using
282             // totally random IDs that are unlikely to be valid.
283             command_buffer_->DestroyTransferBuffer(
284                 op.destroytransferbuffer().id());
285             break;
286           }
287 
288           case fuzzing::InProcessCommandBufferOp::kForceLostContet: {
289             VLOG(3) << "kForceLostContet";
290             auto reason = static_cast<error::ContextLostReason>(
291                 op.forcelostcontet().reason() %
292                     error::ContextLostReason::kContextLostReasonLast +
293                 1);
294             command_buffer_->ForceLostContext(reason);
295             break;
296           }
297 
298           case fuzzing::InProcessCommandBufferOp::kSetGpuControlClient: {
299             // TODO(bookholt): find a sensible approach
300             VLOG(3) << "kSetGpuControlClient: unsupported op";
301             break;
302           }
303 
304           case fuzzing::InProcessCommandBufferOp::kGetCapabilities: {
305             VLOG(3) << "kGetCapabilities: NOOP";
306             // Kind of a NOOP for fuzzing. :-/
307             command_buffer_->GetCapabilities();
308             break;
309           }
310 
311           case fuzzing::InProcessCommandBufferOp::kSignalQuery: {
312             VLOG(3) << "kSignalQuery: unsupported op";
313             // Signal Queries not supported by WebGPUDecoderImpl
314             break;
315           }
316 
317           case fuzzing::InProcessCommandBufferOp::kCreateGpuFence: {
318             VLOG(3) << "kCreateGpuFence: unsupported op";
319             // GPU Fence not supported by WebGPUDecoderImpl
320             break;
321           }
322 
323           case fuzzing::InProcessCommandBufferOp::kGetGpuFence: {
324             VLOG(3) << "kGetGpuFence: unsupported op";
325             // GPU Fence not supported by WebGPUDecoderImpl
326             break;
327           }
328 
329           case fuzzing::InProcessCommandBufferOp::kSetLock: {
330             VLOG(3) << "kSetLock: unsupported op";
331             // Interesting feature to fuzz, but unsupported by
332             // InProcessCommandBuffer :( TODO(bookholt): support for SetLock
333             // would require either
334             // - adding libfuzzer support to BrowserTests or
335             // - snapshot fuzzing support
336             break;
337           }
338 
339           case fuzzing::InProcessCommandBufferOp::kEnsureWorkVisible: {
340             VLOG(3) << "kEnsureWorkVisible: unsupported op";
341             // Unsupported by InProcessCommandBuffer :(
342             break;
343           }
344 
345           case fuzzing::InProcessCommandBufferOp::kGetNamespaceID: {
346             VLOG(3) << "kGetNamespaceID: unsupported op";
347             // Valid values in gpu/command_buffer/common/constants.h Calling
348             // this function is a NOOP from a fuzzer perspective, but other
349             // CommandBufferOps will want to implement it.
350             break;
351           }
352 
353           case fuzzing::InProcessCommandBufferOp::kGetCommandBufferID: {
354             VLOG(3) << "kGetCommandBufferID: unsupported op";
355             // Calling this function is a NOOP from a fuzzer perspective, but
356             // other CommandBufferOps will want to implement it.
357             break;
358           }
359 
360           case fuzzing::InProcessCommandBufferOp::kFlushPendingWork: {
361             VLOG(3) << "kFlushPendingWork: unsupported op";
362             // Unsupported by InProcessCommandBuffer :(
363             break;
364           }
365 
366           case fuzzing::InProcessCommandBufferOp::kGenerateFenceSyncRelease: {
367             VLOG(3) << "kGenerateFenceSyncRelease";
368             command_buffer_->GenerateFenceSyncRelease();
369             break;
370           }
371 
372           case fuzzing::InProcessCommandBufferOp::kIsFenceSyncReleased: {
373             VLOG(3) << "kIsFenceSyncReleased: unsupported op";
374             // Calling this function directly is effectively a NOOP, but other
375             // CommandBufferOps may want to implement it.
376             break;
377           }
378 
379           case fuzzing::InProcessCommandBufferOp::kSignalSyncToken: {
380             VLOG(3) << "kSignalSyncToken";
381             gpu::SyncToken sync_token =
382                 SyncTokenFromProto(op.signalsynctoken().sync_token());
383 
384             auto callback = base::BindOnce(&CmdBufFuzz::SignalSyncTokenCallback,
385                                            base::Unretained(this));
386             command_buffer_->SignalSyncToken(std::move(sync_token),
387                                              std::move(callback));
388             break;
389           }
390 
391           case fuzzing::InProcessCommandBufferOp::kWaitSyncToken: {
392             VLOG(3) << "kWaitSyncToken";
393             gpu::SyncToken sync_token =
394                 SyncTokenFromProto(op.waitsynctoken().sync_token());
395 
396             command_buffer_->WaitSyncToken(std::move(sync_token));
397             break;
398           }
399 
400           case fuzzing::InProcessCommandBufferOp::kCanWaitUnverifiedSyncToken: {
401             VLOG(3) << "kCanWaitUnverifiedSyncToken: unsupported op";
402             // NOOP
403             break;
404           }
405 
406           case fuzzing::InProcessCommandBufferOp::kOnCommandBatchProcessed: {
407             VLOG(3) << "kOnCommandBatchProcessed: unsupported op";
408             // ~NOOP
409             break;
410           }
411 
412           case fuzzing::InProcessCommandBufferOp::kOnParseError: {
413             VLOG(3) << "kOnParseError: unsupported op";
414             break;
415           }
416 
417           case fuzzing::InProcessCommandBufferOp::kOnConsoleMessage: {
418             // Not supported by InProcessCommandBuffer.
419             VLOG(3) << "kOnConsoleMessage: unsupported op";
420             break;
421           }
422 
423           case fuzzing::InProcessCommandBufferOp::kCacheBlob: {
424             // Not supported by InProcessCommandBuffer.
425             VLOG(3) << "kCacheBlob: unsupported op";
426             break;
427           }
428 
429           case fuzzing::InProcessCommandBufferOp::kOnFenceSyncRelease: {
430             VLOG(3) << "kOnFenceSyncRelease";
431             // GPU Fence not supported by WebGPUDecoderImpl
432             command_buffer_->OnFenceSyncRelease(
433                 op.onfencesyncrelease().release());
434             break;
435           }
436 
437           case fuzzing::InProcessCommandBufferOp::kOnDescheduleUntilFinished: {
438             VLOG(3) << "kOnDescheduleUntilFinished: unsupported op";
439             // Not supported by InProcessCommandBuffer.
440             break;
441           }
442 
443           case fuzzing::InProcessCommandBufferOp::kOnRescheduleAfterFinished: {
444             VLOG(3) << "kOnRescheduleAfterFinished: unsupported op";
445             // Not supported by InProcessCommandBuffer.
446             break;
447           }
448 
449           case fuzzing::InProcessCommandBufferOp::kOnSwapBuffers: {
450             VLOG(3) << "kOnSwapBuffers: unsupported op";
451             // Not supported by InProcessCommandBuffer.
452             break;
453           }
454 
455           case fuzzing::InProcessCommandBufferOp::kScheduleGrContextCleanup: {
456             VLOG(3) << "kScheduleGrContextCleanup";
457             command_buffer_->ScheduleGrContextCleanup();
458             break;
459           }
460 
461           case fuzzing::InProcessCommandBufferOp::kHandleReturnData: {
462             VLOG(3) << "kHandleReturnData: "
463                     << op.handlereturndata().data().size();
464 
465             std::vector<uint8_t> vec;
466             for (unsigned int entry : op.handlereturndata().data()) {
467               vec.push_back(entry);
468             }
469             base::span<uint8_t> data_span(vec);
470             // Passing totally unstructured data leads to hitting validation
471             // errors in webgpu_decoder_impl.cc.
472 
473             // TODO(bookholt): Explore whether it's worth giving some structure
474             // to data sent to HandleReturnData().
475             command_buffer_->HandleReturnData(data_span);
476             break;
477           }
478 
479           case fuzzing::InProcessCommandBufferOp::kGetFeatureInfo: {
480             VLOG(3) << "kGetFeatureInfo";
481             command_buffer_->GetFeatureInfo();
482             break;
483           }
484 
485           case fuzzing::InProcessCommandBufferOp::kGetGpuFeatureInfo: {
486             VLOG(3) << "kGetGpuFeatureInfo";
487             command_buffer_->GetGpuFeatureInfo();
488             break;
489           }
490 
491           case fuzzing::InProcessCommandBufferOp::kGetTransferCacheForTest: {
492             VLOG(3) << "kGetTransferCacheForTest";
493             // TODO(bookholt): Worth a think about refactoring to make use of
494             // the TransferCache.
495             command_buffer_->GetTransferCacheForTest();
496             break;
497           }
498 
499           case fuzzing::InProcessCommandBufferOp::kGetRasterDecoderIdForTest: {
500             VLOG(3) << "kGetRasterDecoderIdForTest";
501             command_buffer_->GetRasterDecoderIdForTest();
502             break;
503           }
504 
505           case fuzzing::InProcessCommandBufferOp::kGetWebGPUDecoderForTest: {
506             VLOG(3) << "kGetWebGPUDecoderForTest";
507             command_buffer_->GetWebGPUDecoderForTest();
508             break;
509           }
510 
511           case fuzzing::InProcessCommandBufferOp::kServiceForTesting: {
512             VLOG(3) << "kServiceForTesting";
513             command_buffer_->service_for_testing();
514             break;
515           }
516 
517           case fuzzing::InProcessCommandBufferOp::kGetSharedImageInterface: {
518             VLOG(3) << "kGetSharedImageInterface: unsupported op";
519             // TODO(bookholt): Worth a think about refactoring to make use of
520             // the gpu::SharedImageInterface.
521             command_buffer_->GetSharedImageInterface();
522             break;
523           }
524 
525           // TODO(bookholt): The fuzzer really shouldn't generate this value,
526           // but it does. Investigate how/why LPM generates this value and
527           // consider tuning to avoid it because it seems like a waste of
528           // performance.
529           case fuzzing::InProcessCommandBufferOp::CMD_BUF_OPS_NOT_SET: {
530             VLOG(3) << "Invalid InProcessCommandBufferOp";
531             break;
532           }
533         }
534         break;
535       }
536       // TODO(bookholt): The fuzzer really shouldn't generate this value, but it
537       // does. Investigate how/why LPM generates this value and consider tuning
538       // to avoid it because it seems like a waste of performance.
539       case fuzzing::Action::ACTION_NOT_SET: {
540         DLOG(WARNING) << "No Action set";
541       } break;
542     }
543     action_index_++;
544   }
545 
546   //  Prepare for next testcase.
547   if (!Reset()) {
548     // See crbug.com/1424591
549     VLOG(1) << "Test case reset failed. Re-initializing graphics.";
550     // Re-initialize the graphics stack to (hopefully!) avoid sync problems.
551     GfxInit();
552     return;
553   }
554 }
555 
556 /* Make CommandBuffer ready for the next test case. */
CmdBufReset()557 bool CmdBufFuzz::CmdBufReset() {
558   // Wait for handling of commands from the previous test case to complete.
559   return cmd_helper_->Finish();
560 }
561 
562 /* Clean up from the last test case and get ready for the next one. */
Reset()563 bool CmdBufFuzz::Reset() {
564   action_index_ = 0;
565   return CmdBufReset();
566 }
567 
568 // Keeper of global fuzzing state
569 CmdBufFuzz* wgpuf_setup;
570 
571 }  // namespace gpu::cmdbuf::fuzzing
572 
573 /* One-time early initialization at process startup. */
LLVMFuzzerInitialize(int * argc,char *** argv)574 extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
575   logging::SetMinLogLevel(logging::LOGGING_VERBOSE);  // Enable logging.
576   CHECK(base::i18n::InitializeICU());  // Unicode support for cmd line parsing.
577   base::CommandLine::Init(*argc, *argv);  // Parse cmd line args.
578   mojo::core::Init();  // Initialize Mojo; probably unnecessary.
579 
580   gpu::cmdbuf::fuzzing::wgpuf_setup = new gpu::cmdbuf::fuzzing::CmdBufFuzz();
581   return 0;
582 }
583 
584 /* Fuzzer entry point. Called on every iteration with a fresh test case. */
DEFINE_PROTO_FUZZER(gpu::cmdbuf::fuzzing::CmdBufSession & session)585 DEFINE_PROTO_FUZZER(gpu::cmdbuf::fuzzing::CmdBufSession& session) {
586   gpu::cmdbuf::fuzzing::wgpuf_setup->RunCommandBuffer(session);
587   return;
588 }
589