mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-10 05:57:51 +00:00
Reland "fuzzing: Add supportsErrorInjection option to DawnWireServerFuzzer"
This is a reland of f58f69f66b
The whitebox dawn_end2end_tests are updated to link statically against
libdawn_native. This is required because the test link against and use
libdawn_native as sources. It is an error with MSVC to both import and
export symbols from libdawn_native.
Original change's description:
> fuzzing: Add supportsErrorInjection option to DawnWireServerFuzzer
>
> This option will be used by backends that support error injection so
> that errors can be injected into a "clean" corpus to generate a seed
> corpus with good examples of injected error conditions.
>
> Bug: dawn:295
> Change-Id: I837acdde6dd4274adb56edf8e4307427f8d6333b
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/14681
> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
> Commit-Queue: Austin Eng <enga@chromium.org>
Bug: dawn:295
Change-Id: Ifa092d28aa7ac57cfb197aa4daeb8408f8036d4a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/14820
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
committed by
Commit Bot service account
parent
d08a14b709
commit
470921fe46
@@ -15,11 +15,14 @@
|
||||
#include "DawnWireServerFuzzer.h"
|
||||
|
||||
#include "common/Assert.h"
|
||||
#include "common/Log.h"
|
||||
#include "common/SystemUtils.h"
|
||||
#include "dawn/dawn_proc.h"
|
||||
#include "dawn/webgpu_cpp.h"
|
||||
#include "dawn_native/DawnNative.h"
|
||||
#include "dawn_wire/WireServer.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
@@ -42,6 +45,9 @@ namespace {
|
||||
|
||||
WGPUProcDeviceCreateSwapChain sOriginalDeviceCreateSwapChain = nullptr;
|
||||
|
||||
std::string sInjectedErrorTestcaseOutDir;
|
||||
uint64_t sOutputFileNumber = 0;
|
||||
|
||||
WGPUSwapChain ErrorDeviceCreateSwapChain(WGPUDevice device, const WGPUSwapChainDescriptor*) {
|
||||
WGPUSwapChainDescriptor desc;
|
||||
desc.nextInChain = nullptr;
|
||||
@@ -53,7 +59,61 @@ namespace {
|
||||
|
||||
} // namespace
|
||||
|
||||
int DawnWireServerFuzzer::Run(const uint8_t* data, size_t size, MakeDeviceFn MakeDevice) {
|
||||
int DawnWireServerFuzzer::Initialize(int* argc, char*** argv) {
|
||||
ASSERT(argc != nullptr && argv != nullptr);
|
||||
|
||||
// The first argument (the fuzzer binary) always stays the same.
|
||||
int argcOut = 1;
|
||||
|
||||
for (int i = 1; i < *argc; ++i) {
|
||||
constexpr const char kInjectedErrorTestcaseDirArg[] = "--injected-error-testcase-dir=";
|
||||
if (strstr((*argv)[i], kInjectedErrorTestcaseDirArg) == (*argv)[i]) {
|
||||
sInjectedErrorTestcaseOutDir = (*argv)[i] + strlen(kInjectedErrorTestcaseDirArg);
|
||||
const char* sep = GetPathSeparator();
|
||||
if (sInjectedErrorTestcaseOutDir.back() != *sep) {
|
||||
sInjectedErrorTestcaseOutDir += sep;
|
||||
}
|
||||
// Log so that it's clear the fuzzer found the argument.
|
||||
dawn::InfoLog() << "Generating injected errors, output dir is: \""
|
||||
<< sInjectedErrorTestcaseOutDir << "\"";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Move any unconsumed arguments to the next slot in the output array.
|
||||
(*argv)[argcOut++] = (*argv)[i];
|
||||
}
|
||||
|
||||
// Write the argument count
|
||||
*argc = argcOut;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DawnWireServerFuzzer::Run(const uint8_t* data,
|
||||
size_t size,
|
||||
MakeDeviceFn MakeDevice,
|
||||
bool supportsErrorInjection) {
|
||||
bool didInjectError = false;
|
||||
|
||||
if (supportsErrorInjection) {
|
||||
dawn_native::EnableErrorInjector();
|
||||
|
||||
// Clear the error injector since it has the previous run's call counts.
|
||||
dawn_native::ClearErrorInjector();
|
||||
|
||||
// If we're outputing testcases with injected errors, we run the fuzzer on the original
|
||||
// input data, and prepend injected errors to it. In the case, where we're NOT outputing,
|
||||
// we use the first bytes as the injected error index.
|
||||
if (sInjectedErrorTestcaseOutDir.empty() && size >= sizeof(uint64_t)) {
|
||||
// Otherwise, use the first bytes as the injected error index.
|
||||
dawn_native::InjectErrorAt(*reinterpret_cast<const uint64_t*>(data));
|
||||
didInjectError = true;
|
||||
|
||||
data += sizeof(uint64_t);
|
||||
size -= sizeof(uint64_t);
|
||||
}
|
||||
}
|
||||
|
||||
DawnProcTable procs = dawn_native::GetProcs();
|
||||
|
||||
// Swapchains receive a pointer to an implementation. The fuzzer will pass garbage in so we
|
||||
@@ -67,7 +127,11 @@ int DawnWireServerFuzzer::Run(const uint8_t* data, size_t size, MakeDeviceFn Mak
|
||||
|
||||
std::unique_ptr<dawn_native::Instance> instance = std::make_unique<dawn_native::Instance>();
|
||||
wgpu::Device device = MakeDevice(instance.get());
|
||||
ASSERT(device);
|
||||
if (!device) {
|
||||
// We should only ever fail device creation if an error was injected.
|
||||
ASSERT(didInjectError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DevNull devNull;
|
||||
dawn_wire::WireServerDescriptor serverDesc = {};
|
||||
@@ -87,5 +151,27 @@ int DawnWireServerFuzzer::Run(const uint8_t* data, size_t size, MakeDeviceFn Mak
|
||||
device = nullptr;
|
||||
instance = nullptr;
|
||||
|
||||
// If we support error injection, and an output directory was provided, output copies of the
|
||||
// original testcase data, prepended with the injected error index.
|
||||
if (supportsErrorInjection && !sInjectedErrorTestcaseOutDir.empty()) {
|
||||
const uint64_t injectedCallCount = dawn_native::AcquireErrorInjectorCallCount();
|
||||
|
||||
auto WriteTestcase = [&](uint64_t i) {
|
||||
std::ofstream outFile(
|
||||
sInjectedErrorTestcaseOutDir + "injected_error_testcase_" +
|
||||
std::to_string(sOutputFileNumber++),
|
||||
std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
|
||||
outFile.write(reinterpret_cast<const char*>(&i), sizeof(i));
|
||||
outFile.write(reinterpret_cast<const char*>(data), size);
|
||||
};
|
||||
|
||||
for (uint64_t i = 0; i < injectedCallCount; ++i) {
|
||||
WriteTestcase(i);
|
||||
}
|
||||
|
||||
// Also add a testcase where the injected error is so large no errors should occur.
|
||||
WriteTestcase(std::numeric_limits<uint64_t>::max());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user