• 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   dawn_instance_->DiscoverDefaultAdapters();
155   wire_server_->InjectInstance(dawn_instance_->Get(), 1, 0);
156 
157   VLOG(3) << "Populate data structure grab bag";
158   command_buffer_ = webgpu_context_->GetCommandBufferForTest();
159   command_buffer_service_ =
160       std::make_unique<CommandBufferService>(command_buffer_, nullptr);
161   cmd_helper_ = webgpu_context_->GetCommandBufferHelperForTest();
162   webgpu_cmd_helper_ =
163       std::make_unique<webgpu::WebGPUCmdHelper>(command_buffer_.get());
164   task_executor_ = command_buffer_->service_for_testing();
165   // task_executor_->GetSharedContextState()->surface();
166   surface_ = gl::init::CreateOffscreenGLSurface(gl_display_, gfx::Size());
167   CHECK(surface_.get());
168   decoder_ = command_buffer_->GetWebGPUDecoderForTest();
169   webgpu_instance_ =
170       std::make_unique<wgpu::Instance>(wire_channel_->GetWGPUInstance());
171   buffer_ = cmd_helper_->get_ring_buffer();
172   CHECK(buffer_);
173   command_buffer_id_ = cmd_helper_->get_ring_buffer_id();
174   // command_buffer_->SetGetBuffer(command_buffer_id_);
175   webgpu_impl_ = webgpu_context_->GetImplementation();
176 
177   VLOG(3) << "GfxInit complete";
178 }
179 
180 CmdBufFuzz::~CmdBufFuzz() = default;
181 
182 /* Per-test case setup. */
RuntimeInit()183 void CmdBufFuzz::RuntimeInit() {
184   // Verify command buffer is ready for the new test case.
185   if (!cmd_helper_->HaveRingBuffer()) {
186     VLOG(3) << "CommandBuffer (re-)init";
187     cmd_helper_->Initialize(shared_memory_limits_->command_buffer_size);
188 
189     buffer_ = cmd_helper_->get_ring_buffer();
190     CHECK(buffer_);
191     command_buffer_id_ = cmd_helper_->get_ring_buffer_id();
192     command_buffer_->SetGetBuffer(command_buffer_id_);
193   }
194 }
195 
196 /* Deserialize a proto message from a test case into a gpu::SyncToken. */
SyncTokenFromProto(fuzzing::SyncToken token_proto)197 gpu::SyncToken CmdBufFuzz::SyncTokenFromProto(fuzzing::SyncToken token_proto) {
198   // TODO(bookholt): Pick buffer_id from a narrower range of sensible values.
199   CommandBufferId buffer_id =
200       CommandBufferId::FromUnsafeValue(token_proto.command_buffer_id());
201   uint64_t release_count = token_proto.release_count();
202 
203   // Limit the range of CommandBufferNamespaceId values because this fuzzer
204   // bypasses Mojo trait validation, but a real renderer cannot.
205   CommandBufferNamespace ns = static_cast<CommandBufferNamespace>(
206       token_proto.namespace_id() %
207       gpu::cmdbuf::fuzzing::CommandBufferNamespaceIds::MAX_VALID);
208 
209   gpu::SyncToken sync_token(ns, buffer_id, release_count);
210   return sync_token;
211 }
212 
213 /* Dummy SignalSyncToken callback function. */
SignalSyncTokenCallback()214 void CmdBufFuzz::SignalSyncTokenCallback() {}
215 
216 /* Fuzzing happens here. */
RunCommandBuffer(fuzzing::CmdBufSession session)217 void CmdBufFuzz::RunCommandBuffer(fuzzing::CmdBufSession session) {
218   if (!session.actions_size()) {
219     VLOG(3) << "Empty test case :(";
220     return;
221   }
222 
223   RuntimeInit();
224 
225   while (action_index_ < session.actions_size()) {
226     const auto& action = session.actions(action_index_);
227     switch (action.action_case()) {
228       case fuzzing::Action::kCmdBufOp: {
229         auto op = action.cmdbufop();
230         switch (op.cmd_buf_ops_case()) {
231           case fuzzing::InProcessCommandBufferOp::kGetLastState: {
232             VLOG(3) << "kGetLastState";
233             command_buffer_->GetLastState();
234             break;
235           }
236 
237           case fuzzing::InProcessCommandBufferOp::kFlush: {
238             VLOG(3) << "kFlush";
239             command_buffer_->Flush(op.flush().put_offset());
240             break;
241           }
242 
243           case fuzzing::InProcessCommandBufferOp::kOrderingBarrier: {
244             VLOG(3) << "kOrderingBarrier";
245             command_buffer_->OrderingBarrier(op.orderingbarrier().put_offset());
246             break;
247           }
248 
249           case fuzzing::InProcessCommandBufferOp::kWaitForTokenInRange: {
250             VLOG(3) << "kWaitForTokenInRange";
251             // TODO(bookholt): random start/end values is probably unwise
252             break;
253             command_buffer_->WaitForTokenInRange(
254                 op.waitfortokeninrange().start(),
255                 op.waitfortokeninrange().end());
256             break;
257           }
258 
259           case fuzzing::InProcessCommandBufferOp::kWaitForGetOffsetInRange: {
260             VLOG(3) << "kWaitForGetOffsetInRange";
261             // TODO(bookholt): random count/start/end values is probably unwise
262             break;
263             command_buffer_->WaitForGetOffsetInRange(
264                 op.waitforgetoffsetinrange().set_get_buffer_count(),
265                 op.waitforgetoffsetinrange().start(),
266                 op.waitforgetoffsetinrange().end());
267             break;
268           }
269 
270           case fuzzing::InProcessCommandBufferOp::kSetGetBuffer: {
271             VLOG(3) << "kSetGetBuffer";
272             // TODO(bookholt): Random shm_id is probably unwise.
273             command_buffer_->SetGetBuffer(op.setgetbuffer().shm_id());
274             break;
275           }
276 
277           case fuzzing::InProcessCommandBufferOp::kCreateTransferBuffer: {
278             VLOG(3) << "kCreateTransferBuffer";
279             // TODO(bookholt): Add to vector for use in kDestroyTransferBuffer.
280             int id = -1;
281             command_buffer_->CreateTransferBuffer(
282                 op.createtransferbuffer().size(), &id);
283             break;
284           }
285 
286           case fuzzing::InProcessCommandBufferOp::kDestroyTransferBuffer: {
287             VLOG(3) << "kDestroyTransferBuffer";
288             // TODO(bookholt): Make a way to identify all TransferBuffers
289             // created during GfxInit(), then add those to the TB vector.
290             //
291             // TODO(bookholt): Pull TB IDs from the vector rather than using
292             // totally random IDs that are unlikely to be valid.
293             command_buffer_->DestroyTransferBuffer(
294                 op.destroytransferbuffer().id());
295             break;
296           }
297 
298           case fuzzing::InProcessCommandBufferOp::kForceLostContet: {
299             VLOG(3) << "kForceLostContet";
300             auto reason = static_cast<error::ContextLostReason>(
301                 op.forcelostcontet().reason() %
302                     error::ContextLostReason::kContextLostReasonLast +
303                 1);
304             command_buffer_->ForceLostContext(reason);
305             break;
306           }
307 
308           case fuzzing::InProcessCommandBufferOp::kSetGpuControlClient: {
309             // TODO(bookholt): find a sensible approach
310             VLOG(3) << "kSetGpuControlClient: unsupported op";
311             break;
312           }
313 
314           case fuzzing::InProcessCommandBufferOp::kGetCapabilities: {
315             VLOG(3) << "kGetCapabilities: NOOP";
316             // Kind of a NOOP for fuzzing. :-/
317             command_buffer_->GetCapabilities();
318             break;
319           }
320 
321           case fuzzing::InProcessCommandBufferOp::kSignalQuery: {
322             VLOG(3) << "kSignalQuery: unsupported op";
323             // Signal Queries not supported by WebGPUDecoderImpl
324             break;
325           }
326 
327           case fuzzing::InProcessCommandBufferOp::kCreateGpuFence: {
328             VLOG(3) << "kCreateGpuFence: unsupported op";
329             // GPU Fence not supported by WebGPUDecoderImpl
330             break;
331           }
332 
333           case fuzzing::InProcessCommandBufferOp::kGetGpuFence: {
334             VLOG(3) << "kGetGpuFence: unsupported op";
335             // GPU Fence not supported by WebGPUDecoderImpl
336             break;
337           }
338 
339           case fuzzing::InProcessCommandBufferOp::kSetLock: {
340             VLOG(3) << "kSetLock: unsupported op";
341             // Interesting feature to fuzz, but unsupported by
342             // InProcessCommandBuffer :( TODO(bookholt): support for SetLock
343             // would require either
344             // - adding libfuzzer support to BrowserTests or
345             // - snapshot fuzzing support
346             break;
347           }
348 
349           case fuzzing::InProcessCommandBufferOp::kEnsureWorkVisible: {
350             VLOG(3) << "kEnsureWorkVisible: unsupported op";
351             // Unsupported by InProcessCommandBuffer :(
352             break;
353           }
354 
355           case fuzzing::InProcessCommandBufferOp::kGetNamespaceID: {
356             VLOG(3) << "kGetNamespaceID: unsupported op";
357             // Valid values in gpu/command_buffer/common/constants.h Calling
358             // this function is a NOOP from a fuzzer perspective, but other
359             // CommandBufferOps will want to implement it.
360             break;
361           }
362 
363           case fuzzing::InProcessCommandBufferOp::kGetCommandBufferID: {
364             VLOG(3) << "kGetCommandBufferID: unsupported op";
365             // Calling this function is a NOOP from a fuzzer perspective, but
366             // other CommandBufferOps will want to implement it.
367             break;
368           }
369 
370           case fuzzing::InProcessCommandBufferOp::kFlushPendingWork: {
371             VLOG(3) << "kFlushPendingWork: unsupported op";
372             // Unsupported by InProcessCommandBuffer :(
373             break;
374           }
375 
376           case fuzzing::InProcessCommandBufferOp::kGenerateFenceSyncRelease: {
377             VLOG(3) << "kGenerateFenceSyncRelease";
378             command_buffer_->GenerateFenceSyncRelease();
379             break;
380           }
381 
382           case fuzzing::InProcessCommandBufferOp::kIsFenceSyncReleased: {
383             VLOG(3) << "kIsFenceSyncReleased: unsupported op";
384             // Calling this function directly is effectively a NOOP, but other
385             // CommandBufferOps may want to implement it.
386             break;
387           }
388 
389           case fuzzing::InProcessCommandBufferOp::kSignalSyncToken: {
390             VLOG(3) << "kSignalSyncToken";
391             gpu::SyncToken sync_token =
392                 SyncTokenFromProto(op.signalsynctoken().sync_token());
393 
394             auto callback = base::BindOnce(&CmdBufFuzz::SignalSyncTokenCallback,
395                                            base::Unretained(this));
396             command_buffer_->SignalSyncToken(std::move(sync_token),
397                                              std::move(callback));
398             break;
399           }
400 
401           case fuzzing::InProcessCommandBufferOp::kWaitSyncToken: {
402             VLOG(3) << "kWaitSyncToken";
403             gpu::SyncToken sync_token =
404                 SyncTokenFromProto(op.waitsynctoken().sync_token());
405 
406             command_buffer_->WaitSyncToken(std::move(sync_token));
407             break;
408           }
409 
410           case fuzzing::InProcessCommandBufferOp::kCanWaitUnverifiedSyncToken: {
411             VLOG(3) << "kCanWaitUnverifiedSyncToken: unsupported op";
412             // NOOP
413             break;
414           }
415 
416           case fuzzing::InProcessCommandBufferOp::kOnCommandBatchProcessed: {
417             VLOG(3) << "kOnCommandBatchProcessed: unsupported op";
418             // ~NOOP
419             break;
420           }
421 
422           case fuzzing::InProcessCommandBufferOp::kOnParseError: {
423             VLOG(3) << "kOnParseError: unsupported op";
424             break;
425           }
426 
427           case fuzzing::InProcessCommandBufferOp::kOnConsoleMessage: {
428             // Not supported by InProcessCommandBuffer.
429             VLOG(3) << "kOnConsoleMessage: unsupported op";
430             break;
431           }
432 
433           case fuzzing::InProcessCommandBufferOp::kCacheBlob: {
434             // Not supported by InProcessCommandBuffer.
435             VLOG(3) << "kCacheBlob: unsupported op";
436             break;
437           }
438 
439           case fuzzing::InProcessCommandBufferOp::kOnFenceSyncRelease: {
440             VLOG(3) << "kOnFenceSyncRelease";
441             // GPU Fence not supported by WebGPUDecoderImpl
442             command_buffer_->OnFenceSyncRelease(
443                 op.onfencesyncrelease().release());
444             break;
445           }
446 
447           case fuzzing::InProcessCommandBufferOp::kOnDescheduleUntilFinished: {
448             VLOG(3) << "kOnDescheduleUntilFinished: unsupported op";
449             // Not supported by InProcessCommandBuffer.
450             break;
451           }
452 
453           case fuzzing::InProcessCommandBufferOp::kOnRescheduleAfterFinished: {
454             VLOG(3) << "kOnRescheduleAfterFinished: unsupported op";
455             // Not supported by InProcessCommandBuffer.
456             break;
457           }
458 
459           case fuzzing::InProcessCommandBufferOp::kOnSwapBuffers: {
460             VLOG(3) << "kOnSwapBuffers: unsupported op";
461             // Not supported by InProcessCommandBuffer.
462             break;
463           }
464 
465           case fuzzing::InProcessCommandBufferOp::kScheduleGrContextCleanup: {
466             VLOG(3) << "kScheduleGrContextCleanup";
467             command_buffer_->ScheduleGrContextCleanup();
468             break;
469           }
470 
471           case fuzzing::InProcessCommandBufferOp::kHandleReturnData: {
472             VLOG(3) << "kHandleReturnData: "
473                     << op.handlereturndata().data().size();
474 
475             std::vector<uint8_t> vec;
476             for (unsigned int entry : op.handlereturndata().data()) {
477               vec.push_back(entry);
478             }
479             base::span<uint8_t> data_span(vec);
480             // Passing totally unstructured data leads to hitting validation
481             // errors in webgpu_decoder_impl.cc.
482 
483             // TODO(bookholt): Explore whether it's worth giving some structure
484             // to data sent to HandleReturnData().
485             command_buffer_->HandleReturnData(data_span);
486             break;
487           }
488 
489           case fuzzing::InProcessCommandBufferOp::kGetFeatureInfo: {
490             VLOG(3) << "kGetFeatureInfo";
491             command_buffer_->GetFeatureInfo();
492             break;
493           }
494 
495           case fuzzing::InProcessCommandBufferOp::kGetGpuFeatureInfo: {
496             VLOG(3) << "kGetGpuFeatureInfo";
497             command_buffer_->GetGpuFeatureInfo();
498             break;
499           }
500 
501           case fuzzing::InProcessCommandBufferOp::kGetTransferCacheForTest: {
502             VLOG(3) << "kGetTransferCacheForTest";
503             // TODO(bookholt): Worth a think about refactoring to make use of
504             // the TransferCache.
505             command_buffer_->GetTransferCacheForTest();
506             break;
507           }
508 
509           case fuzzing::InProcessCommandBufferOp::kGetRasterDecoderIdForTest: {
510             VLOG(3) << "kGetRasterDecoderIdForTest";
511             command_buffer_->GetRasterDecoderIdForTest();
512             break;
513           }
514 
515           case fuzzing::InProcessCommandBufferOp::kGetWebGPUDecoderForTest: {
516             VLOG(3) << "kGetWebGPUDecoderForTest";
517             command_buffer_->GetWebGPUDecoderForTest();
518             break;
519           }
520 
521           case fuzzing::InProcessCommandBufferOp::kServiceForTesting: {
522             VLOG(3) << "kServiceForTesting";
523             command_buffer_->service_for_testing();
524             break;
525           }
526 
527           case fuzzing::InProcessCommandBufferOp::kGetSharedImageInterface: {
528             VLOG(3) << "kGetSharedImageInterface: unsupported op";
529             // TODO(bookholt): Worth a think about refactoring to make use of
530             // the gpu::SharedImageInterface.
531             command_buffer_->GetSharedImageInterface();
532             break;
533           }
534 
535           // TODO(bookholt): The fuzzer really shouldn't generate this value,
536           // but it does. Investigate how/why LPM generates this value and
537           // consider tuning to avoid it because it seems like a waste of
538           // performance.
539           case fuzzing::InProcessCommandBufferOp::CMD_BUF_OPS_NOT_SET: {
540             VLOG(3) << "Invalid InProcessCommandBufferOp";
541             break;
542           }
543         }
544         break;
545       }
546       // TODO(bookholt): The fuzzer really shouldn't generate this value, but it
547       // does. Investigate how/why LPM generates this value and consider tuning
548       // to avoid it because it seems like a waste of performance.
549       case fuzzing::Action::ACTION_NOT_SET: {
550         DLOG(WARNING) << "No Action set";
551       } break;
552     }
553     action_index_++;
554   }
555 
556   //  Prepare for next testcase.
557   if (!Reset()) {
558     // See crbug.com/1424591
559     VLOG(1) << "Test case reset failed. Re-initializing graphics.";
560     // Re-initialize the graphics stack to (hopefully!) avoid sync problems.
561     GfxInit();
562     return;
563   }
564 }
565 
566 /* Make CommandBuffer ready for the next test case. */
CmdBufReset()567 bool CmdBufFuzz::CmdBufReset() {
568   // Wait for handling of commands from the previous test case to complete.
569   return cmd_helper_->Finish();
570 }
571 
572 /* Clean up from the last test case and get ready for the next one. */
Reset()573 bool CmdBufFuzz::Reset() {
574   action_index_ = 0;
575   return CmdBufReset();
576 }
577 
578 // Keeper of global fuzzing state
579 CmdBufFuzz* wgpuf_setup;
580 
581 }  // namespace gpu::cmdbuf::fuzzing
582 
583 /* One-time early initialization at process startup. */
LLVMFuzzerInitialize(int * argc,char *** argv)584 extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
585   logging::SetMinLogLevel(logging::LOGGING_VERBOSE);  // Enable logging.
586   CHECK(base::i18n::InitializeICU());  // Unicode support for cmd line parsing.
587   base::CommandLine::Init(*argc, *argv);  // Parse cmd line args.
588   mojo::core::Init();  // Initialize Mojo; probably unnecessary.
589 
590   gpu::cmdbuf::fuzzing::wgpuf_setup = new gpu::cmdbuf::fuzzing::CmdBufFuzz();
591   return 0;
592 }
593 
594 /* Fuzzer entry point. Called on every iteration with a fresh test case. */
DEFINE_PROTO_FUZZER(gpu::cmdbuf::fuzzing::CmdBufSession & session)595 DEFINE_PROTO_FUZZER(gpu::cmdbuf::fuzzing::CmdBufSession& session) {
596   gpu::cmdbuf::fuzzing::wgpuf_setup->RunCommandBuffer(session);
597   return;
598 }
599