// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include #include #include #include "base/command_line.h" #include "base/pickle.h" #include "base/strings/string_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "ipc/ipc_message.h" #include "ipc/ipc_message_utils.h" #include "ipc/ipc_switches.h" #include "ipc/ipc_sync_channel.h" #include "ipc/ipc_sync_message.h" #include "tools/ipc_fuzzer/message_lib/message_file.h" #include "tools/ipc_fuzzer/mutate/rand_util.h" #if defined(OS_POSIX) #include #endif // First include of message files to provide basic type. #include "tools/ipc_fuzzer/message_lib/all_messages.h" #include "ipc/ipc_message_null_macros.h" namespace IPC { class Message; } // namespace IPC namespace { // For breaking deep recursion. int g_depth = 0; } // namespace namespace ipc_fuzzer { // Interface implemented by those who generate basic types. The types all // correspond to the types which a pickle from base/pickle.h can pickle, // plus the floating point types. class Generator { public: virtual void GenerateBool(bool* value) = 0; virtual void GenerateInt(int* value) = 0; virtual void GenerateLong(long* value) = 0; virtual void GenerateSize(size_t* value) = 0; virtual void GenerateUChar(unsigned char *value) = 0; virtual void GenerateUInt16(uint16* value) = 0; virtual void GenerateUInt32(uint32* value) = 0; virtual void GenerateInt64(int64* value) = 0; virtual void GenerateUInt64(uint64* value) = 0; virtual void GenerateFloat(float *value) = 0; virtual void GenerateDouble(double *value) = 0; virtual void GenerateString(std::string* value) = 0; virtual void GenerateString16(base::string16* value) = 0; virtual void GenerateData(char* data, int length) = 0; virtual void GenerateBytes(void* data, int data_len) = 0; }; template void GenerateIntegralType(T* value) { switch (RandInRange(16)) { case 0: *value = 0; break; case 1: *value = 1; break; case 2: *value = -1; break; case 3: *value = 2; break; default: *value = static_cast(RandU64()); break; } } template void GenerateFloatingType(T* value) { *value = RandDouble(); } template void GenerateStringType(T* value) { T temp_string; size_t length = RandInRange(300); for (size_t i = 0; i < length; ++i) temp_string += RandInRange(256); *value = temp_string; } class GeneratorImpl : public Generator { public: GeneratorImpl() {} virtual ~GeneratorImpl() {} void GenerateBool(bool* value) override { *value = RandInRange(2); } void GenerateInt(int* value) override { GenerateIntegralType(value); } void GenerateLong(long* value) override { GenerateIntegralType(value); } void GenerateSize(size_t* value) override { GenerateIntegralType(value); } void GenerateUChar(unsigned char* value) override { GenerateIntegralType(value); } void GenerateUInt16(uint16* value) override { GenerateIntegralType(value); } void GenerateUInt32(uint32* value) override { GenerateIntegralType(value); } void GenerateInt64(int64* value) override { GenerateIntegralType(value); } void GenerateUInt64(uint64* value) override { GenerateIntegralType(value); } void GenerateFloat(float* value) override { GenerateFloatingType(value); } void GenerateDouble(double* value) override { GenerateFloatingType(value); } void GenerateString(std::string* value) override { GenerateStringType(value); } void GenerateString16(base::string16* value) override { GenerateStringType(value); } void GenerateData(char* data, int length) override { for (int i = 0; i < length; ++i) { GenerateIntegralType(&data[i]); } } void GenerateBytes(void* data, int data_len) override { GenerateData(static_cast(data), data_len); } }; // Partially-specialized class that knows how to generate a given type. template struct GenerateTraits { static bool Generate(P* p, Generator *generator) { // 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 static bool GenerateParam(P* p, Generator* generator) { return GenerateTraits

