blob: f1d6c7a6b9353ba024a7730eb1ea2ec2a66fffe5 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <iostream>
#include <iterator>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "base/compiler_specific.h"
#include "base/containers/span.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_util.h"
#include "base/types/id_type.h"
#include "base/unguessable_token.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/content_settings/core/common/content_settings_pattern.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/local_surface_id.h"
#include "gpu/command_buffer/common/command_buffer.h"
#include "gpu/command_buffer/common/context_creation_attribs.h"
#include "gpu/ipc/common/gpu_param_traits_macros.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_platform_file.h"
#include "ipc/ipc_sync_channel.h"
#include "ipc/ipc_sync_message.h"
#include "media/gpu/ipc/common/media_param_traits.h"
#include "ppapi/buildflags/buildflags.h"
#include "printing/mojom/print.mojom-shared.h"
#include "services/device/public/mojom/screen_orientation_lock_types.mojom-shared.h"
#include "third_party/blink/public/common/page_state/page_state.h"
#include "third_party/blink/public/mojom/widget/device_emulation_params.mojom-shared.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "tools/ipc_fuzzer/fuzzer/fuzzer.h"
#include "tools/ipc_fuzzer/fuzzer/rand_util.h"
#include "tools/ipc_fuzzer/message_lib/message_cracker.h"
#include "tools/ipc_fuzzer/message_lib/message_file.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/range/range.h"
#include "ui/gl/gpu_preference.h"
#include "ui/latency/latency_info.h"
#if BUILDFLAG(IS_POSIX)
#include <unistd.h>
#endif
// First include of all message files to provide basic types.
#include "tools/ipc_fuzzer/message_lib/all_messages.h"
#include "tools/ipc_fuzzer/message_lib/all_message_null_macros.h"
namespace IPC {
class Message;
} // namespace IPC
namespace {
// For breaking deep recursion.
int g_depth = 0;
} // namespace
namespace ipc_fuzzer {
FuzzerFunctionVector g_function_vector;
bool Fuzzer::ShouldGenerate() {
return false;
}
// Partially-specialized class that knows how to handle a given type.
template <class P>
struct FuzzTraits {
static bool Fuzz(P* p, Fuzzer *fuzzer) {
// This is the catch-all for types we don't have enough information
// to generate.
std::cerr << "Can't handle " << PRETTY_FUNCTION << "\n";
return false;
}
};
// Template function to invoke partially-specialized class method.
template <class P>
static bool FuzzParam(P* p, Fuzzer* fuzzer) {
return FuzzTraits<P>::Fuzz(p, fuzzer);
}
template <class P>
static bool FuzzParamArray(P* p, size_t length, Fuzzer* fuzzer) {
for (size_t i = 0; i < length; i++, p++) {
if (!FuzzTraits<P>::Fuzz(p, fuzzer))
return false;
}
return true;
}
// Specializations to generate primitive types.
template <>
struct FuzzTraits<bool> {
static bool Fuzz(bool* p, Fuzzer* fuzzer) {
fuzzer->FuzzBool(p);
return true;
}
};
template <>
struct FuzzTraits<int> {
static bool Fuzz(int* p, Fuzzer* fuzzer) {
fuzzer->FuzzInt(p);
return true;
}
};
template <>
struct FuzzTraits<unsigned int> {
static bool Fuzz(unsigned int* p, Fuzzer* fuzzer) {
fuzzer->FuzzInt(reinterpret_cast<int*>(p));
return true;
}
};
template <>
struct FuzzTraits<long> {
static bool Fuzz(long* p, Fuzzer* fuzzer) {
fuzzer->FuzzLong(p);
return true;
}
};
template <>
struct FuzzTraits<unsigned long> {
static bool Fuzz(unsigned long* p, Fuzzer* fuzzer) {
fuzzer->FuzzLong(reinterpret_cast<long*>(p));
return true;
}
};
template <>
struct FuzzTraits<long long> {
static bool Fuzz(long long* p, Fuzzer* fuzzer) {
fuzzer->FuzzInt64(reinterpret_cast<int64_t*>(p));
return true;
}
};
template <>
struct FuzzTraits<unsigned long long> {
static bool Fuzz(unsigned long long* p, Fuzzer* fuzzer) {
fuzzer->FuzzInt64(reinterpret_cast<int64_t*>(p));
return true;
}
};
template <>
struct FuzzTraits<short> {
static bool Fuzz(short* p, Fuzzer* fuzzer) {
fuzzer->FuzzUInt16(reinterpret_cast<uint16_t*>(p));
return true;
}
};
template <>
struct FuzzTraits<unsigned short> {
static bool Fuzz(unsigned short* p, Fuzzer* fuzzer) {
fuzzer->FuzzUInt16(reinterpret_cast<uint16_t*>(p));
return true;
}
};
template <>
struct FuzzTraits<char> {
static bool Fuzz(char* p, Fuzzer* fuzzer) {
fuzzer->FuzzUChar(reinterpret_cast<unsigned char*>(p));
return true;
}
};
template <>
struct FuzzTraits<signed char> {
static bool Fuzz(signed char* p, Fuzzer* fuzzer) {
fuzzer->FuzzUChar(reinterpret_cast<unsigned char*>(p));
return true;
}
};
template <>
struct FuzzTraits<unsigned char> {
static bool Fuzz(unsigned char* p, Fuzzer* fuzzer) {
fuzzer->FuzzUChar(p);
return true;
}
};
template <>
struct FuzzTraits<wchar_t> {
static bool Fuzz(wchar_t* p, Fuzzer* fuzzer) {
fuzzer->FuzzWChar(p);
return true;
}
};
template <>
struct FuzzTraits<float> {
static bool Fuzz(float* p, Fuzzer* fuzzer) {
fuzzer->FuzzFloat(p);
return true;
}
};
template <>
struct FuzzTraits<double> {
static bool Fuzz(double* p, Fuzzer* fuzzer) {
fuzzer->FuzzDouble(p);
return true;
}
};
template <>
struct FuzzTraits<std::string> {
static bool Fuzz(std::string* p, Fuzzer* fuzzer) {
fuzzer->FuzzString(p);
return true;
}
};
template <>
struct FuzzTraits<std::u16string> {
static bool Fuzz(std::u16string* p, Fuzzer* fuzzer) {
fuzzer->FuzzString16(p);
return true;
}
};
// Specializations for tuples.
template <>
struct FuzzTraits<std::tuple<>> {
static bool Fuzz(std::tuple<>* p, Fuzzer* fuzzer) { return true; }
};
template <class A>
struct FuzzTraits<std::tuple<A>> {
static bool Fuzz(std::tuple<A>* p, Fuzzer* fuzzer) {
return FuzzParam(&std::get<0>(*p), fuzzer);
}
};
template <class A, class B>
struct FuzzTraits<std::tuple<A, B>> {
static bool Fuzz(std::tuple<A, B>* p, Fuzzer* fuzzer) {
return FuzzParam(&std::get<0>(*p), fuzzer) &&
FuzzParam(&std::get<1>(*p), fuzzer);
}
};
template <class A, class B, class C>
struct FuzzTraits<std::tuple<A, B, C>> {
static bool Fuzz(std::tuple<A, B, C>* p, Fuzzer* fuzzer) {
return FuzzParam(&std::get<0>(*p), fuzzer) &&
FuzzParam(&std::get<1>(*p), fuzzer) &&
FuzzParam(&std::get<2>(*p), fuzzer);
}
};
template <class A, class B, class C, class D>
struct FuzzTraits<std::tuple<A, B, C, D>> {
static bool Fuzz(std::tuple<A, B, C, D>* p, Fuzzer* fuzzer) {
return FuzzParam(&std::get<0>(*p), fuzzer) &&
FuzzParam(&std::get<1>(*p), fuzzer) &&
FuzzParam(&std::get<2>(*p), fuzzer) &&
FuzzParam(&std::get<3>(*p), fuzzer);
}
};
template <class A, class B, class C, class D, class E>
struct FuzzTraits<std::tuple<A, B, C, D, E>> {
static bool Fuzz(std::tuple<A, B, C, D, E>* p, Fuzzer* fuzzer) {
return FuzzParam(&std::get<0>(*p), fuzzer) &&
FuzzParam(&std::get<1>(*p), fuzzer) &&
FuzzParam(&std::get<2>(*p), fuzzer) &&
FuzzParam(&std::get<3>(*p), fuzzer) &&
FuzzParam(&std::get<4>(*p), fuzzer);
}
};
// Specializations for containers.
template <class A>
struct FuzzTraits<std::vector<A> > {
static bool Fuzz(std::vector<A>* p, Fuzzer* fuzzer) {
++g_depth;
size_t count = p->size();
if (fuzzer->ShouldGenerate()) {
count = g_depth > 3 ? 0 : RandElementCount();
p->resize(count);
}
for (size_t i = 0; i < count; ++i) {
if (!FuzzParam(&p->at(i), fuzzer)) {
--g_depth;
return false;
}
}
--g_depth;
return true;
}
};
template <class A>
struct FuzzTraits<std::set<A> > {
static bool Fuzz(std::set<A>* p, Fuzzer* fuzzer) {
if (!fuzzer->ShouldGenerate()) {
std::set<A> result;
typename std::set<A>::iterator it;
for (it = p->begin(); it != p->end(); ++it) {
A item = *it;
if (!FuzzParam(&item, fuzzer))
return false;
result.insert(item);
}
*p = result;
return true;
}
static int g_depth = 0;
size_t count = ++g_depth > 3 ? 0 : RandElementCount();
A a;
for (size_t i = 0; i < count; ++i) {
if (!FuzzParam(&a, fuzzer)) {
--g_depth;
return false;
}
p->insert(a);
}
--g_depth;
return true;
}
};
template <class A, class B>
struct FuzzTraits<std::map<A, B> > {
static bool Fuzz(std::map<A, B>* p, Fuzzer* fuzzer) {
if (!fuzzer->ShouldGenerate()) {
typename std::map<A, B>::iterator it;
for (it = p->begin(); it != p->end(); ++it) {
if (!FuzzParam(&it->second, fuzzer))
return false;
}
return true;
}
static int g_depth = 0;
size_t count = ++g_depth > 3 ? 0 : RandElementCount();
std::pair<A, B> place_holder;
for (size_t i = 0; i < count; ++i) {
if (!FuzzParam(&place_holder, fuzzer)) {
--g_depth;
return false;
}
p->insert(place_holder);
}
--g_depth;
return true;
}
};
template <class A, class B, class C, class D>
struct FuzzTraits<std::map<A, B, C, D>> {
static bool Fuzz(std::map<A, B, C, D>* p, Fuzzer* fuzzer) {
if (!fuzzer->ShouldGenerate()) {
typename std::map<A, B, C, D>::iterator it;
for (it = p->begin(); it != p->end(); ++it) {
if (!FuzzParam(&it->second, fuzzer))
return false;
}
return true;
}
static int g_depth = 0;
size_t count = ++g_depth > 3 ? 0 : RandElementCount();
std::pair<A, B> place_holder;
for (size_t i = 0; i < count; ++i) {
if (!FuzzParam(&place_holder, fuzzer)) {
--g_depth;
return false;
}
p->insert(place_holder);
}
--g_depth;
return true;
}
};
template <class A, class B>
struct FuzzTraits<std::pair<A, B> > {
static bool Fuzz(std::pair<A, B>* p, Fuzzer* fuzzer) {
return
FuzzParam(&p->first, fuzzer) &&
FuzzParam(&p->second, fuzzer);
}
};
// Specializations for hand-coded types.
template <>
struct FuzzTraits<base::FilePath> {
static bool Fuzz(base::FilePath* p, Fuzzer* fuzzer) {
if (!fuzzer->ShouldGenerate()) {
base::FilePath::StringType path = p->value();
if(!FuzzParam(&path, fuzzer))
return false;
*p = base::FilePath(path);
return true;
}
const char path_chars[] = "ACz0/.~:";
size_t count = RandInRange(60);
base::FilePath::StringType random_path;
for (size_t i = 0; i < count; ++i)
random_path += path_chars[RandInRange(sizeof(path_chars) - 1)];
*p = base::FilePath(random_path);
return true;
}
};
template <>
struct FuzzTraits<base::File::Error> {
static bool Fuzz(base::File::Error* p, Fuzzer* fuzzer) {
int value = static_cast<int>(*p);
if (!FuzzParam(&value, fuzzer))
return false;
*p = static_cast<base::File::Error>(value);
return true;
}
};
template <>
struct FuzzTraits<base::File::Info> {
static bool Fuzz(base::File::Info* p, Fuzzer* fuzzer) {
double last_modified = p->last_modified.InSecondsFSinceUnixEpoch();
double last_accessed = p->last_accessed.InSecondsFSinceUnixEpoch();
double creation_time = p->creation_time.InSecondsFSinceUnixEpoch();
if (!FuzzParam(&p->size, fuzzer))
return false;
if (!FuzzParam(&p->is_directory, fuzzer))
return false;
if (!FuzzParam(&last_modified, fuzzer))
return false;
if (!FuzzParam(&last_accessed, fuzzer))
return false;
if (!FuzzParam(&creation_time, fuzzer))
return false;
p->last_modified = base::Time::FromSecondsSinceUnixEpoch(last_modified);
p->last_accessed = base::Time::FromSecondsSinceUnixEpoch(last_accessed);
p->creation_time = base::Time::FromSecondsSinceUnixEpoch(creation_time);
return true;
}
};
template <>
struct FuzzTraits<base::Time> {
static bool Fuzz(base::Time* p, Fuzzer* fuzzer) {
int64_t internal_value = p->ToInternalValue();
if (!FuzzParam(&internal_value, fuzzer))
return false;
*p = base::Time::FromInternalValue(internal_value);
return true;
}
};
template <>
struct FuzzTraits<base::TimeDelta> {
static bool Fuzz(base::TimeDelta* p, Fuzzer* fuzzer) {
int64_t internal_value = p->ToInternalValue();
if (!FuzzParam(&internal_value, fuzzer))
return false;
*p = base::TimeDelta::FromInternalValue(internal_value);
return true;
}
};
template <>
struct FuzzTraits<base::TimeTicks> {
static bool Fuzz(base::TimeTicks* p, Fuzzer* fuzzer) {
int64_t internal_value = p->ToInternalValue();
if (!FuzzParam(&internal_value, fuzzer))
return false;
*p = base::TimeTicks::FromInternalValue(internal_value);
return true;
}
};
template <>
struct FuzzTraits<base::Value> {
static bool Fuzz(base::Value* p, Fuzzer* fuzzer) {
DCHECK(p->type() == base::Value::Type::LIST ||
p->type() == base::Value::Type::DICT);
// TODO(mbarbella): Support mutation.
if (!fuzzer->ShouldGenerate())
return true;
if (g_depth > 2)
return true;
g_depth++;
const size_t kMaxSize = 8;
size_t random_size = RandInRange(kMaxSize);
for (size_t i = 0; i < random_size; i++) {
base::Value random_value;
const size_t kNumValueTypes = 8;
switch (static_cast<base::Value::Type>(RandInRange(kNumValueTypes))) {
case base::Value::Type::BOOLEAN: {
bool tmp;
fuzzer->FuzzBool(&tmp);
random_value = base::Value(tmp);
break;
}
case base::Value::Type::INTEGER: {
int tmp;
fuzzer->FuzzInt(&tmp);
random_value = base::Value(tmp);
break;
}
case base::Value::Type::DOUBLE: {
double tmp;
fuzzer->FuzzDouble(&tmp);
random_value = base::Value(tmp);
break;
}
case base::Value::Type::BINARY: {
char tmp[200];
size_t bin_length = RandInRange(sizeof(tmp));
fuzzer->FuzzData(tmp, bin_length);
random_value =
base::Value(base::as_bytes(base::make_span(tmp, bin_length)));
break;
}
case base::Value::Type::STRING: {
random_value = base::Value(base::Value::Type::STRING);
fuzzer->FuzzString(&random_value.GetString());
break;
}
case base::Value::Type::DICT: {
random_value = base::Value(base::Value::Type::DICT);
FuzzParam(&random_value, fuzzer);
break;
}
case base::Value::Type::LIST: {
random_value = base::Value(base::Value::Type::LIST);
FuzzParam(&random_value, fuzzer);
break;
}
case base::Value::Type::NONE:
// |random_value| already has type NONE, nothing to do.
break;
}
// Add |random_value| to the container.
if (p->type() == base::Value::Type::LIST) {
p->GetList().Append(std::move(random_value));
} else {
// |p| is a dictionary, a fuzzed key is also required.
std::string key;
fuzzer->FuzzString(&key);
p->GetDict().Set(key, std::move(random_value));
}
}
--g_depth;
return true;
}
};
template <>
struct FuzzTraits<base::UnguessableToken> {
static bool Fuzz(base::UnguessableToken* p, Fuzzer* fuzzer) {
auto low = p->GetLowForSerialization();
auto high = p->GetHighForSerialization();
if (!FuzzParam(&low, fuzzer))
return false;
if (!FuzzParam(&high, fuzzer))
return false;
while (high == 0 && low == 0) {
FuzzParam(&low, fuzzer);
FuzzParam(&high, fuzzer);
}
*p = base::UnguessableToken::Deserialize(high, low).value();
return true;
}
};
template <>
struct FuzzTraits<base::UnsafeSharedMemoryRegion> {
static bool Fuzz(base::UnsafeSharedMemoryRegion* p, Fuzzer* fuzzer) {
size_t size = RandInRange(16 * 1024 * 1024 * sizeof(char));
*p = base::UnsafeSharedMemoryRegion::Create(size);
return true;
}
};
template <>
struct FuzzTraits<blink::mojom::EmulatedScreenType> {
static bool Fuzz(blink::mojom::EmulatedScreenType* p, Fuzzer* fuzzer) {
int screen_type = RandInRange(
static_cast<int>(blink::mojom::EmulatedScreenType::kMaxValue) + 1);
*p = static_cast<blink::mojom::EmulatedScreenType>(screen_type);
return true;
}
};
template <>
struct FuzzTraits<viz::FrameSinkId> {
static bool Fuzz(viz::FrameSinkId* p, Fuzzer* fuzzer) {
uint32_t client_id;
uint32_t sink_id;
if (!FuzzParam(&client_id, fuzzer))
return false;
if (!FuzzParam(&sink_id, fuzzer))
return false;
*p = viz::FrameSinkId(client_id, sink_id);
return true;
}
};
template <>
struct FuzzTraits<viz::LocalSurfaceId> {
static bool Fuzz(viz::LocalSurfaceId* p, Fuzzer* fuzzer) {
uint32_t parent_sequence_number = p->parent_sequence_number();
uint32_t child_sequence_number = p->child_sequence_number();
base::UnguessableToken embed_token = p->embed_token();
if (!FuzzParam(&parent_sequence_number, fuzzer))
return false;
if (!FuzzParam(&child_sequence_number, fuzzer))
return false;
if (!FuzzParam(&embed_token, fuzzer))
return false;
*p = viz::LocalSurfaceId(parent_sequence_number, child_sequence_number,
embed_token);
return true;
}
};
template <>
struct FuzzTraits<blink::PageState> {
static bool Fuzz(blink::PageState* p, Fuzzer* fuzzer) {
std::string data = p->ToEncodedData();
if (!FuzzParam(&data, fuzzer))
return false;
*p = blink::PageState::CreateFromEncodedData(data);
return true;
}
};
template <>
struct FuzzTraits<device::mojom::ScreenOrientationLockType> {
static bool Fuzz(device::mojom::ScreenOrientationLockType* p,
Fuzzer* fuzzer) {
int value = RandInRange(
static_cast<int>(device::mojom::ScreenOrientationLockType::kMaxValue) +
1);
*p = static_cast<device::mojom::ScreenOrientationLockType>(value);
return true;
}
};
template <>
struct FuzzTraits<ContentSettingsPattern> {
static bool Fuzz(ContentSettingsPattern* p, Fuzzer* fuzzer) {
// TODO(mbarbella): This can crash if a pattern is generated from a random
// string. We could carefully generate a pattern or fix pattern generation.
return true;
}
};
template <>
struct FuzzTraits<gfx::BufferFormat> {
static bool Fuzz(gfx::BufferFormat* p, Fuzzer* fuzzer) {
int format = RandInRange(static_cast<int>(gfx::BufferFormat::LAST) + 1);
*p = static_cast<gfx::BufferFormat>(format);
return true;
}
};
template <>
struct FuzzTraits<gfx::ColorSpace> {
static bool Fuzz(gfx::ColorSpace* p, Fuzzer* fuzzer) {
gfx::ColorSpace::PrimaryID primaries;
gfx::ColorSpace::TransferID transfer;
gfx::ColorSpace::MatrixID matrix;
gfx::ColorSpace::RangeID range;
if (!FuzzParam(&primaries, fuzzer))
return false;
if (!FuzzParam(&transfer, fuzzer))
return false;
if (!FuzzParam(&matrix, fuzzer))
return false;
if (!FuzzParam(&range, fuzzer))
return false;
*p = gfx::ColorSpace(primaries, transfer, matrix, range);
return true;
}
};
template <>
struct FuzzTraits<gfx::ColorSpace::MatrixID> {
static bool Fuzz(gfx::ColorSpace::MatrixID* p, Fuzzer* fuzzer) {
uint8_t matrix =
RandInRange(static_cast<int>(gfx::ColorSpace::MatrixID::kMaxValue) + 1);
*p = static_cast<gfx::ColorSpace::MatrixID>(matrix);
return true;
}
};
template <>
struct FuzzTraits<gfx::ColorSpace::PrimaryID> {
static bool Fuzz(gfx::ColorSpace::PrimaryID* p, Fuzzer* fuzzer) {
int primaries = RandInRange(
static_cast<int>(gfx::ColorSpace::PrimaryID::kMaxValue) + 1);
*p = static_cast<gfx::ColorSpace::PrimaryID>(primaries);
return true;
}
};
template <>
struct FuzzTraits<gfx::ColorSpace::RangeID> {
static bool Fuzz(gfx::ColorSpace::RangeID* p, Fuzzer* fuzzer) {
uint8_t range =
RandInRange(static_cast<int>(gfx::ColorSpace::RangeID::kMaxValue) + 1);
*p = static_cast<gfx::ColorSpace::RangeID>(range);
return true;
}
};
template <>
struct FuzzTraits<gfx::ColorSpace::TransferID> {
static bool Fuzz(gfx::ColorSpace::TransferID* p, Fuzzer* fuzzer) {
uint8_t transfer = RandInRange(
static_cast<int>(gfx::ColorSpace::TransferID::kMaxValue) + 1);
*p = static_cast<gfx::ColorSpace::TransferID>(transfer);
return true;
}
};
template <>
struct FuzzTraits<gfx::GpuFenceHandle> {
static bool Fuzz(gfx::GpuFenceHandle* p, Fuzzer* fuzzer) {
return true;
}
};
template <>
struct FuzzTraits<gfx::GpuMemoryBufferHandle> {
static bool Fuzz(gfx::GpuMemoryBufferHandle* p, Fuzzer* fuzzer) {
int type;
if (!FuzzParam(&type, fuzzer))
return false;
if (!FuzzParam(&p->offset, fuzzer))
return false;
if (!FuzzParam(&p->stride, fuzzer))
return false;
if (!FuzzParam(&p->region, fuzzer))
return false;
p->type = static_cast<gfx::GpuMemoryBufferType>(type);
return true;
}
};
template <>
struct FuzzTraits<gfx::Point> {
static bool Fuzz(gfx::Point* p, Fuzzer* fuzzer) {
int x = p->x();
int y = p->y();
if (!FuzzParam(&x, fuzzer))
return false;
if (!FuzzParam(&y, fuzzer))
return false;
p->SetPoint(x, y);
return true;
}
};
template <>
struct FuzzTraits<gfx::PointF> {
static bool Fuzz(gfx::PointF* p, Fuzzer* fuzzer) {
float x = p->x();
float y = p->y();
if (!FuzzParam(&x, fuzzer))
return false;
if (!FuzzParam(&y, fuzzer))
return false;
p->SetPoint(x, y);
return true;
}
};
template <>
struct FuzzTraits<gfx::Rect> {
static bool Fuzz(gfx::Rect* p, Fuzzer* fuzzer) {
gfx::Point origin = p->origin();
gfx::Size size = p->size();
if (!FuzzParam(&origin, fuzzer))
return false;
if (!FuzzParam(&size, fuzzer))
return false;
p->set_origin(origin);
p->set_size(size);
return true;
}
};
template <>
struct FuzzTraits<gfx::RectF> {
static bool Fuzz(gfx::RectF* p, Fuzzer* fuzzer) {
gfx::PointF origin = p->origin();
gfx::SizeF size = p->size();
if (!FuzzParam(&origin, fuzzer))
return false;
if (!FuzzParam(&size, fuzzer))
return false;
p->set_origin(origin);
p->set_size(size);
return true;
}
};
template <>
struct FuzzTraits<gfx::Range> {
static bool Fuzz(gfx::Range* p, Fuzzer* fuzzer) {
size_t start = p->start();
size_t end = p->end();
if (!FuzzParam(&start, fuzzer))
return false;
if (!FuzzParam(&end, fuzzer))
return false;
*p = gfx::Range(start, end);
return true;
}
};
template <>
struct FuzzTraits<gfx::Size> {
static bool Fuzz(gfx::Size* p, Fuzzer* fuzzer) {
int width = p->width();
int height = p->height();
if (!FuzzParam(&width, fuzzer))
return false;
if (!FuzzParam(&height, fuzzer))
return false;
p->SetSize(width, height);
return true;
}
};
template <>
struct FuzzTraits<gfx::SizeF> {
static bool Fuzz(gfx::SizeF* p, Fuzzer* fuzzer) {
float w;
float h;
if (!FuzzParam(&w, fuzzer))
return false;
if (!FuzzParam(&h, fuzzer))
return false;
p->SetSize(w, h);
return true;
}
};
template <>
struct FuzzTraits<gfx::SwapResponse> {
static bool Fuzz(gfx::SwapResponse* p, Fuzzer* fuzzer) {
if (!FuzzParam(&p->swap_id, fuzzer))
return false;
if (!FuzzParam(&p->result, fuzzer))
return false;
if (!FuzzParam(&p->timings, fuzzer))
return false;
return true;
}
};
template <>
struct FuzzTraits<gfx::SwapResult> {
static bool Fuzz(gfx::SwapResult* p, Fuzzer* fuzzer) {
int result =
RandInRange(static_cast<int>(gfx::SwapResult::SWAP_RESULT_LAST) + 1);
*p = static_cast<gfx::SwapResult>(result);
return true;
}
};
template <>
struct FuzzTraits<gfx::SwapTimings> {
static bool Fuzz(gfx::SwapTimings* p, Fuzzer* fuzzer) {
if (!FuzzParam(&p->swap_start, fuzzer))
return false;
if (!FuzzParam(&p->swap_end, fuzzer))
return false;
return true;
}
};
template <>
struct FuzzTraits<gfx::Transform> {
static bool Fuzz(gfx::Transform* p, Fuzzer* fuzzer) {
float matrix[16];
p->GetColMajorF(matrix);
if (!FuzzParamArray(&matrix[0], std::size(matrix), fuzzer))
return false;
*p = gfx::Transform::ColMajorF(matrix);
return true;
}
};
template <>
struct FuzzTraits<gfx::Vector2d> {
static bool Fuzz(gfx::Vector2d* p, Fuzzer* fuzzer) {
int x = p->x();
int y = p->y();
if (!FuzzParam(&x, fuzzer))
return false;
if (!FuzzParam(&y, fuzzer))
return false;
*p = gfx::Vector2d(x, y);
return true;
}
};
template <>
struct FuzzTraits<gfx::Vector2dF> {
static bool Fuzz(gfx::Vector2dF* p, Fuzzer* fuzzer) {
float x = p->x();
float y = p->y();
if (!FuzzParam(&x, fuzzer))
return false;
if (!FuzzParam(&y, fuzzer))
return false;
*p = gfx::Vector2dF(x, y);
return true;
}
};
template <typename TypeMarker, typename WrappedType, WrappedType kInvalidValue>
struct FuzzTraits<base::IdType<TypeMarker, WrappedType, kInvalidValue>> {
using param_type = base::IdType<TypeMarker, WrappedType, kInvalidValue>;
static bool Fuzz(param_type* id, Fuzzer* fuzzer) {
WrappedType raw_value = id->GetUnsafeValue();
if (!FuzzParam(&raw_value, fuzzer))
return false;
*id = param_type::FromUnsafeValue(raw_value);
return true;
}
};
template <>
struct FuzzTraits<gl::GpuPreference> {
static bool Fuzz(gl::GpuPreference* p, Fuzzer* fuzzer) {
int preference =
RandInRange(static_cast<int>(gl::GpuPreference::kMaxValue) + 1);
*p = static_cast<gl::GpuPreference>(preference);
return true;
}
};
template <>
struct FuzzTraits<gpu::CommandBuffer::State> {
static bool Fuzz(gpu::CommandBuffer::State* p, Fuzzer* fuzzer) {
if (!FuzzParam(&p->get_offset, fuzzer))
return false;
if (!FuzzParam(&p->token, fuzzer))
return false;
if (!FuzzParam(&p->release_count, fuzzer))
return false;
if (!FuzzParam(&p->error, fuzzer))
return false;
if (!FuzzParam(&p->context_lost_reason, fuzzer))
return false;
if (!FuzzParam(&p->generation, fuzzer))
return false;
if (!FuzzParam(&p->set_get_buffer_count, fuzzer))
return false;
return true;
}
};
template <>
struct FuzzTraits<gpu::CommandBufferNamespace> {
static bool Fuzz(gpu::CommandBufferNamespace* p, Fuzzer* fuzzer) {
int name_space =
RandInRange(gpu::CommandBufferNamespace::NUM_COMMAND_BUFFER_NAMESPACES);
*p = static_cast<gpu::CommandBufferNamespace>(name_space);
return true;
}
};
template <>
struct FuzzTraits<gpu::ContextCreationAttribs> {
static bool Fuzz(gpu::ContextCreationAttribs* p, Fuzzer* fuzzer) {
if (!FuzzParam(&p->gpu_preference, fuzzer))
return false;
if (!FuzzParam(&p->context_type, fuzzer))
return false;
return true;
}
};
template <>
struct FuzzTraits<gpu::ContextType> {
static bool Fuzz(gpu::ContextType* p, Fuzzer* fuzzer) {
int type = RandInRange(gpu::ContextType::CONTEXT_TYPE_LAST + 1);
*p = static_cast<gpu::ContextType>(type);
return true;
}
};
template <>
struct FuzzTraits<gpu::error::ContextLostReason> {
static bool Fuzz(gpu::error::ContextLostReason* p, Fuzzer* fuzzer) {
int reason =
RandInRange(gpu::error::ContextLostReason::kContextLostReasonLast + 1);
*p = static_cast<gpu::error::ContextLostReason>(reason);
return true;
}
};
template <>
struct FuzzTraits<gpu::error::Error> {
static bool Fuzz(gpu::error::Error* p, Fuzzer* fuzzer) {
int error = RandInRange(gpu::error::Error::kErrorLast + 1);
*p = static_cast<gpu::error::Error>(error);
return true;
}
};
template <>
struct FuzzTraits<gpu::Mailbox> {
static bool Fuzz(gpu::Mailbox* p, Fuzzer* fuzzer) {
fuzzer->FuzzBytes(p->name, sizeof(p->name));
return true;
}
};
template <>
struct FuzzTraits<gpu::SwapBuffersCompleteParams> {
static bool Fuzz(gpu::SwapBuffersCompleteParams* p, Fuzzer* fuzzer) {
if (!FuzzParam(&p->swap_response, fuzzer))
return false;
return true;
}
};
template <>
struct FuzzTraits<gpu::SyncToken> {
static bool Fuzz(gpu::SyncToken* p, Fuzzer* fuzzer) {
bool verified_flush = false;
gpu::CommandBufferNamespace namespace_id =
gpu::CommandBufferNamespace::INVALID;
gpu::CommandBufferId command_buffer_id;
uint64_t release_count = 0;
if (!FuzzParam(&verified_flush, fuzzer))
return false;
if (!FuzzParam(&namespace_id, fuzzer))
return false;
if (!FuzzParam(&command_buffer_id, fuzzer))
return false;
if (!FuzzParam(&release_count, fuzzer))
return false;
p->Clear();
p->Set(namespace_id, command_buffer_id, release_count);
if (verified_flush)
p->SetVerifyFlush();
return true;
}
};
template <>
struct FuzzTraits<gpu::MailboxHolder> {
static bool Fuzz(gpu::MailboxHolder* p, Fuzzer* fuzzer) {
if (!FuzzParam(&p->mailbox, fuzzer))
return false;
if (!FuzzParam(&p->sync_token, fuzzer))
return false;
if (!FuzzParam(&p->texture_target, fuzzer))
return false;
return true;
}
};
template <>
struct FuzzTraits<GURL> {
static bool Fuzz(GURL* p, Fuzzer* fuzzer) {
if (!fuzzer->ShouldGenerate()) {
std::string spec = p->possibly_invalid_spec();
if (!FuzzParam(&spec, fuzzer))
return false;
if (spec != p->possibly_invalid_spec())
*p = GURL(spec);
return true;
}
const char url_chars[] = "Ahtp0:/.?+\\%&#";
size_t count = RandInRange(100);
std::string random_url;
for (size_t i = 0; i < count; ++i)
random_url += url_chars[RandInRange(sizeof(url_chars) - 1)];
int selector = RandInRange(10);
if (selector == 0)
random_url = std::string("http://") + random_url;
else if (selector == 1)
random_url = std::string("file://") + random_url;
else if (selector == 2)
random_url = std::string("javascript:") + random_url;
else if (selector == 2)
random_url = std::string("data:") + random_url;
*p = GURL(random_url);
return true;
}
};
#if BUILDFLAG(IS_WIN)
template <>
struct FuzzTraits<HWND> {
static bool Fuzz(HWND* p, Fuzzer* fuzzer) {
// TODO(aarya): This should actually do something.
return true;
}
};
#endif
template <>
struct FuzzTraits<std::unique_ptr<IPC::Message>> {
static bool Fuzz(std::unique_ptr<IPC::Message>* p, Fuzzer* fuzzer) {
// TODO(mbarbella): Support mutation.
if (!fuzzer->ShouldGenerate())
return true;
if (g_function_vector.empty())
return false;
size_t index = RandInRange(g_function_vector.size());
std::unique_ptr<IPC::Message> ipc_message =
(*g_function_vector[index])(nullptr, fuzzer);
if (!ipc_message)
return false;
*p = std::move(ipc_message);
return true;
}
};
template <>
struct FuzzTraits<IPC::PlatformFileForTransit> {
static bool Fuzz(IPC::PlatformFileForTransit* p, Fuzzer* fuzzer) {
// TODO(inferno): I don't think we can generate real ones due to check on
// construct.
return true;
}
};
template <>
struct FuzzTraits<IPC::ChannelHandle> {
static bool Fuzz(IPC::ChannelHandle* p, Fuzzer* fuzzer) {
// TODO(mbarbella): Support mutation.
if (!fuzzer->ShouldGenerate())
return true;
return FuzzParam(&p->mojo_handle, fuzzer);
}
};
#if BUILDFLAG(IS_WIN)
template <>
struct FuzzTraits<LOGFONT> {
static bool Fuzz(LOGFONT* p, Fuzzer* fuzzer) {
// TODO(aarya): This should actually do something.
return true;
}
};
#endif
template <>
struct FuzzTraits<media::AudioParameters> {
static bool Fuzz(media::AudioParameters* p, Fuzzer* fuzzer) {
int channel_layout = p->channel_layout();
int format = p->format();
int sample_rate = p->sample_rate();
int frames_per_buffer = p->frames_per_buffer();
int channels = p->channels();
int effects = p->effects();
// TODO(mbarbella): Support ChannelLayout mutation and invalid values.
if (fuzzer->ShouldGenerate()) {
channel_layout =
RandInRange(media::ChannelLayout::CHANNEL_LAYOUT_MAX + 1);
}
if (!FuzzParam(&format, fuzzer))
return false;
if (!FuzzParam(&sample_rate, fuzzer))
return false;
if (!FuzzParam(&frames_per_buffer, fuzzer))
return false;
if (!FuzzParam(&channels, fuzzer))
return false;
if (!FuzzParam(&effects, fuzzer))
return false;
media::AudioParameters params(
static_cast<media::AudioParameters::Format>(format),
{static_cast<media::ChannelLayout>(channel_layout), channels},
sample_rate, frames_per_buffer);
params.set_effects(effects);
*p = params;
return true;
}
};
template <>
struct FuzzTraits<media::OverlayInfo> {
static bool Fuzz(media::OverlayInfo* p, Fuzzer* fuzzer) {
if (!FuzzParam(&p->is_fullscreen, fuzzer))
return false;
if (!FuzzParam(&p->is_persistent_video, fuzzer))
return false;
if (!FuzzParam(&p->routing_token, fuzzer))
return false;
return true;
}
};
template <>
struct FuzzTraits<media::VideoPixelFormat> {
static bool Fuzz(media::VideoPixelFormat* p, Fuzzer* fuzzer) {
int format = RandInRange(media::VideoPixelFormat::PIXEL_FORMAT_MAX + 1);
*p = static_cast<media::VideoPixelFormat>(format);
return true;
}
};
template <>
struct FuzzTraits<net::EffectiveConnectionType> {
static bool Fuzz(net::EffectiveConnectionType* p, Fuzzer* fuzzer) {
int type = RandInRange(
net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_LAST + 1);
*p = static_cast<net::EffectiveConnectionType>(type);
return true;
}
};
template <>
struct FuzzTraits<net::LoadTimingInfo> {
static bool Fuzz(net::LoadTimingInfo* p, Fuzzer* fuzzer) {
return FuzzParam(&p->socket_log_id, fuzzer) &&
FuzzParam(&p->socket_reused, fuzzer) &&
FuzzParam(&p->request_start_time, fuzzer) &&
FuzzParam(&p->request_start, fuzzer) &&
FuzzParam(&p->proxy_resolve_start, fuzzer) &&
FuzzParam(&p->proxy_resolve_end, fuzzer) &&
FuzzParam(&p->connect_timing.domain_lookup_start, fuzzer) &&
FuzzParam(&p->connect_timing.domain_lookup_end, fuzzer) &&
FuzzParam(&p->connect_timing.connect_start, fuzzer) &&
FuzzParam(&p->connect_timing.connect_end, fuzzer) &&
FuzzParam(&p->connect_timing.ssl_start, fuzzer) &&
FuzzParam(&p->connect_timing.ssl_end, fuzzer) &&
FuzzParam(&p->send_start, fuzzer) &&
FuzzParam(&p->send_end, fuzzer) &&
FuzzParam(&p->receive_headers_end, fuzzer);
}
};
template <>
struct FuzzTraits<net::HostPortPair> {
static bool Fuzz(net::HostPortPair* p, Fuzzer* fuzzer) {
std::string host = p->host();
uint16_t port = p->port();
if (!FuzzParam(&host, fuzzer))
return false;
if (!FuzzParam(&port, fuzzer))
return false;
p->set_host(host);
p->set_port(port);
return true;
}
};
template <>
struct FuzzTraits<net::IPAddress> {
static bool Fuzz(net::IPAddress* p, Fuzzer* fuzzer) {
std::vector<uint8_t> bytes = p->CopyBytesToVector();
if (!FuzzParam(&bytes, fuzzer))
return false;
net::IPAddress ip_address(bytes);
*p = ip_address;
return true;
}
};
template <>
struct FuzzTraits<net::IPEndPoint> {
static bool Fuzz(net::IPEndPoint* p, Fuzzer* fuzzer) {
net::IPAddress ip_address = p->address();
int port = p->port();
if (!FuzzParam(&ip_address, fuzzer))
return false;
if (!FuzzParam(&port, fuzzer))
return false;
net::IPEndPoint ip_endpoint(ip_address, port);
*p = ip_endpoint;
return true;
}
};
#if BUILDFLAG(ENABLE_PPAPI)
// PP_ traits.
template <>
struct FuzzTraits<PP_Bool> {
static bool Fuzz(PP_Bool* p, Fuzzer* fuzzer) {
bool tmp = PP_ToBool(*p);
if (!FuzzParam(&tmp, fuzzer))
return false;
*p = PP_FromBool(tmp);
return true;
}
};
template <>
struct FuzzTraits<PP_NetAddress_Private> {
static bool Fuzz(PP_NetAddress_Private* p, Fuzzer* fuzzer) {
p->size = RandInRange(sizeof(p->data) + 1);
fuzzer->FuzzBytes(&p->data, p->size);
return true;
}
};
template <>
struct FuzzTraits<ppapi::PPB_X509Certificate_Fields> {
static bool Fuzz(ppapi::PPB_X509Certificate_Fields* p,
Fuzzer* fuzzer) {
// TODO(mbarbella): This should actually do something.
return true;
}
};
template <>
struct FuzzTraits<ppapi::proxy::ResourceMessageCallParams> {
static bool Fuzz(
ppapi::proxy::ResourceMessageCallParams* p, Fuzzer* fuzzer) {
// TODO(mbarbella): Support mutation.
if (!fuzzer->ShouldGenerate())
return true;
PP_Resource resource;
int32_t sequence;
bool has_callback;
if (!FuzzParam(&resource, fuzzer))
return false;
if (!FuzzParam(&sequence, fuzzer))
return false;
if (!FuzzParam(&has_callback, fuzzer))
return false;
*p = ppapi::proxy::ResourceMessageCallParams(resource, sequence);
if (has_callback)
p->set_has_callback();
return true;
}
};
template <>
struct FuzzTraits<ppapi::proxy::ResourceMessageReplyParams> {
static bool Fuzz(
ppapi::proxy::ResourceMessageReplyParams* p, Fuzzer* fuzzer) {
// TODO(mbarbella): Support mutation.
if (!fuzzer->ShouldGenerate())
return true;
PP_Resource resource;
int32_t sequence;
int32_t result;
if (!FuzzParam(&resource, fuzzer))
return false;
if (!FuzzParam(&sequence, fuzzer))
return false;
if (!FuzzParam(&result, fuzzer))
return false;
*p = ppapi::proxy::ResourceMessageReplyParams(resource, sequence);
p->set_result(result);
return true;
}
};
template <>
struct FuzzTraits<ppapi::proxy::SerializedHandle> {
static bool Fuzz(ppapi::proxy::SerializedHandle* p,
Fuzzer* fuzzer) {
// TODO(mbarbella): This should actually do something.
return true;
}
};
template <>
struct FuzzTraits<ppapi::proxy::SerializedFontDescription> {
static bool Fuzz(ppapi::proxy::SerializedFontDescription* p,
Fuzzer* fuzzer) {
// TODO(mbarbella): This should actually do something.
return true;
}
};
template <>
struct FuzzTraits<ppapi::proxy::SerializedVar> {
static bool Fuzz(ppapi::proxy::SerializedVar* p, Fuzzer* fuzzer) {
// TODO(mbarbella): This should actually do something.
return true;
}
};
template <>
struct FuzzTraits<ppapi::HostResource> {
static bool Fuzz(ppapi::HostResource* p, Fuzzer* fuzzer) {
// TODO(mbarbella): Support mutation.
if (!fuzzer->ShouldGenerate())
return true;
PP_Instance instance;
PP_Resource resource;
if (!FuzzParam(&instance, fuzzer))
return false;
if (!FuzzParam(&resource, fuzzer))
return false;
p->SetHostResource(instance, resource);
return true;
}
};
template <>
struct FuzzTraits<ppapi::PepperFilePath> {
static bool Fuzz(ppapi::PepperFilePath *p, Fuzzer* fuzzer) {
// TODO(mbarbella): Support mutation.
if (!fuzzer->ShouldGenerate())
return true;
unsigned domain = RandInRange(ppapi::PepperFilePath::DOMAIN_MAX_VALID+1);
base::FilePath path;
if (!FuzzParam(&path, fuzzer))
return false;
*p = ppapi::PepperFilePath(
static_cast<ppapi::PepperFilePath::Domain>(domain), path);
return true;
}
};
template <>
struct FuzzTraits<ppapi::PpapiPermissions> {
static bool Fuzz(ppapi::PpapiPermissions* p, Fuzzer* fuzzer) {
uint32_t bits = p->GetBits();
if (!FuzzParam(&bits, fuzzer))
return false;
*p = ppapi::PpapiPermissions(bits);
return true;
}
};
template <>
struct FuzzTraits<ppapi::SocketOptionData> {
static bool Fuzz(ppapi::SocketOptionData* p, Fuzzer* fuzzer) {
// TODO(mbarbella): This can be improved.
int32_t tmp;
p->GetInt32(&tmp);
if (!FuzzParam(&tmp, fuzzer))
return false;
p->SetInt32(tmp);
return true;
}
};
#endif // BUILDFLAG(ENABLE_PPAPI)
template <>
struct FuzzTraits<printing::mojom::MarginType> {
static bool Fuzz(printing::mojom::MarginType* p, Fuzzer* fuzzer) {
int type = RandInRange(
static_cast<int>(printing::mojom::MarginType::kMaxValue) + 1);
*p = static_cast<printing::mojom::MarginType>(type);
return true;
}
};
template <>
struct FuzzTraits<SkBitmap> {
static bool Fuzz(SkBitmap* p, Fuzzer* fuzzer) {
// TODO(mbarbella): This should actually do something.
return true;
}
};
template <>
struct FuzzTraits<ui::LatencyInfo> {
static bool Fuzz(ui::LatencyInfo* p, Fuzzer* fuzzer) {
// TODO(inferno): Add param traits for |latency_components|.
int64_t trace_id = p->trace_id();
bool terminated = p->terminated();
if (!FuzzParam(&trace_id, fuzzer))
return false;
if (!FuzzParam(&terminated, fuzzer))
return false;
ui::LatencyInfo latency(trace_id, terminated);
*p = latency;
return true;
}
};
template <>
struct FuzzTraits<url::Origin> {
static bool Fuzz(url::Origin* p, Fuzzer* fuzzer) {
bool opaque = p->opaque();
if (!FuzzParam(&opaque, fuzzer))
return false;
std::string scheme = p->GetTupleOrPrecursorTupleIfOpaque().scheme();
std::string host = p->GetTupleOrPrecursorTupleIfOpaque().host();
uint16_t port = p->GetTupleOrPrecursorTupleIfOpaque().port();
if (!FuzzParam(&scheme, fuzzer))
return false;
if (!FuzzParam(&host, fuzzer))
return false;
if (!FuzzParam(&port, fuzzer))
return false;
std::optional<url::Origin> origin;
if (!opaque) {
origin = url::Origin::UnsafelyCreateTupleOriginWithoutNormalization(
scheme, host, port);
} else {
std::optional<base::UnguessableToken> token;
if (auto* nonce = p->GetNonceForSerialization()) {
token = *nonce;
} else {
auto high = RandU64();
auto low = RandU64();
while (high == 0 && low == 0) {
high = RandU64();
low = RandU64();
}
token = base::UnguessableToken::Deserialize(high, low).value();
}
if (!FuzzParam(&(*token), fuzzer))
return false;
origin = url::Origin::UnsafelyCreateOpaqueOriginWithoutNormalization(
scheme, host, port, url::Origin::Nonce(*token));
}
if (!origin) {
// This means that we produced non-canonical values that were rejected by
// UnsafelyCreate. Which is nice, except, those are arguably interesting
// values to be sending over the wire sometimes, to make sure they're
// rejected at the receiving end.
//
// We could potentially call CreateFromNormalizedTuple here to force their
// creation, except that could lead to invariant violations within the
// url::Origin we construct -- and potentially crash the fuzzer. What to
// do?
return false;
}
*p = std::move(origin).value();
return true;
}
};
// Redefine macros to generate generating from traits declarations.
// STRUCT declarations cause corresponding STRUCT_TRAITS declarations to occur.
#undef IPC_STRUCT_BEGIN
#undef IPC_STRUCT_BEGIN_WITH_PARENT
#undef IPC_STRUCT_MEMBER
#undef IPC_STRUCT_END
#define IPC_STRUCT_BEGIN_WITH_PARENT(struct_name, parent) \
IPC_STRUCT_BEGIN(struct_name)
#define IPC_STRUCT_BEGIN(struct_name) IPC_STRUCT_TRAITS_BEGIN(struct_name)
#define IPC_STRUCT_MEMBER(type, name, ...) IPC_STRUCT_TRAITS_MEMBER(name)
#define IPC_STRUCT_END() IPC_STRUCT_TRAITS_END()
// Set up so next include will generate generate trait classes.
#undef IPC_STRUCT_TRAITS_BEGIN
#undef IPC_STRUCT_TRAITS_MEMBER
#undef IPC_STRUCT_TRAITS_PARENT
#undef IPC_STRUCT_TRAITS_END
#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \
template <> \
struct FuzzTraits<struct_name> { \
static bool Fuzz(struct_name *p, Fuzzer* fuzzer) {
#define IPC_STRUCT_TRAITS_MEMBER(name) \
if (!FuzzParam(&p->name, fuzzer)) \
return false;
#define IPC_STRUCT_TRAITS_PARENT(type) \
if (!FuzzParam(static_cast<type*>(p), fuzzer)) \
return false;
#define IPC_STRUCT_TRAITS_END() \
return true; \
} \
};
// If |condition| isn't met, the messsge will fail to serialize. Try
// increasingly smaller ranges until we find one that happens to meet
// the condition, or fail trying.
// TODO(mbarbella): Attempt to validate even in the mutation case.
#undef IPC_ENUM_TRAITS_VALIDATE
#define IPC_ENUM_TRAITS_VALIDATE(enum_name, condition) \
template <> \
struct FuzzTraits<enum_name> { \
static bool Fuzz(enum_name* p, Fuzzer* fuzzer) { \
if (!fuzzer->ShouldGenerate()) { \
return FuzzParam(reinterpret_cast<int*>(p), fuzzer); \
} \
for (int shift = 30; shift; --shift) { \
for (int tries = 0; tries < 2; ++tries) { \
int value = RandInRange(1 << shift); \
if (condition) { \
*reinterpret_cast<int*>(p) = value; \
return true; \
} \
} \
} \
std::cerr << "failed to satisfy " << #condition << "\n"; \
return false; \
} \
};
// Bring them into existence.
#include "tools/ipc_fuzzer/message_lib/all_messages.h"
#include "tools/ipc_fuzzer/message_lib/all_message_null_macros.h"
#define MAX_FAKE_ROUTING_ID 15
// MessageFactory abstracts away constructing control/routed messages by
// providing an additional random routing ID argument when necessary.
template <typename Message, IPC::MessageKind>
class MessageFactory;
template <typename Message>
class MessageFactory<Message, IPC::MessageKind::CONTROL> {
public:
template <typename... Args>
static std::unique_ptr<Message> New(const Args&... args) {
return std::make_unique<Message>(args...);
}
};
template <typename Message>
class MessageFactory<Message, IPC::MessageKind::ROUTED> {
public:
template <typename... Args>
static std::unique_ptr<Message> New(const Args&... args) {
return std::make_unique<Message>(RandInRange(MAX_FAKE_ROUTING_ID), args...);
}
};
template <typename Message>
class FuzzerHelper;
template <typename Meta, typename... Ins>
class FuzzerHelper<IPC::MessageT<Meta, std::tuple<Ins...>, void>> {
public:
using Message = IPC::MessageT<Meta, std::tuple<Ins...>, void>;
static std::unique_ptr<IPC::Message> Fuzz(IPC::Message* msg, Fuzzer* fuzzer) {
return FuzzImpl(msg, fuzzer, std::index_sequence_for<Ins...>());
}
private:
template <size_t... Ns>
static std::unique_ptr<IPC::Message> FuzzImpl(IPC::Message* msg,
Fuzzer* fuzzer,
std::index_sequence<Ns...>) {
typename Message::Param p;
if (msg) {
Message::Read(static_cast<Message*>(msg), &p);
}
if (FuzzParam(&p, fuzzer)) {
return MessageFactory<Message, Meta::kKind>::New(std::get<Ns>(p)...);
}
std::cerr << "Don't know how to handle " << Meta::kName << "\n";
return nullptr;
}
};
template <typename Meta, typename... Ins, typename... Outs>
class FuzzerHelper<
IPC::MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>> {
public:
using Message = IPC::MessageT<Meta, std::tuple<Ins...>, std::tuple<Outs...>>;
static std::unique_ptr<IPC::Message> Fuzz(IPC::Message* msg, Fuzzer* fuzzer) {
return FuzzImpl(msg, fuzzer, std::index_sequence_for<Ins...>());
}
private:
template <size_t... Ns>
static std::unique_ptr<IPC::Message> FuzzImpl(IPC::Message* msg,
Fuzzer* fuzzer,
std::index_sequence<Ns...>) {
typename Message::SendParam p;
Message* real_msg = static_cast<Message*>(msg);
std::unique_ptr<Message> new_msg;
if (real_msg) {
Message::ReadSendParam(real_msg, &p);
}
if (FuzzParam(&p, fuzzer)) {
new_msg = MessageFactory<Message, Meta::kKind>::New(
std::get<Ns>(p)..., static_cast<Outs*>(nullptr)...);
}
if (real_msg && new_msg) {
MessageCracker::CopyMessageID(new_msg.get(), real_msg);
} else if (!new_msg) {
std::cerr << "Don't know how to handle " << Meta::kName << "\n";
}
return new_msg;
}
};
#include "tools/ipc_fuzzer/message_lib/all_message_null_macros.h"
void PopulateFuzzerFunctionVector(
FuzzerFunctionVector* function_vector) {
#undef IPC_MESSAGE_DECL
#define IPC_MESSAGE_DECL(name, ...) \
function_vector->push_back(FuzzerHelper<name>::Fuzz);
#include "tools/ipc_fuzzer/message_lib/all_messages.h"
}
// Redefine macros to register fuzzing functions into map.
#include "tools/ipc_fuzzer/message_lib/all_message_null_macros.h"
#undef IPC_MESSAGE_DECL
#define IPC_MESSAGE_DECL(name, ...) \
(*map)[static_cast<uint32_t>(name::ID)] = FuzzerHelper<name>::Fuzz;
void PopulateFuzzerFunctionMap(FuzzerFunctionMap* map) {
#include "tools/ipc_fuzzer/message_lib/all_messages.h"
}
} // namespace ipc_fuzzer