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