Merge "Revert "libsnapshot_fuzzer: Add tests""
This commit is contained in:
commit
75f8236bb9
4 changed files with 84 additions and 248 deletions
|
|
@ -14,9 +14,6 @@
|
|||
},
|
||||
{
|
||||
"name": "vts_libsnapshot_test"
|
||||
},
|
||||
{
|
||||
"name": "libsnapshot_fuzzer_test"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -246,8 +246,8 @@ cc_test {
|
|||
gtest: false,
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "libsnapshot_fuzzer_defaults",
|
||||
cc_fuzz {
|
||||
name: "libsnapshot_fuzzer",
|
||||
|
||||
// TODO(b/154633114): make host supported.
|
||||
// host_supported: true,
|
||||
|
|
@ -289,11 +289,6 @@ cc_defaults {
|
|||
canonical_path_from_root: false,
|
||||
local_include_dirs: ["."],
|
||||
},
|
||||
}
|
||||
|
||||
cc_fuzz {
|
||||
name: "libsnapshot_fuzzer",
|
||||
defaults: ["libsnapshot_fuzzer_defaults"],
|
||||
corpus: ["corpus/*"],
|
||||
fuzz_config: {
|
||||
cc: ["android-virtual-ab+bugs@google.com"],
|
||||
|
|
@ -303,14 +298,3 @@ cc_fuzz {
|
|||
fuzz_on_haiku_device: true,
|
||||
},
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "libsnapshot_fuzzer_test",
|
||||
defaults: ["libsnapshot_fuzzer_defaults"],
|
||||
data: ["corpus/*"],
|
||||
test_suites: [
|
||||
"device-tests",
|
||||
],
|
||||
auto_gen_config: true,
|
||||
require_root: true,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,25 +68,17 @@ int CheckConsistency() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Get the field descriptor for the oneof field in the action message. If no oneof field is set,
|
||||
// return nullptr.
|
||||
template <typename Action>
|
||||
const google::protobuf::FieldDescriptor* GetValueFieldDescriptor(
|
||||
const typename Action::Proto& action_proto) {
|
||||
void ExecuteActionProto(typename Action::Class* module,
|
||||
const typename Action::Proto& action_proto) {
|
||||
static auto* action_value_desc = GetProtoValueDescriptor(Action::Proto::GetDescriptor());
|
||||
|
||||
auto* action_refl = Action::Proto::GetReflection();
|
||||
if (!action_refl->HasOneof(action_proto, action_value_desc)) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
return action_refl->GetOneofFieldDescriptor(action_proto, action_value_desc);
|
||||
}
|
||||
|
||||
template <typename Action>
|
||||
void ExecuteActionProto(typename Action::ClassType* module,
|
||||
const typename Action::Proto& action_proto) {
|
||||
const auto* field_desc = GetValueFieldDescriptor<Action>(action_proto);
|
||||
if (field_desc == nullptr) return;
|
||||
const auto* field_desc = action_refl->GetOneofFieldDescriptor(action_proto, action_value_desc);
|
||||
auto number = field_desc->number();
|
||||
const auto& map = *Action::GetFunctionMap();
|
||||
auto it = map.find(number);
|
||||
|
|
@ -97,7 +89,7 @@ void ExecuteActionProto(typename Action::ClassType* module,
|
|||
|
||||
template <typename Action>
|
||||
void ExecuteAllActionProtos(
|
||||
typename Action::ClassType* module,
|
||||
typename Action::Class* module,
|
||||
const google::protobuf::RepeatedPtrField<typename Action::Proto>& action_protos) {
|
||||
for (const auto& proto : action_protos) {
|
||||
ExecuteActionProto<Action>(module, proto);
|
||||
|
|
@ -142,57 +134,53 @@ FUZZ_DEFINE_PRIMITIVE_GETTER(float, GetFloat);
|
|||
// ActionPerformer extracts arguments from the protobuf message, and then call FuzzFunction
|
||||
// with these arguments.
|
||||
template <typename FuzzFunction, typename Signature, typename Enabled = void>
|
||||
struct ActionPerformerImpl; // undefined
|
||||
struct ActionPerfomer; // undefined
|
||||
|
||||
template <typename FuzzFunction, typename MessageProto>
|
||||
struct ActionPerformerImpl<
|
||||
struct ActionPerfomer<
|
||||
FuzzFunction, void(const MessageProto&),
|
||||
typename std::enable_if_t<std::is_base_of_v<google::protobuf::Message, MessageProto>>> {
|
||||
static typename FuzzFunction::ReturnType Invoke(
|
||||
typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
|
||||
const google::protobuf::FieldDescriptor* field_desc) {
|
||||
static void Invoke(typename FuzzFunction::Class* module,
|
||||
const google::protobuf::Message& action_proto,
|
||||
const google::protobuf::FieldDescriptor* field_desc) {
|
||||
const MessageProto& arg = CheckedCast<std::remove_reference_t<MessageProto>>(
|
||||
action_proto.GetReflection()->GetMessage(action_proto, field_desc));
|
||||
return FuzzFunction::ImplBody(module, arg);
|
||||
FuzzFunction::ImplBody(module, arg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename FuzzFunction, typename Primitive>
|
||||
struct ActionPerformerImpl<FuzzFunction, void(Primitive),
|
||||
typename std::enable_if_t<std::is_arithmetic_v<Primitive>>> {
|
||||
static typename FuzzFunction::ReturnType Invoke(
|
||||
typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
|
||||
const google::protobuf::FieldDescriptor* field_desc) {
|
||||
struct ActionPerfomer<FuzzFunction, void(Primitive),
|
||||
typename std::enable_if_t<std::is_arithmetic_v<Primitive>>> {
|
||||
static void Invoke(typename FuzzFunction::Class* module,
|
||||
const google::protobuf::Message& action_proto,
|
||||
const google::protobuf::FieldDescriptor* field_desc) {
|
||||
Primitive arg = std::invoke(PrimitiveGetter<Primitive>::fp, action_proto.GetReflection(),
|
||||
action_proto, field_desc);
|
||||
return FuzzFunction::ImplBody(module, arg);
|
||||
FuzzFunction::ImplBody(module, arg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename FuzzFunction>
|
||||
struct ActionPerformerImpl<FuzzFunction, void()> {
|
||||
static typename FuzzFunction::ReturnType Invoke(typename FuzzFunction::ClassType* module,
|
||||
const google::protobuf::Message&,
|
||||
const google::protobuf::FieldDescriptor*) {
|
||||
return FuzzFunction::ImplBody(module);
|
||||
struct ActionPerfomer<FuzzFunction, void()> {
|
||||
static void Invoke(typename FuzzFunction::Class* module, const google::protobuf::Message&,
|
||||
const google::protobuf::FieldDescriptor*) {
|
||||
FuzzFunction::ImplBody(module);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename FuzzFunction>
|
||||
struct ActionPerformerImpl<FuzzFunction, void(const std::string&)> {
|
||||
static typename FuzzFunction::ReturnType Invoke(
|
||||
typename FuzzFunction::ClassType* module, const google::protobuf::Message& action_proto,
|
||||
const google::protobuf::FieldDescriptor* field_desc) {
|
||||
struct ActionPerfomer<FuzzFunction, void(const std::string&)> {
|
||||
static void Invoke(typename FuzzFunction::Class* module,
|
||||
const google::protobuf::Message& action_proto,
|
||||
const google::protobuf::FieldDescriptor* field_desc) {
|
||||
std::string scratch;
|
||||
const std::string& arg = action_proto.GetReflection()->GetStringReference(
|
||||
action_proto, field_desc, &scratch);
|
||||
return FuzzFunction::ImplBody(module, arg);
|
||||
FuzzFunction::ImplBody(module, arg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename FuzzFunction>
|
||||
struct ActionPerformer : ActionPerformerImpl<FuzzFunction, typename FuzzFunction::Signature> {};
|
||||
|
||||
} // namespace android::fuzz
|
||||
|
||||
// Fuzz existing C++ class, ClassType, with a collection of functions under the name Action.
|
||||
|
|
@ -209,11 +197,11 @@ struct ActionPerformer : ActionPerformerImpl<FuzzFunction, typename FuzzFunction
|
|||
// FUZZ_CLASS(Foo, FooAction)
|
||||
// After linking functions of Foo to FooAction, execute all actions by:
|
||||
// FooAction::ExecuteAll(foo_object, action_protos)
|
||||
#define FUZZ_CLASS(Class, Action) \
|
||||
#define FUZZ_CLASS(ClassType, Action) \
|
||||
class Action { \
|
||||
public: \
|
||||
using Proto = Action##Proto; \
|
||||
using ClassType = Class; \
|
||||
using Class = ClassType; \
|
||||
using FunctionMap = android::fuzz::FunctionMap<Class>; \
|
||||
static FunctionMap* GetFunctionMap() { \
|
||||
static Action::FunctionMap map; \
|
||||
|
|
@ -237,33 +225,29 @@ struct ActionPerformer : ActionPerformerImpl<FuzzFunction, typename FuzzFunction
|
|||
// }
|
||||
// class Foo { public: void DoAwesomeFoo(bool arg); };
|
||||
// FUZZ_OBJECT(FooAction, Foo);
|
||||
// FUZZ_FUNCTION(FooAction, DoFoo, void, IFoo* module, bool arg) {
|
||||
// FUZZ_FUNCTION(FooAction, DoFoo, module, bool arg) {
|
||||
// module->DoAwesomeFoo(arg);
|
||||
// }
|
||||
// The name DoFoo is the camel case name of the action in protobuf definition of FooActionProto.
|
||||
#define FUZZ_FUNCTION(Action, FunctionName, Return, ModuleArg, ...) \
|
||||
class FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName) { \
|
||||
public: \
|
||||
using ActionType = Action; \
|
||||
using ClassType = Action::ClassType; \
|
||||
using ReturnType = Return; \
|
||||
using Signature = void(__VA_ARGS__); \
|
||||
static constexpr const char name[] = #FunctionName; \
|
||||
static constexpr const auto tag = \
|
||||
Action::Proto::ValueCase::FUZZ_FUNCTION_TAG_NAME(FunctionName); \
|
||||
static ReturnType ImplBody(ModuleArg, ##__VA_ARGS__); \
|
||||
\
|
||||
private: \
|
||||
static bool registered_; \
|
||||
}; \
|
||||
auto FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::registered_ = ([] { \
|
||||
auto tag = FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::tag; \
|
||||
auto func = &::android::fuzz::ActionPerformer<FUZZ_FUNCTION_CLASS_NAME( \
|
||||
Action, FunctionName)>::Invoke; \
|
||||
Action::GetFunctionMap()->CheckEmplace(tag, func); \
|
||||
return true; \
|
||||
})(); \
|
||||
Return FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::ImplBody(ModuleArg, ##__VA_ARGS__)
|
||||
#define FUZZ_FUNCTION(Action, FunctionName, module, ...) \
|
||||
class FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName) { \
|
||||
public: \
|
||||
using Class = Action::Class; \
|
||||
static void ImplBody(Action::Class*, ##__VA_ARGS__); \
|
||||
\
|
||||
private: \
|
||||
static bool registered_; \
|
||||
}; \
|
||||
auto FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::registered_ = ([] { \
|
||||
auto tag = Action::Proto::ValueCase::FUZZ_FUNCTION_TAG_NAME(FunctionName); \
|
||||
auto func = \
|
||||
&::android::fuzz::ActionPerfomer<FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName), \
|
||||
void(__VA_ARGS__)>::Invoke; \
|
||||
Action::GetFunctionMap()->CheckEmplace(tag, func); \
|
||||
return true; \
|
||||
})(); \
|
||||
void FUZZ_FUNCTION_CLASS_NAME(Action, FunctionName)::ImplBody(Action::Class* module, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
// Implement a simple action by linking it to the function with the same name. Example:
|
||||
// message FooActionProto {
|
||||
|
|
@ -277,9 +261,5 @@ struct ActionPerformer : ActionPerformerImpl<FuzzFunction, typename FuzzFunction
|
|||
// FUZZ_FUNCTION(FooAction, DoBar);
|
||||
// The name DoBar is the camel case name of the action in protobuf definition of FooActionProto, and
|
||||
// also the name of the function of Foo.
|
||||
#define FUZZ_SIMPLE_FUNCTION(Action, FunctionName) \
|
||||
FUZZ_FUNCTION(Action, FunctionName, \
|
||||
decltype(std::declval<Action::ClassType>().FunctionName()), \
|
||||
Action::ClassType* module) { \
|
||||
return module->FunctionName(); \
|
||||
}
|
||||
#define FUZZ_SIMPLE_FUNCTION(Action, FunctionName) \
|
||||
FUZZ_FUNCTION(Action, FunctionName, module) { (void)module->FunctionName(); }
|
||||
|
|
|
|||
|
|
@ -21,21 +21,14 @@
|
|||
#include <tuple>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/result.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <src/libfuzzer/libfuzzer_macro.h>
|
||||
#include <storage_literals/storage_literals.h>
|
||||
|
||||
#include "fuzz_utils.h"
|
||||
#include "snapshot_fuzz_utils.h"
|
||||
|
||||
using android::base::Error;
|
||||
using android::base::GetBoolProperty;
|
||||
using android::base::LogId;
|
||||
using android::base::LogSeverity;
|
||||
using android::base::ReadFileToString;
|
||||
using android::base::Result;
|
||||
using android::base::SetLogger;
|
||||
using android::base::StderrLogger;
|
||||
using android::base::StdioLogger;
|
||||
|
|
@ -44,8 +37,6 @@ using android::fuzz::CheckedCast;
|
|||
using android::snapshot::SnapshotFuzzData;
|
||||
using android::snapshot::SnapshotFuzzEnv;
|
||||
using chromeos_update_engine::DeltaArchiveManifest;
|
||||
using google::protobuf::FieldDescriptor;
|
||||
using google::protobuf::Message;
|
||||
using google::protobuf::RepeatedPtrField;
|
||||
|
||||
// Avoid linking to libgsi since it needs disk I/O.
|
||||
|
|
@ -83,49 +74,48 @@ FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, RecoveryCreateSnapshotDevices);
|
|||
FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, EnsureMetadataMounted);
|
||||
FUZZ_SIMPLE_FUNCTION(SnapshotManagerAction, GetSnapshotMergeStatsInstance);
|
||||
|
||||
#define SNAPSHOT_FUZZ_FUNCTION(FunctionName, ReturnType, ...) \
|
||||
FUZZ_FUNCTION(SnapshotManagerAction, FunctionName, ReturnType, ISnapshotManager* snapshot, \
|
||||
##__VA_ARGS__)
|
||||
#define SNAPSHOT_FUZZ_FUNCTION(FunctionName, ...) \
|
||||
FUZZ_FUNCTION(SnapshotManagerAction, FunctionName, snapshot, ##__VA_ARGS__)
|
||||
|
||||
SNAPSHOT_FUZZ_FUNCTION(FinishedSnapshotWrites, bool, bool wipe) {
|
||||
return snapshot->FinishedSnapshotWrites(wipe);
|
||||
SNAPSHOT_FUZZ_FUNCTION(FinishedSnapshotWrites, bool wipe) {
|
||||
(void)snapshot->FinishedSnapshotWrites(wipe);
|
||||
}
|
||||
|
||||
SNAPSHOT_FUZZ_FUNCTION(ProcessUpdateState, bool, const ProcessUpdateStateArgs& args) {
|
||||
SNAPSHOT_FUZZ_FUNCTION(ProcessUpdateState, const ProcessUpdateStateArgs& args) {
|
||||
std::function<bool()> before_cancel;
|
||||
if (args.has_before_cancel()) {
|
||||
before_cancel = [&]() { return args.fail_before_cancel(); };
|
||||
}
|
||||
return snapshot->ProcessUpdateState({}, before_cancel);
|
||||
(void)snapshot->ProcessUpdateState({}, before_cancel);
|
||||
}
|
||||
|
||||
SNAPSHOT_FUZZ_FUNCTION(GetUpdateState, UpdateState, bool has_progress_arg) {
|
||||
SNAPSHOT_FUZZ_FUNCTION(GetUpdateState, bool has_progress_arg) {
|
||||
double progress;
|
||||
return snapshot->GetUpdateState(has_progress_arg ? &progress : nullptr);
|
||||
(void)snapshot->GetUpdateState(has_progress_arg ? &progress : nullptr);
|
||||
}
|
||||
|
||||
SNAPSHOT_FUZZ_FUNCTION(HandleImminentDataWipe, bool, bool has_callback) {
|
||||
SNAPSHOT_FUZZ_FUNCTION(HandleImminentDataWipe, bool has_callback) {
|
||||
std::function<void()> callback;
|
||||
if (has_callback) {
|
||||
callback = []() {};
|
||||
}
|
||||
return snapshot->HandleImminentDataWipe(callback);
|
||||
(void)snapshot->HandleImminentDataWipe(callback);
|
||||
}
|
||||
|
||||
SNAPSHOT_FUZZ_FUNCTION(Dump, bool) {
|
||||
SNAPSHOT_FUZZ_FUNCTION(Dump) {
|
||||
std::stringstream ss;
|
||||
return snapshot->Dump(ss);
|
||||
(void)snapshot->Dump(ss);
|
||||
}
|
||||
|
||||
SNAPSHOT_FUZZ_FUNCTION(CreateUpdateSnapshots, bool, const DeltaArchiveManifest& manifest) {
|
||||
return snapshot->CreateUpdateSnapshots(manifest);
|
||||
SNAPSHOT_FUZZ_FUNCTION(CreateUpdateSnapshots, const DeltaArchiveManifest& manifest) {
|
||||
(void)snapshot->CreateUpdateSnapshots(manifest);
|
||||
}
|
||||
|
||||
SNAPSHOT_FUZZ_FUNCTION(UnmapUpdateSnapshot, bool, const std::string& name) {
|
||||
return snapshot->UnmapUpdateSnapshot(name);
|
||||
SNAPSHOT_FUZZ_FUNCTION(UnmapUpdateSnapshot, const std::string& name) {
|
||||
(void)snapshot->UnmapUpdateSnapshot(name);
|
||||
}
|
||||
|
||||
SNAPSHOT_FUZZ_FUNCTION(CreateLogicalAndSnapshotPartitions, bool,
|
||||
SNAPSHOT_FUZZ_FUNCTION(CreateLogicalAndSnapshotPartitions,
|
||||
const CreateLogicalAndSnapshotPartitionsArgs& args) {
|
||||
const std::string* super;
|
||||
if (args.use_correct_super()) {
|
||||
|
|
@ -133,21 +123,20 @@ SNAPSHOT_FUZZ_FUNCTION(CreateLogicalAndSnapshotPartitions, bool,
|
|||
} else {
|
||||
super = &args.super();
|
||||
}
|
||||
return snapshot->CreateLogicalAndSnapshotPartitions(
|
||||
(void)snapshot->CreateLogicalAndSnapshotPartitions(
|
||||
*super, std::chrono::milliseconds(args.timeout_millis()));
|
||||
}
|
||||
|
||||
SNAPSHOT_FUZZ_FUNCTION(RecoveryCreateSnapshotDevicesWithMetadata, CreateResult,
|
||||
SNAPSHOT_FUZZ_FUNCTION(RecoveryCreateSnapshotDevicesWithMetadata,
|
||||
const RecoveryCreateSnapshotDevicesArgs& args) {
|
||||
std::unique_ptr<AutoDevice> device;
|
||||
if (args.has_metadata_device_object()) {
|
||||
device = std::make_unique<DummyAutoDevice>(args.metadata_mounted());
|
||||
}
|
||||
return snapshot->RecoveryCreateSnapshotDevices(device);
|
||||
(void)snapshot->RecoveryCreateSnapshotDevices(device);
|
||||
}
|
||||
|
||||
SNAPSHOT_FUZZ_FUNCTION(MapUpdateSnapshot, bool,
|
||||
const CreateLogicalPartitionParamsProto& params_proto) {
|
||||
SNAPSHOT_FUZZ_FUNCTION(MapUpdateSnapshot, const CreateLogicalPartitionParamsProto& params_proto) {
|
||||
auto partition_opener = std::make_unique<TestPartitionOpener>(GetSnapshotFuzzEnv()->super());
|
||||
CreateLogicalPartitionParams params;
|
||||
if (params_proto.use_correct_super()) {
|
||||
|
|
@ -164,10 +153,10 @@ SNAPSHOT_FUZZ_FUNCTION(MapUpdateSnapshot, bool,
|
|||
params.device_name = params_proto.device_name();
|
||||
params.partition_opener = partition_opener.get();
|
||||
std::string path;
|
||||
return snapshot->MapUpdateSnapshot(params, &path);
|
||||
(void)snapshot->MapUpdateSnapshot(params, &path);
|
||||
}
|
||||
|
||||
SNAPSHOT_FUZZ_FUNCTION(SwitchSlot, void) {
|
||||
SNAPSHOT_FUZZ_FUNCTION(SwitchSlot) {
|
||||
(void)snapshot;
|
||||
CHECK(current_module != nullptr);
|
||||
CHECK(current_module->device_info != nullptr);
|
||||
|
|
@ -205,8 +194,7 @@ void FatalOnlyLogger(LogId logid, LogSeverity severity, const char* tag, const c
|
|||
}
|
||||
// Stop logging (except fatal messages) after global initialization. This is only done once.
|
||||
int StopLoggingAfterGlobalInit() {
|
||||
(void)GetSnapshotFuzzEnv();
|
||||
[[maybe_unused]] static protobuf_mutator::protobuf::LogSilencer log_silencer;
|
||||
[[maybe_unused]] static protobuf_mutator::protobuf::LogSilencer log_silincer;
|
||||
SetLogger(&FatalOnlyLogger);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -214,10 +202,15 @@ int StopLoggingAfterGlobalInit() {
|
|||
SnapshotFuzzEnv* GetSnapshotFuzzEnv() {
|
||||
[[maybe_unused]] static auto allow_logging = AllowLoggingDuringGlobalInit();
|
||||
static SnapshotFuzzEnv env;
|
||||
[[maybe_unused]] static auto stop_logging = StopLoggingAfterGlobalInit();
|
||||
return &env;
|
||||
}
|
||||
|
||||
SnapshotTestModule SetUpTest(const SnapshotFuzzData& snapshot_fuzz_data) {
|
||||
} // namespace android::snapshot
|
||||
|
||||
DEFINE_PROTO_FUZZER(const SnapshotFuzzData& snapshot_fuzz_data) {
|
||||
using namespace android::snapshot;
|
||||
|
||||
current_data = &snapshot_fuzz_data;
|
||||
|
||||
auto env = GetSnapshotFuzzEnv();
|
||||
|
|
@ -226,127 +219,9 @@ SnapshotTestModule SetUpTest(const SnapshotFuzzData& snapshot_fuzz_data) {
|
|||
auto test_module = env->CheckCreateSnapshotManager(snapshot_fuzz_data);
|
||||
current_module = &test_module;
|
||||
CHECK(test_module.snapshot);
|
||||
return test_module;
|
||||
}
|
||||
|
||||
void TearDownTest() {
|
||||
SnapshotManagerAction::ExecuteAll(test_module.snapshot.get(), snapshot_fuzz_data.actions());
|
||||
|
||||
current_module = nullptr;
|
||||
current_data = nullptr;
|
||||
}
|
||||
|
||||
} // namespace android::snapshot
|
||||
|
||||
DEFINE_PROTO_FUZZER(const SnapshotFuzzData& snapshot_fuzz_data) {
|
||||
using namespace android::snapshot;
|
||||
|
||||
[[maybe_unused]] static auto stop_logging = StopLoggingAfterGlobalInit();
|
||||
auto test_module = SetUpTest(snapshot_fuzz_data);
|
||||
SnapshotManagerAction::ExecuteAll(test_module.snapshot.get(), snapshot_fuzz_data.actions());
|
||||
TearDownTest();
|
||||
}
|
||||
|
||||
namespace android::snapshot {
|
||||
|
||||
// Work-around to cast a 'void' value to Result<void>.
|
||||
template <typename T>
|
||||
struct GoodResult {
|
||||
template <typename F>
|
||||
static Result<T> Cast(F&& f) {
|
||||
return f();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct GoodResult<void> {
|
||||
template <typename F>
|
||||
static Result<void> Cast(F&& f) {
|
||||
f();
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
class LibsnapshotFuzzerTest : public ::testing::Test {
|
||||
protected:
|
||||
static void SetUpTestCase() {
|
||||
// Do initialization once.
|
||||
(void)GetSnapshotFuzzEnv();
|
||||
}
|
||||
void SetUp() override {
|
||||
bool is_virtual_ab = GetBoolProperty("ro.virtual_ab.enabled", false);
|
||||
if (!is_virtual_ab) GTEST_SKIP() << "Test only runs on Virtual A/B devices.";
|
||||
}
|
||||
void SetUpFuzzData(const std::string& fn) {
|
||||
auto path = android::base::GetExecutableDirectory() + "/corpus/"s + fn;
|
||||
std::string proto_text;
|
||||
ASSERT_TRUE(ReadFileToString(path, &proto_text));
|
||||
snapshot_fuzz_data_ = std::make_unique<SnapshotFuzzData>();
|
||||
ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(proto_text,
|
||||
snapshot_fuzz_data_.get()));
|
||||
test_module_ = android::snapshot::SetUpTest(*snapshot_fuzz_data_);
|
||||
}
|
||||
void TearDown() override { android::snapshot::TearDownTest(); }
|
||||
template <typename FuzzFunction>
|
||||
Result<typename FuzzFunction::ReturnType> Execute(int action_index) {
|
||||
if (action_index >= snapshot_fuzz_data_->actions_size()) {
|
||||
return Error() << "Index " << action_index << " is out of bounds ("
|
||||
<< snapshot_fuzz_data_->actions_size() << " actions in corpus";
|
||||
}
|
||||
const auto& action_proto = snapshot_fuzz_data_->actions(action_index);
|
||||
const auto* field_desc =
|
||||
android::fuzz::GetValueFieldDescriptor<typename FuzzFunction::ActionType>(
|
||||
action_proto);
|
||||
if (field_desc == nullptr) {
|
||||
return Error() << "Action at index " << action_index << " has no value defined.";
|
||||
}
|
||||
if (FuzzFunction::tag != field_desc->number()) {
|
||||
return Error() << "Action at index " << action_index << " is expected to be "
|
||||
<< FuzzFunction::name << ", but it is " << field_desc->name()
|
||||
<< " in corpus.";
|
||||
}
|
||||
return GoodResult<typename FuzzFunction::ReturnType>::Cast([&]() {
|
||||
return android::fuzz::ActionPerformer<FuzzFunction>::Invoke(test_module_.snapshot.get(),
|
||||
action_proto, field_desc);
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_ptr<SnapshotFuzzData> snapshot_fuzz_data_;
|
||||
SnapshotTestModule test_module_;
|
||||
};
|
||||
|
||||
#define SNAPSHOT_FUZZ_FN_NAME(name) FUZZ_FUNCTION_CLASS_NAME(SnapshotManagerAction, name)
|
||||
|
||||
MATCHER_P(ResultIs, expected, "") {
|
||||
if (!arg.ok()) {
|
||||
*result_listener << arg.error();
|
||||
return false;
|
||||
}
|
||||
*result_listener << "expected: " << expected;
|
||||
return arg.value() == expected;
|
||||
}
|
||||
|
||||
#define ASSERT_RESULT_TRUE(actual) ASSERT_THAT(actual, ResultIs(true))
|
||||
|
||||
// Check that launch_device.txt is executed correctly.
|
||||
TEST_F(LibsnapshotFuzzerTest, LaunchDevice) {
|
||||
SetUpFuzzData("launch_device.txt");
|
||||
|
||||
int i = 0;
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(BeginUpdate)>(i++));
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(CreateUpdateSnapshots)>(i++));
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "sys_b";
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "vnd_b";
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(MapUpdateSnapshot)>(i++)) << "prd_b";
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(FinishedSnapshotWrites)>(i++));
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "sys_b";
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "vnd_b";
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(UnmapUpdateSnapshot)>(i++)) << "prd_b";
|
||||
ASSERT_RESULT_OK(Execute<SNAPSHOT_FUZZ_FN_NAME(SwitchSlot)>(i++));
|
||||
ASSERT_EQ("_b", test_module_.device_info->GetSlotSuffix());
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(NeedSnapshotsInFirstStageMount)>(i++));
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(CreateLogicalAndSnapshotPartitions)>(i++));
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(InitiateMerge)>(i++));
|
||||
ASSERT_RESULT_TRUE(Execute<SNAPSHOT_FUZZ_FN_NAME(ProcessUpdateState)>(i++));
|
||||
ASSERT_EQ(i, snapshot_fuzz_data_->actions_size()) << "Not all actions are executed.";
|
||||
}
|
||||
|
||||
} // namespace android::snapshot
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue