Revert "fuzzing: Add supportsErrorInjection option to DawnWireServerFuzzer"
This reverts commit f58f69f66b
.
Reason for revert: This breaks the MSVC build because the whitebox end2end tests try to both import and export the error injector 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>
TBR=cwallez@chromium.org,kainino@chromium.org,enga@chromium.org
Change-Id: I14a15fcd094d431cbb8a29d5642a4a7fe6a11f4c
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: dawn:295
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/14741
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
2cb76ab598
commit
87d3138158
|
@ -4,23 +4,17 @@
|
||||||
|
|
||||||
The `dawn_wire_server_and_frontend_fuzzer` sets up Dawn using the Null backend, and passes inputs to the wire server. This fuzzes the `dawn_wire` deserialization, as well as Dawn's frontend validation.
|
The `dawn_wire_server_and_frontend_fuzzer` sets up Dawn using the Null backend, and passes inputs to the wire server. This fuzzes the `dawn_wire` deserialization, as well as Dawn's frontend validation.
|
||||||
|
|
||||||
## `dawn_wire_server_and_vulkan_backend_fuzzer`
|
|
||||||
|
|
||||||
The `dawn_wire_server_and_vulkan_backend_fuzzer` is like `dawn_wire_server_and_frontend_fuzzer` but it runs using a Vulkan CPU backend such as Swiftshader. This fuzzer supports error injection by using the first bytes of the fuzzing input as a Vulkan call index for which to mock a failure.
|
|
||||||
|
|
||||||
## Updating the Seed Corpus
|
## Updating the Seed Corpus
|
||||||
|
|
||||||
Using a seed corpus significantly improves the efficiency of fuzzing. Dawn's fuzzers use interesting testcases discovered in previous fuzzing runs to seed future runs. Fuzzing can be further improved by using Dawn tests as a example of API usage which allows the fuzzer to quickly discover and use new API entrypoints and usage patterns.
|
Using a seed corpus significantly improves the efficiency of fuzzing. Dawn's fuzzers use interesting testcases discovered in previous fuzzing runs to seed future runs. Fuzzing can be further improved by using Dawn tests as a example of API usage which allows the fuzzer to quickly discover and use new API entrypoints and usage patterns.
|
||||||
|
|
||||||
The script [update_fuzzer_seed_corpus.sh](../scripts/update_fuzzer_seed_corpus.sh) can be used to capture a trace while running Dawn tests, and upload it to the existing fuzzer seed corpus. It does the following steps:
|
The script [update_fuzzer_seed_corpus.sh](../scripts/update_fuzzer_seed_corpus.sh) can be used to capture a trace while running Dawn tests, and upload it to the existing fuzzzer seed corpus.
|
||||||
1. Builds the provided test and fuzzer targets.
|
|
||||||
2. Runs the provided test target with `--use-wire --wire-trace-dir=tmp_dir1 [additional_test_args]` to dump traces of the tests.
|
|
||||||
3. Generates one variant of each trace for every possible error index, by running the fuzzer target with `--injected-error-testcase-dir=tmp_dir2 ...`.
|
|
||||||
4. Minimizes all testcases by running the fuzzer target with `-merge=1 tmp_dir3 tmp_dir1 tmp_dir2`.
|
|
||||||
|
|
||||||
To run the script:
|
To run the script:
|
||||||
1. You must be in a Chromium checkout using the GN arg `use_libfuzzer=true`
|
1. Make sure gcloud is installed: https://g3doc.corp.google.com/cloud/sdk/g3doc/index.md?cl=head
|
||||||
2. Run `./third_party/dawn/scripts/update_fuzzer_seed_corpus.sh <out_dir> <fuzzer> <test> [additional_test_args]`.
|
2. Login with @google.com credentials: `gcloud auth login`
|
||||||
|
3. You must be in a Chromium checkout using the GN arg `use_libfuzzer=true`
|
||||||
|
4. Run `./third_party/dawn/scripts/update_fuzzer_seed_corpus.sh <out_dir> <fuzzer> <test>`.
|
||||||
|
|
||||||
Example: `./third_party/dawn/scripts/update_fuzzer_seed_corpus.sh out/fuzz dawn_wire_server_and_vulkan_backend_fuzzer dawn_end2end_tests --gtest_filter=*Vulkan`
|
Example: `./third_party/dawn/scripts/update_fuzzer_seed_corpus.sh out/fuzz dawn_wire_server_and_frontend_fuzzer dawn_end2end_tests`
|
||||||
3. The script will print instructions for testing, and then uploading new inputs. Please, only upload inputs after testing the fuzzer with new inputs, and verifying there is a meaningful change in coverage. Uploading requires [gcloud](https://g3doc.corp.google.com/cloud/sdk/g3doc/index.md?cl=head) to be logged in with @google.com credentials: `gcloud auth login`.
|
5. The script will print instructions for testing, and then uploading new inputs. Please, only upload inputs after testing the fuzzer with new inputs, and verifying there is a meaningful change in coverage.
|
||||||
|
|
|
@ -20,39 +20,29 @@
|
||||||
# Exit if anything fails
|
# Exit if anything fails
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ "$#" -lt 3 ]; then
|
if [ "$#" -ne 3 ]; then
|
||||||
cat << EOF
|
cat << EOF
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
$0 <out_dir> <fuzzer_name> <test_name> [additional_test_args...]
|
$0 <out_dir> <fuzzer_name> <test_name>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
$0 out/fuzz dawn_wire_server_and_vulkan_backend_fuzzer dawn_end2end_tests --gtest_filter=*Vulkan
|
$0 out/fuzz dawn_wire_server_and_frontend_fuzzer dawn_end2end_tests
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
all_args=("$@")
|
|
||||||
out_dir=$1
|
out_dir=$1
|
||||||
fuzzer_name=$2
|
fuzzer_name=$2
|
||||||
test_name=$3
|
test_name=$3
|
||||||
additional_test_args=("${all_args[@]:3}")
|
|
||||||
|
|
||||||
testcase_dir="/tmp/testcases/${fuzzer_name}/"
|
testcase_dir="/tmp/testcases/${fuzzer_name}/"
|
||||||
injected_error_testcase_dir="/tmp/testcases/${fuzzer_name}_injected/"
|
|
||||||
minimized_testcase_dir="/tmp/testcases/${fuzzer_name}_minimized/"
|
minimized_testcase_dir="/tmp/testcases/${fuzzer_name}_minimized/"
|
||||||
|
|
||||||
# Print commands so it's clear what is being executed
|
|
||||||
set -x
|
|
||||||
|
|
||||||
# Make a directory for temporarily storing testcases
|
# Make a directory for temporarily storing testcases
|
||||||
mkdir -p "$testcase_dir"
|
mkdir -p "$testcase_dir"
|
||||||
|
|
||||||
# Make an empty directory for temporarily storing testcases with injected errors
|
|
||||||
rm -rf "$injected_error_testcase_dir"
|
|
||||||
mkdir -p "$injected_error_testcase_dir"
|
|
||||||
|
|
||||||
# Make an empty directory for temporarily storing minimized testcases
|
# Make an empty directory for temporarily storing minimized testcases
|
||||||
rm -rf "$minimized_testcase_dir"
|
rm -rf "$minimized_testcase_dir"
|
||||||
mkdir -p "$minimized_testcase_dir"
|
mkdir -p "$minimized_testcase_dir"
|
||||||
|
@ -64,16 +54,10 @@ fuzzer_binary="${out_dir}/${fuzzer_name}"
|
||||||
test_binary="${out_dir}/${test_name}"
|
test_binary="${out_dir}/${test_name}"
|
||||||
|
|
||||||
# Run the test binary
|
# Run the test binary
|
||||||
$test_binary --use-wire --wire-trace-dir="$testcase_dir" $additional_test_args
|
$test_binary --use-wire --wire-trace-dir="$testcase_dir"
|
||||||
|
|
||||||
# Run the fuzzer over the testcases to inject errors
|
# Run the fuzzer to minimize the corpus
|
||||||
$fuzzer_binary --injected-error-testcase-dir="$injected_error_testcase_dir" -runs=0 "$testcase_dir"
|
$fuzzer_binary -merge=1 "$minimized_testcase_dir" "$testcase_dir"
|
||||||
|
|
||||||
# Run the fuzzer to minimize the testcases + injected errors
|
|
||||||
$fuzzer_binary -merge=1 "$minimized_testcase_dir" "$injected_error_testcase_dir" "$testcase_dir"
|
|
||||||
|
|
||||||
# Turn off command printing
|
|
||||||
set +x
|
|
||||||
|
|
||||||
if [ -z "$(ls -A $minimized_testcase_dir)" ]; then
|
if [ -z "$(ls -A $minimized_testcase_dir)" ]; then
|
||||||
cat << EOF
|
cat << EOF
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include "dawn_native/ErrorInjector.h"
|
#include "dawn_native/ErrorInjector.h"
|
||||||
|
|
||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
#include "dawn_native/DawnNative.h"
|
|
||||||
|
|
||||||
namespace dawn_native {
|
namespace dawn_native {
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,12 @@ namespace dawn_native {
|
||||||
bool injected;
|
bool injected;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void EnableErrorInjector();
|
||||||
|
void DisableErrorInjector();
|
||||||
|
void ClearErrorInjector();
|
||||||
|
|
||||||
bool ErrorInjectorEnabled();
|
bool ErrorInjectorEnabled();
|
||||||
|
uint64_t AcquireErrorInjectorCallCount();
|
||||||
|
|
||||||
bool ShouldInjectError();
|
bool ShouldInjectError();
|
||||||
|
|
||||||
|
@ -43,6 +48,8 @@ namespace dawn_native {
|
||||||
return MaybeInjectError(errorTypes...);
|
return MaybeInjectError(errorTypes...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InjectErrorAt(uint64_t index);
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
|
||||||
#if defined(DAWN_ENABLE_ERROR_INJECTION)
|
#if defined(DAWN_ENABLE_ERROR_INJECTION)
|
||||||
|
|
|
@ -45,10 +45,6 @@ namespace {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
return DawnSPIRVCrossFuzzer::Run(data, size, GLSLFastFuzzTask);
|
return DawnSPIRVCrossFuzzer::Run(data, size, GLSLFastFuzzTask);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,10 +51,6 @@ namespace {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
return DawnSPIRVCrossFuzzer::Run(data, size, FuzzTask);
|
return DawnSPIRVCrossFuzzer::Run(data, size, FuzzTask);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,10 +44,6 @@ namespace {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
return DawnSPIRVCrossFuzzer::Run(data, size, FuzzTask);
|
return DawnSPIRVCrossFuzzer::Run(data, size, FuzzTask);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,6 @@
|
||||||
|
|
||||||
#include "spvc/spvc.hpp"
|
#include "spvc/spvc.hpp"
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
shaderc_spvc::Context context;
|
shaderc_spvc::Context context;
|
||||||
if (!context.IsValid()) {
|
if (!context.IsValid()) {
|
||||||
|
|
|
@ -18,10 +18,6 @@
|
||||||
|
|
||||||
#include "spvc/spvc.hpp"
|
#include "spvc/spvc.hpp"
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
shaderc_spvc::Context context;
|
shaderc_spvc::Context context;
|
||||||
if (!context.IsValid()) {
|
if (!context.IsValid()) {
|
||||||
|
|
|
@ -18,10 +18,6 @@
|
||||||
|
|
||||||
#include "spvc/spvc.hpp"
|
#include "spvc/spvc.hpp"
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
shaderc_spvc::Context context;
|
shaderc_spvc::Context context;
|
||||||
if (!context.IsValid()) {
|
if (!context.IsValid()) {
|
||||||
|
|
|
@ -17,28 +17,21 @@
|
||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
#include "dawn_native/DawnNative.h"
|
#include "dawn_native/DawnNative.h"
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
|
|
||||||
return DawnWireServerFuzzer::Initialize(argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
return DawnWireServerFuzzer::Run(
|
return DawnWireServerFuzzer::Run(data, size, [](dawn_native::Instance* instance) {
|
||||||
data, size,
|
instance->DiscoverDefaultAdapters();
|
||||||
[](dawn_native::Instance* instance) {
|
|
||||||
instance->DiscoverDefaultAdapters();
|
|
||||||
|
|
||||||
std::vector<dawn_native::Adapter> adapters = instance->GetAdapters();
|
std::vector<dawn_native::Adapter> adapters = instance->GetAdapters();
|
||||||
|
|
||||||
wgpu::Device nullDevice;
|
wgpu::Device nullDevice;
|
||||||
for (dawn_native::Adapter adapter : adapters) {
|
for (dawn_native::Adapter adapter : adapters) {
|
||||||
if (adapter.GetBackendType() == dawn_native::BackendType::Null) {
|
if (adapter.GetBackendType() == dawn_native::BackendType::Null) {
|
||||||
nullDevice = wgpu::Device::Acquire(adapter.CreateDevice());
|
nullDevice = wgpu::Device::Acquire(adapter.CreateDevice());
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(nullDevice.Get() != nullptr);
|
ASSERT(nullDevice.Get() != nullptr);
|
||||||
return nullDevice;
|
return nullDevice;
|
||||||
},
|
});
|
||||||
false /* supportsErrorInjection */);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,29 +14,25 @@
|
||||||
|
|
||||||
#include "DawnWireServerFuzzer.h"
|
#include "DawnWireServerFuzzer.h"
|
||||||
|
|
||||||
|
#include "common/Assert.h"
|
||||||
#include "dawn_native/DawnNative.h"
|
#include "dawn_native/DawnNative.h"
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
|
|
||||||
return DawnWireServerFuzzer::Initialize(argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
return DawnWireServerFuzzer::Run(
|
return DawnWireServerFuzzer::Run(data, size, [](dawn_native::Instance* instance) {
|
||||||
data, size,
|
instance->DiscoverDefaultAdapters();
|
||||||
[](dawn_native::Instance* instance) {
|
|
||||||
instance->DiscoverDefaultAdapters();
|
|
||||||
|
|
||||||
std::vector<dawn_native::Adapter> adapters = instance->GetAdapters();
|
std::vector<dawn_native::Adapter> adapters = instance->GetAdapters();
|
||||||
|
|
||||||
wgpu::Device device;
|
wgpu::Device device;
|
||||||
for (dawn_native::Adapter adapter : adapters) {
|
for (dawn_native::Adapter adapter : adapters) {
|
||||||
if (adapter.GetBackendType() == dawn_native::BackendType::Vulkan &&
|
if (adapter.GetBackendType() == dawn_native::BackendType::Vulkan &&
|
||||||
adapter.GetDeviceType() == dawn_native::DeviceType::CPU) {
|
adapter.GetDeviceType() == dawn_native::DeviceType::CPU) {
|
||||||
device = wgpu::Device::Acquire(adapter.CreateDevice());
|
device = wgpu::Device::Acquire(adapter.CreateDevice());
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return device;
|
}
|
||||||
},
|
|
||||||
true /* supportsErrorInjection */);
|
ASSERT(device.Get() != nullptr);
|
||||||
|
return device;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,11 @@
|
||||||
#include "DawnWireServerFuzzer.h"
|
#include "DawnWireServerFuzzer.h"
|
||||||
|
|
||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
#include "common/Log.h"
|
|
||||||
#include "common/SystemUtils.h"
|
|
||||||
#include "dawn/dawn_proc.h"
|
#include "dawn/dawn_proc.h"
|
||||||
#include "dawn/webgpu_cpp.h"
|
#include "dawn/webgpu_cpp.h"
|
||||||
#include "dawn_native/DawnNative.h"
|
#include "dawn_native/DawnNative.h"
|
||||||
#include "dawn_wire/WireServer.h"
|
#include "dawn_wire/WireServer.h"
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -45,9 +42,6 @@ namespace {
|
||||||
|
|
||||||
WGPUProcDeviceCreateSwapChain sOriginalDeviceCreateSwapChain = nullptr;
|
WGPUProcDeviceCreateSwapChain sOriginalDeviceCreateSwapChain = nullptr;
|
||||||
|
|
||||||
std::string sInjectedErrorTestcaseOutDir;
|
|
||||||
uint64_t sOutputFileNumber = 0;
|
|
||||||
|
|
||||||
WGPUSwapChain ErrorDeviceCreateSwapChain(WGPUDevice device, const WGPUSwapChainDescriptor*) {
|
WGPUSwapChain ErrorDeviceCreateSwapChain(WGPUDevice device, const WGPUSwapChainDescriptor*) {
|
||||||
WGPUSwapChainDescriptor desc;
|
WGPUSwapChainDescriptor desc;
|
||||||
desc.nextInChain = nullptr;
|
desc.nextInChain = nullptr;
|
||||||
|
@ -59,61 +53,7 @@ namespace {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int DawnWireServerFuzzer::Initialize(int* argc, char*** argv) {
|
int DawnWireServerFuzzer::Run(const uint8_t* data, size_t size, MakeDeviceFn MakeDevice) {
|
||||||
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();
|
DawnProcTable procs = dawn_native::GetProcs();
|
||||||
|
|
||||||
// Swapchains receive a pointer to an implementation. The fuzzer will pass garbage in so we
|
// Swapchains receive a pointer to an implementation. The fuzzer will pass garbage in so we
|
||||||
|
@ -127,11 +67,7 @@ int DawnWireServerFuzzer::Run(const uint8_t* data,
|
||||||
|
|
||||||
std::unique_ptr<dawn_native::Instance> instance = std::make_unique<dawn_native::Instance>();
|
std::unique_ptr<dawn_native::Instance> instance = std::make_unique<dawn_native::Instance>();
|
||||||
wgpu::Device device = MakeDevice(instance.get());
|
wgpu::Device device = MakeDevice(instance.get());
|
||||||
if (!device) {
|
ASSERT(device);
|
||||||
// We should only ever fail device creation if an error was injected.
|
|
||||||
ASSERT(didInjectError);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DevNull devNull;
|
DevNull devNull;
|
||||||
dawn_wire::WireServerDescriptor serverDesc = {};
|
dawn_wire::WireServerDescriptor serverDesc = {};
|
||||||
|
@ -151,27 +87,5 @@ int DawnWireServerFuzzer::Run(const uint8_t* data,
|
||||||
device = nullptr;
|
device = nullptr;
|
||||||
instance = 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,6 @@ namespace DawnWireServerFuzzer {
|
||||||
|
|
||||||
using MakeDeviceFn = std::function<wgpu::Device(dawn_native::Instance*)>;
|
using MakeDeviceFn = std::function<wgpu::Device(dawn_native::Instance*)>;
|
||||||
|
|
||||||
int Initialize(int* argc, char*** argv);
|
int Run(const uint8_t* data, size_t size, MakeDeviceFn MakeDevice);
|
||||||
|
|
||||||
int Run(const uint8_t* data, size_t size, MakeDeviceFn MakeDevice, bool supportsErrorInjection);
|
|
||||||
|
|
||||||
} // namespace DawnWireServerFuzzer
|
} // namespace DawnWireServerFuzzer
|
||||||
|
|
|
@ -17,17 +17,11 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv);
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
if (LLVMFuzzerInitialize(&argc, &argv)) {
|
|
||||||
std::cerr << "Failed to initialize fuzzer target" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
std::cout << "Usage: <standalone reproducer> [options] FILE" << std::endl;
|
std::cout << "Usage: <standalone reproducer> FILE" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,14 +161,6 @@ namespace dawn_native {
|
||||||
|
|
||||||
// Backdoor to get the order of the ProcMap for testing
|
// Backdoor to get the order of the ProcMap for testing
|
||||||
DAWN_NATIVE_EXPORT std::vector<const char*> GetProcMapNamesForTesting();
|
DAWN_NATIVE_EXPORT std::vector<const char*> GetProcMapNamesForTesting();
|
||||||
|
|
||||||
// ErrorInjector functions used for testing only. Defined in dawn_native/ErrorInjector.cpp
|
|
||||||
DAWN_NATIVE_EXPORT void EnableErrorInjector();
|
|
||||||
DAWN_NATIVE_EXPORT void DisableErrorInjector();
|
|
||||||
DAWN_NATIVE_EXPORT void ClearErrorInjector();
|
|
||||||
DAWN_NATIVE_EXPORT uint64_t AcquireErrorInjectorCallCount();
|
|
||||||
DAWN_NATIVE_EXPORT void InjectErrorAt(uint64_t index);
|
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
|
||||||
#endif // DAWNNATIVE_DAWNNATIVE_H_
|
#endif // DAWNNATIVE_DAWNNATIVE_H_
|
||||||
|
|
Loading…
Reference in New Issue