::Generate(p, generator); } // Specializations to generate primitive types. template <> struct GenerateTraits { static bool Generate(bool* p, Generator* generator) { generator->GenerateBool(p); return true; } }; template <> struct GenerateTraits { static bool Generate(int* p, Generator* generator) { generator->GenerateInt(p); return true; } }; template <> struct GenerateTraits { static bool Generate(unsigned int* p, Generator* generator) { generator->GenerateInt(reinterpret_cast(p)); return true; } }; template <> struct GenerateTraits { static bool Generate(long* p, Generator* generator) { generator->GenerateLong(p); return true; } }; template <> struct GenerateTraits { static bool Generate(unsigned long* p, Generator* generator) { generator->GenerateLong(reinterpret_cast(p)); return true; } }; template <> struct GenerateTraits { static bool Generate(long long* p, Generator* generator) { generator->GenerateInt64(reinterpret_cast(p)); return true; } }; template <> struct GenerateTraits { static bool Generate(unsigned long long* p, Generator* generator) { generator->GenerateInt64(reinterpret_cast(p)); return true; } }; template <> struct GenerateTraits { static bool Generate(short* p, Generator* generator) { generator->GenerateUInt16(reinterpret_cast(p)); return true; } }; template <> struct GenerateTraits { static bool Generate(unsigned short* p, Generator* generator) { generator->GenerateUInt16(reinterpret_cast(p)); return true; } }; template <> struct GenerateTraits { static bool Generate(char* p, Generator* generator) { generator->GenerateUChar(reinterpret_cast(p)); return true; } }; template <> struct GenerateTraits { static bool Generate(unsigned char* p, Generator* generator) { generator->GenerateUChar(p); return true; } }; template <> struct GenerateTraits { static bool Generate(float* p, Generator* generator) { generator->GenerateFloat(p); return true; } }; template <> struct GenerateTraits { static bool Generate(double* p, Generator* generator) { generator->GenerateDouble(p); return true; } }; template <> struct GenerateTraits { static bool Generate(std::string* p, Generator* generator) { generator->GenerateString(p); return true; } }; template <> struct GenerateTraits { static bool Generate(base::string16* p, Generator* generator) { generator->GenerateString16(p); return true; } }; // Specializations to generate tuples. template <> struct GenerateTraits> { static bool Generate(Tuple<>* p, Generator* generator) { return true; } }; template struct GenerateTraits> { static bool Generate(Tuple* p, Generator* generator) { return GenerateParam(&get<0>(*p), generator); } }; template struct GenerateTraits> { static bool Generate(Tuple* p, Generator* generator) { return GenerateParam(&get<0>(*p), generator) && GenerateParam(&get<1>(*p), generator); } }; template struct GenerateTraits> { static bool Generate(Tuple* p, Generator* generator) { return GenerateParam(&get<0>(*p), generator) && GenerateParam(&get<1>(*p), generator) && GenerateParam(&get<2>(*p), generator); } }; template struct GenerateTraits> { static bool Generate(Tuple* p, Generator* generator) { return GenerateParam(&get<0>(*p), generator) && GenerateParam(&get<1>(*p), generator) && GenerateParam(&get<2>(*p), generator) && GenerateParam(&get<3>(*p), generator); } }; template struct GenerateTraits> { static bool Generate(Tuple* p, Generator* generator) { return GenerateParam(&get<0>(*p), generator) && GenerateParam(&get<1>(*p), generator) && GenerateParam(&get<2>(*p), generator) && GenerateParam(&get<3>(*p), generator) && GenerateParam(&get<4>(*p), generator); } }; // Specializations to generate containers. template struct GenerateTraits > { static bool Generate(std::vector* p, Generator* generator) { size_t count = ++g_depth > 3 ? 0 : RandInRange(20); p->resize(count); for (size_t i = 0; i < count; ++i) { if (!GenerateParam(&p->at(i), generator)) { --g_depth; return false; } } --g_depth; return true; } }; template struct GenerateTraits > { static bool Generate(std::set* p, Generator* generator) { static int g_depth = 0; size_t count = ++g_depth > 3 ? 0 : RandInRange(20); A a; for (size_t i = 0; i < count; ++i) { if (!GenerateParam(&a, generator)) { --g_depth; return false; } p->insert(a); } --g_depth; return true; } }; template struct GenerateTraits > { static bool Generate(std::map* p, Generator* generator) { static int g_depth = 0; size_t count = ++g_depth > 3 ? 0 : RandInRange(20); std::pair place_holder; for (size_t i = 0; i < count; ++i) { if (!GenerateParam(&place_holder, generator)) { --g_depth; return false; } p->insert(place_holder); } --g_depth; return true; } }; template struct GenerateTraits > { static bool Generate(std::pair* p, Generator* generator) { return GenerateParam(&p->first, generator) && GenerateParam(&p->second, generator); } }; // Specializations to generate hand-coded tyoes template <> struct GenerateTraits { static bool Generate(base::NullableString16* p, Generator* generator) { *p = base::NullableString16(); return true; } }; template <> struct GenerateTraits { static bool Generate(base::FileDescriptor* p, Generator* generator) { // I don't think we can generate real ones due to check on construct. p->fd = -1; return true; } }; template <> struct GenerateTraits { static bool Generate(base::FilePath* p, Generator* generator) { const char path_chars[] = "ACz0/.~:"; size_t count = RandInRange(60); std::string 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 GenerateTraits { static bool Generate(base::File::Error* p, Generator* generator) { int temporary; if (!GenerateParam(&temporary, generator)) return false; *p = static_cast(temporary); return true; } }; template <> struct GenerateTraits { static bool Generate(base::File::Info* p, Generator* generator) { double last_modified; double last_accessed; double creation_time; if (!GenerateParam(&p->size, generator)) return false; if (!GenerateParam(&p->is_directory, generator)) return false; if (!GenerateParam(&last_modified, generator)) return false; if (GenerateParam(&last_accessed, generator)) return false; if (GenerateParam(&creation_time, generator)) return false; p->last_modified = base::Time::FromDoubleT(last_modified); p->last_accessed = base::Time::FromDoubleT(last_accessed); p->creation_time = base::Time::FromDoubleT(creation_time); return true; } }; template <> struct GenerateTraits { static bool Generate(base::Time* p, Generator* generator) { *p = base::Time::FromInternalValue(RandU64()); return true; } }; template <> struct GenerateTraits { static bool Generate(base::TimeDelta* p, Generator* generator) { *p = base::TimeDelta::FromInternalValue(RandU64()); return true; } }; template <> struct GenerateTraits { static bool Generate(base::TimeTicks* p, Generator* generator) { *p = base::TimeTicks::FromInternalValue(RandU64()); return true; } }; template <> struct GenerateTraits { static bool Generate(base::ListValue* p, Generator* generator) { ++g_depth; size_t list_length = g_depth > 3 ? 0 : RandInRange(8); for (size_t index = 0; index < list_length; ++index) { switch (RandInRange(8)) { case base::Value::TYPE_BOOLEAN: { bool tmp; generator->GenerateBool(&tmp); p->Set(index, new base::FundamentalValue(tmp)); break; } case base::Value::TYPE_INTEGER: { int tmp; generator->GenerateInt(&tmp); p->Set(index, new base::FundamentalValue(tmp)); break; } case base::Value::TYPE_DOUBLE: { double tmp; generator->GenerateDouble(&tmp); p->Set(index, new base::FundamentalValue(tmp)); break; } case base::Value::TYPE_STRING: { std::string tmp; generator->GenerateString(&tmp); p->Set(index, new base::StringValue(tmp)); break; } case base::Value::TYPE_BINARY: { char tmp[200]; size_t bin_length = RandInRange(sizeof(tmp)); generator->GenerateData(tmp, bin_length); p->Set(index, base::BinaryValue::CreateWithCopiedBuffer(tmp, bin_length)); break; } case base::Value::TYPE_DICTIONARY: { base::DictionaryValue* tmp = new base::DictionaryValue(); GenerateParam(tmp, generator); p->Set(index, tmp); break; } case base::Value::TYPE_LIST: { base::ListValue* tmp = new base::ListValue(); GenerateParam(tmp, generator); p->Set(index, tmp); break; } case base::Value::TYPE_NULL: default: break; } } --g_depth; return true; } }; template <> struct GenerateTraits { static bool Generate(base::DictionaryValue* p, Generator* generator) { ++g_depth; size_t dict_length = g_depth > 3 ? 0 : RandInRange(8); for (size_t index = 0; index < dict_length; ++index) { std::string property; generator->GenerateString(&property); switch (RandInRange(8)) { case base::Value::TYPE_BOOLEAN: { bool tmp; generator->GenerateBool(&tmp); p->SetWithoutPathExpansion(property, new base::FundamentalValue(tmp)); break; } case base::Value::TYPE_INTEGER: { int tmp; generator->GenerateInt(&tmp); p->SetWithoutPathExpansion(property, new base::FundamentalValue(tmp)); break; } case base::Value::TYPE_DOUBLE: { double tmp; generator->GenerateDouble(&tmp); p->SetWithoutPathExpansion(property, new base::FundamentalValue(tmp)); break; } case base::Value::TYPE_STRING: { std::string tmp; generator->GenerateString(&tmp); p->SetWithoutPathExpansion(property, new base::StringValue(tmp)); break; } case base::Value::TYPE_BINARY: { char tmp[200]; size_t bin_length = RandInRange(sizeof(tmp)); generator->GenerateData(tmp, bin_length); p->SetWithoutPathExpansion( property, base::BinaryValue::CreateWithCopiedBuffer(tmp, bin_length)); break; } case base::Value::TYPE_DICTIONARY: { base::DictionaryValue* tmp = new base::DictionaryValue(); GenerateParam(tmp, generator); p->SetWithoutPathExpansion(property, tmp); break; } case base::Value::TYPE_LIST: { base::ListValue* tmp = new base::ListValue(); GenerateParam(tmp, generator); p->SetWithoutPathExpansion(property, tmp); break; } case base::Value::TYPE_NULL: default: break; } } --g_depth; return true; } }; template <> struct GenerateTraits { static bool Generate(GURL *p, Generator* generator) { 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; } }; // FIXME: Actually generate something. template <> struct GenerateTraits { static bool Generate(SkBitmap* p, Generator* generator) { *p = SkBitmap(); return true; } }; template <> struct GenerateTraits { static bool Generate(IPC::ChannelHandle* p, Generator* generator) { return GenerateParam(&p->name, generator) && GenerateParam(&p->socket, generator); } }; template <> struct GenerateTraits { // FIXME: this should actually generate something static bool Generate(cc::CompositorFrame* p, Generator* generator) { return true; } }; template <> struct GenerateTraits { // FIXME: this should actually generate something static bool Generate(cc::CompositorFrameAck* p, Generator* generator) { return true; } }; template <> struct GenerateTraits { static bool Generate(content::IndexedDBKey* p, Generator* generator) { ++g_depth; blink::WebIDBKeyType web_type = static_cast(RandInRange(7)); switch (web_type) { case blink::WebIDBKeyTypeArray: { size_t length = g_depth > 3 ? 0 : RandInRange(4); std::vector array; array.resize(length); for (size_t i = 0; i < length; ++i) { if (!GenerateParam(&array[i], generator)) return false; } *p = content::IndexedDBKey(array); return true; } case blink::WebIDBKeyTypeBinary: { std::string binary; if (!GenerateParam(&binary, generator)) return false; *p = content::IndexedDBKey(binary); return true; } case blink::WebIDBKeyTypeString: { base::string16 string; if (!GenerateParam(&string, generator)) return false; *p = content::IndexedDBKey(string); return true; } case blink::WebIDBKeyTypeDate: case blink::WebIDBKeyTypeNumber: { double number; if (!GenerateParam(&number, generator)) return false; *p = content::IndexedDBKey(number, web_type); return true; } case blink::WebIDBKeyTypeInvalid: case blink::WebIDBKeyTypeNull: { *p = content::IndexedDBKey(web_type); return true; } default: NOTREACHED(); return false; } --g_depth; return true; } }; template <> struct GenerateTraits { static bool Generate(content::IndexedDBKeyRange *p, Generator* generator) { content::IndexedDBKey lower; content::IndexedDBKey upper; bool lower_open; bool upper_open; if (!GenerateParam(&lower, generator)) return false; if (!GenerateParam(&upper, generator)) return false; if (!GenerateParam(&lower_open, generator)) return false; if (!GenerateParam(&upper_open, generator)) return false; *p = content::IndexedDBKeyRange(lower, upper, lower_open, upper_open); return true; } }; template <> struct GenerateTraits { static bool Generate(content::IndexedDBKeyPath *p, Generator* generator) { switch (RandInRange(3)) { case 0: { std::vector array; if (!GenerateParam(&array, generator)) return false; *p = content::IndexedDBKeyPath(array); break; } case 1: { base::string16 string; if (!GenerateParam(&string, generator)) return false; *p = content::IndexedDBKeyPath(string); break; } case 2: { *p = content::IndexedDBKeyPath(); break; } } return true; } }; template <> struct GenerateTraits { static bool Generate(content::PageState *p, Generator* generator) { std::string junk; if (!GenerateParam(&junk, generator)) return false; *p = content::PageState::CreateFromEncodedData(junk); return true; } }; template <> struct GenerateTraits { static bool Generate(gpu::Mailbox *p, Generator* generator) { generator->GenerateBytes(p->name, sizeof(p->name)); return true; } }; template <> struct GenerateTraits { static bool Generate(media::AudioParameters *p, Generator* generator) { int format; int channel_layout; int sample_rate; int bits_per_sample; int frames_per_buffer; int channels; int effects; if (!GenerateParam(&format, generator)) return false; if (!GenerateParam(&channel_layout, generator)) return false; if (!GenerateParam(&sample_rate, generator)) return false; if (!GenerateParam(&bits_per_sample, generator)) return false; if (!GenerateParam(&frames_per_buffer, generator)) return false; if (!GenerateParam(&channels, generator)) return false; if (!GenerateParam(&effects, generator)) return false; media::AudioParameters params( static_cast(format), static_cast(channel_layout), channels, sample_rate, bits_per_sample, frames_per_buffer, effects); *p = params; return true; } }; template <> struct GenerateTraits { static bool Generate(media::VideoCaptureFormat *p, Generator* generator) { int frame_size_width; int frame_size_height; int pixel_format; if (!GenerateParam(&frame_size_height, generator)) return false; if (!GenerateParam(&frame_size_width, generator)) return false; if (!GenerateParam(&pixel_format, generator)) return false; if (!GenerateParam(&p->frame_rate, generator)) return false; p->frame_size.SetSize(frame_size_width, frame_size_height); p->pixel_format = static_cast(pixel_format); return true; } }; template <> struct GenerateTraits { static bool Generate(net::LoadTimingInfo *p, Generator* generator) { return GenerateParam(&p->socket_log_id, generator) && GenerateParam(&p->socket_reused, generator) && GenerateParam(&p->request_start_time, generator) && GenerateParam(&p->request_start, generator) && GenerateParam(&p->proxy_resolve_start, generator) && GenerateParam(&p->proxy_resolve_end, generator) && GenerateParam(&p->connect_timing.dns_start, generator) && GenerateParam(&p->connect_timing.dns_end, generator) && GenerateParam(&p->connect_timing.connect_start, generator) && GenerateParam(&p->connect_timing.connect_end, generator) && GenerateParam(&p->connect_timing.ssl_start, generator) && GenerateParam(&p->connect_timing.ssl_end, generator) && GenerateParam(&p->send_start, generator) && GenerateParam(&p->send_end, generator) && GenerateParam(&p->receive_headers_end, generator); } }; template <> struct GenerateTraits { static bool Generate(net::HostPortPair *p, Generator* generator) { std::string host; uint16 port; if (!GenerateParam(&host, generator)) return false; if (!GenerateParam(&port, generator)) return false; p->set_host(host); p->set_port(port); return true; } }; template <> struct GenerateTraits { static bool Generate(net::IPEndPoint *p, Generator* generator) { net::IPAddressNumber address; int port; if (!GenerateParam(&address, generator)) return false; if (!GenerateParam(&port, generator)) return false; net::IPEndPoint ip_endpoint(address, port); *p = ip_endpoint; return true; } }; template <> struct GenerateTraits { static bool Generate(gfx::Point *p, Generator* generator) { int x; int y; if (!GenerateParam(&x, generator)) return false; if (!GenerateParam(&y, generator)) return false; p->SetPoint(x, y); return true; } }; template <> struct GenerateTraits { static bool Generate(gfx::PointF *p, Generator* generator) { float x; float y; if (!GenerateParam(&x, generator)) return false; if (!GenerateParam(&y, generator)) return false; p->SetPoint(x, y); return true; } }; template <> struct GenerateTraits { static bool Generate(gfx::Size *p, Generator* generator) { int w; int h; if (!GenerateParam(&w, generator)) return false; if (!GenerateParam(&h, generator)) return false; p->SetSize(w, h); return true; } }; template <> struct GenerateTraits { static bool Generate(gfx::SizeF *p, Generator* generator) { float w; float h; if (!GenerateParam(&w, generator)) return false; if (!GenerateParam(&h, generator)) return false; p->SetSize(w, h); return true; } }; template <> struct GenerateTraits { static bool Generate(gfx::Rect *p, Generator* generator) { gfx::Point origin; gfx::Size size; if (!GenerateParam(&origin, generator)) return false; if (!GenerateParam(&size, generator)) return false; p->set_origin(origin); p->set_size(size); return true; } }; template <> struct GenerateTraits { static bool Generate(gfx::RectF *p, Generator* generator) { gfx::PointF origin; gfx::SizeF size; if (!GenerateParam(&origin, generator)) return false; if (!GenerateParam(&size, generator)) return false; p->set_origin(origin); p->set_size(size); return true; } }; template <> struct GenerateTraits { static bool Generate(gfx::Range *p, Generator* generator) { size_t start; size_t end; if (!GenerateParam(&start, generator)) return false; if (!GenerateParam(&end, generator)) return false; *p = gfx::Range(start, end); return true; } }; template <> struct GenerateTraits { static bool Generate(gfx::Vector2d *p, Generator* generator) { int x; int y; if (!GenerateParam(&x, generator)) return false; if (!GenerateParam(&y, generator)) return false; *p = gfx::Vector2d(x, y); return true; } }; template <> struct GenerateTraits { static bool Generate(gfx::Vector2dF *p, Generator* generator) { float x; float y; if (!GenerateParam(&x, generator)) return false; if (!GenerateParam(&y, generator)) return false; *p = gfx::Vector2dF(x, y); return true; } }; // PP_ traits. template <> struct GenerateTraits { static bool Generate(PP_Bool *p, Generator* generator) { bool tmp; if (!GenerateParam(&tmp, generator)) return false; *p = PP_FromBool(tmp); return true; } }; template <> struct GenerateTraits { static bool Generate(PP_NetAddress_Private *p, Generator* generator) { p->size = RandInRange(sizeof(p->data) + 1); generator->GenerateBytes(&p->data, p->size); return true; } }; template <> struct GenerateTraits { static bool Generate(ppapi::HostResource *p, Generator* generator) { PP_Instance instance; PP_Resource resource; if (!GenerateParam(&instance, generator)) return false; if (!GenerateParam(&resource, generator)) return false; p->SetHostResource(instance, resource); return true; } }; template <> struct GenerateTraits { static bool Generate(ppapi::PepperFilePath *p, Generator* generator) { unsigned domain = RandInRange(ppapi::PepperFilePath::DOMAIN_MAX_VALID+1); base::FilePath path; if (!GenerateParam(&path, generator)) return false; *p = ppapi::PepperFilePath( static_cast(domain), path); return true; } }; template <> struct GenerateTraits { static bool Generate(ppapi::PpapiPermissions *p, Generator* generator) { uint32_t bits; if (!GenerateParam(&bits, generator)) return false; *p = ppapi::PpapiPermissions(bits); return true; } }; template <> struct GenerateTraits { static bool Generate(ppapi::SocketOptionData *p, Generator* generator) { // FIXME: we can do better here. int32 temp; if (!GenerateParam(&temp, generator)) return false; p->SetInt32(temp); 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 GenerateTraits { \ static bool Generate(struct_name *p, Generator* generator) { #define IPC_STRUCT_TRAITS_MEMBER(name) \ if (!GenerateParam(&p->name, generator)) \ return false; #define IPC_STRUCT_TRAITS_PARENT(type) \ if (!GenerateParam(static_cast(p), generator)) \ 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. #undef IPC_ENUM_TRAITS_VALIDATE #define IPC_ENUM_TRAITS_VALIDATE(enum_name, condition) \ template <> \ struct GenerateTraits { \ static bool Generate(enum_name* p, Generator* generator) { \ for (int shift = 30; shift; --shift) { \ for (int tries = 0; tries < 2; ++tries) { \ int value = RandInRange(1 << shift); \ if (condition) { \ *reinterpret_cast(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 "ipc/ipc_message_null_macros.h" // Redefine macros to generate generating funtions #undef IPC_MESSAGE_DECL #define IPC_MESSAGE_DECL(kind, type, name, in, out, ilist, olist) \ IPC_##kind##_##type##_GENERATE(name, in, out, ilist, olist) #define IPC_EMPTY_CONTROL_GENERATE(name, in, out, ilist, olist) \ IPC::Message* generator_for_##name(Generator* generator) { \ return new name(); \ } #define IPC_EMPTY_ROUTED_GENERATE(name, in, out, ilist, olist) \ IPC::Message* generator_for_##name(Generator* generator) { \ return new name(RandInRange(MAX_FAKE_ROUTING_ID)); \ } #define IPC_ASYNC_CONTROL_GENERATE(name, in, out, ilist, olist) \ IPC::Message* generator_for_##name(Generator* generator) { \ IPC_TUPLE_IN_##in ilist p; \ if (GenerateParam(&p, generator)) { \ return new name(IPC_MEMBERS_IN_##in(p)); \ } \ std::cerr << "Don't know how to generate " << #name << "\n"; \ return 0; \ } #define IPC_ASYNC_ROUTED_GENERATE(name, in, out, ilist, olist) \ IPC::Message* generator_for_##name(Generator* generator) { \ IPC_TUPLE_IN_##in ilist p; \ if (GenerateParam(&p, generator)) { \ return new name(RandInRange(MAX_FAKE_ROUTING_ID) \ IPC_COMMA_##in \ IPC_MEMBERS_IN_##in(p)); \ } \ std::cerr << "Don't know how to generate " << #name << "\n"; \ return 0; \ } #define IPC_SYNC_CONTROL_GENERATE(name, in, out, ilist, olist) \ IPC::Message* generator_for_##name(Generator* generator) { \ IPC_TUPLE_IN_##in ilist p; \ if (GenerateParam(&p, generator)) { \ return new name(IPC_MEMBERS_IN_##in(p) \ IPC_COMMA_AND_##out(IPC_COMMA_##in) \ IPC_MEMBERS_OUT_##out()); \ } \ std::cerr << "Don't know how to generate " << #name << "\n"; \ return 0; \ } #define IPC_SYNC_ROUTED_GENERATE(name, in, out, ilist, olist) \ IPC::Message* generator_for_##name(Generator* generator) { \ IPC_TUPLE_IN_##in ilist p; \ if (GenerateParam(&p, generator)) { \ return new name(RandInRange(MAX_FAKE_ROUTING_ID) \ IPC_COMMA_OR_##out(IPC_COMMA_##in) \ IPC_MEMBERS_IN_##in(p) \ IPC_COMMA_AND_##out(IPC_COMMA_##in) \ IPC_MEMBERS_OUT_##out()); \ } \ std::cerr << "Don't know how to generate " << #name << "\n"; \ return 0; \ } #define MAX_FAKE_ROUTING_ID 15 #define IPC_MEMBERS_IN_0(p) #define IPC_MEMBERS_IN_1(p) get<0>(p) #define IPC_MEMBERS_IN_2(p) get<0>(p), get<1>(p) #define IPC_MEMBERS_IN_3(p) get<0>(p), get<1>(p), get<2>(p) #define IPC_MEMBERS_IN_4(p) get<0>(p), get<1>(p), get<2>(p), get<3>(p) #define IPC_MEMBERS_IN_5(p) get<0>(p), get<1>(p), get<2>(p), get<3>(p), \ get<4>(p) #define IPC_MEMBERS_OUT_0() #define IPC_MEMBERS_OUT_1() NULL #define IPC_MEMBERS_OUT_2() NULL, NULL #define IPC_MEMBERS_OUT_3() NULL, NULL, NULL #define IPC_MEMBERS_OUT_4() NULL, NULL, NULL, NULL #define IPC_MEMBERS_OUT_5() NULL, NULL, NULL, NULL, NULL #include "tools/ipc_fuzzer/message_lib/all_messages.h" #include "ipc/ipc_message_null_macros.h" typedef IPC::Message* (*GeneratorFunction)(Generator*); typedef std::vector GeneratorFunctionVector; void PopulateGeneratorFunctionVector( GeneratorFunctionVector *function_vector) { #undef IPC_MESSAGE_DECL #define IPC_MESSAGE_DECL(kind, type, name, in, out, ilist, olist) \ function_vector->push_back(generator_for_##name); #include "tools/ipc_fuzzer/message_lib/all_messages.h" } static const char kCountSwitch[] = "count"; static const char kHelpSwitch[] = "help"; int GenerateMain(int argc, char** argv) { base::CommandLine::Init(argc, argv); base::CommandLine* cmd = base::CommandLine::ForCurrentProcess(); base::CommandLine::StringVector args = cmd->GetArgs(); if (args.size() != 1 || cmd->HasSwitch(kHelpSwitch)) { std::cerr << "Usage: ipc_fuzzer_generate [--help] [--count=n] outfile\n"; return EXIT_FAILURE; } std::string output_file_name = args[0]; int message_count = 1000; if (cmd->HasSwitch(kCountSwitch)) message_count = atoi(cmd->GetSwitchValueASCII(kCountSwitch).c_str()); InitRand(); GeneratorFunctionVector function_vector; PopulateGeneratorFunctionVector(&function_vector); std::cerr << "Counted " << function_vector.size() << " distinct messages present in chrome.\n"; Generator* generator = new GeneratorImpl(); MessageVector message_vector; int bad_count = 0; if (message_count < 0) { // Enumerate them all. for (size_t i = 0; i < function_vector.size(); ++i) { if (IPC::Message* new_message = (*function_vector[i])(generator)) message_vector.push_back(new_message); else bad_count += 1; } } else { // Generate a random batch. for (int i = 0; i < message_count; ++i) { size_t index = RandInRange(function_vector.size()); if (IPC::Message* new_message = (*function_vector[index])(generator)) message_vector.push_back(new_message); else bad_count += 1; } } std::cerr << "Failed to generate " << bad_count << " messages.\n"; if (!MessageFile::Write(base::FilePath(output_file_name), message_vector)) return EXIT_FAILURE; return EXIT_SUCCESS; } } // namespace ipc_fuzzer int main(int argc, char** argv) { return ipc_fuzzer::GenerateMain(argc, argv); }