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