blob: 2b4ea0d38ad7b51360f2847990de6c6e43fe15da [file] [log] [blame]
// Copyright 2021 The Fuchsia 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 "src/sys/fuzzing/framework/engine/runner-test.h"
#include <lib/syslog/cpp/macros.h>
#include <gtest/gtest.h>
namespace fuzzing {
void RunnerImplTest::SetUp() {
RunnerTest::SetUp();
dispatcher_ = std::make_shared<Dispatcher>();
}
void RunnerImplTest::Configure(Runner* runner, const std::shared_ptr<Options>& options) {
RunnerTest::Configure(runner, options);
auto* runner_impl = static_cast<RunnerImpl*>(runner);
runner_impl->SetTargetAdapterHandler(target_adapter_.GetHandler());
process_proxy_handler_ = runner_impl->GetProcessProxyHandler(dispatcher_);
}
Input RunnerImplTest::GetTestInput() {
EXPECT_EQ(target_adapter_.AwaitSignal(), kStart);
if (stopped_) {
process_proxy_handler_(process_.NewRequest());
process_.Connect();
process_.AddFeedback();
}
return target_adapter_.test_input();
}
void RunnerImplTest::SetFeedback(const Coverage& coverage, Result result, bool leak) {
// Fake some activity within the process.
process_.SetCoverage(coverage);
process_.SetLeak(leak);
// In most cases, the fake process stops, and unless the error is recoverable the target adapter
// should, too.
stopped_ = true;
bool fatal = true;
switch (result) {
case Result::NO_ERRORS:
// Finish the run normally.
target_adapter_.SignalPeer(kFinish);
stopped_ = false;
break;
case Result::BAD_MALLOC:
process_.Exit(options()->malloc_exitcode());
break;
case Result::CRASH:
process_.Crash();
break;
case Result::DEATH:
process_.Exit(options()->death_exitcode());
break;
case Result::EXIT:
process_.Exit(1);
fatal = options()->detect_exits();
break;
case Result::LEAK:
process_.Exit(options()->leak_exitcode());
break;
case Result::OOM:
process_.Exit(options()->oom_exitcode());
break;
case Result::TIMEOUT:
// Don't signal from the target adapter and don't exit the fake process; just... wait.
// Eventually, the Runner's Timer thread will time out and kill the process.
break;
default:
FX_NOTREACHED();
}
if (stopped_ && fatal) {
EXPECT_EQ(target_adapter_.AwaitSignal(), ZX_EVENTPAIR_PEER_CLOSED);
}
}
void RunnerImplTest::RunAllForFuzzUntilTime() {
RunOne({{1, 2}});
zx::nanosleep(zx::deadline_after(zx::msec(200)));
RunOne();
}
void RunnerImplTest::MergeSeedError(Runner* runner) {
RunnerTest::MergeSeedError(runner);
EXPECT_EQ(GetStatus(), ZX_ERR_INVALID_ARGS);
}
void RunnerImplTest::RunAllForMerge() {
// Seed corpus.
EXPECT_EQ(RunOne().ToHex(), "");
EXPECT_EQ(RunOne().ToHex(), "0a");
// Live corpus, first pass. Should be in same order as added to corpus.
EXPECT_EQ(RunOne().ToHex(), "");
EXPECT_EQ(RunOne().ToHex(), "0b");
EXPECT_EQ(RunOne().ToHex(), "0c0c");
EXPECT_EQ(RunOne().ToHex(), "0d0d0d");
EXPECT_EQ(RunOne().ToHex(), "0e0e");
EXPECT_EQ(RunOne().ToHex(), "0f");
EXPECT_EQ(RunOne().ToHex(), "10101010");
// Live corpus, second pass. Inputs should be ordered by size, smallest to largest, then by most
// unique features to fewest to break ties.
// input2 is skipped, as error-triggering inputs are always included.
// input6 is skipped, as it is redundant with the seed corpus.
EXPECT_EQ(RunOne().ToHex(), "0c0c");
EXPECT_EQ(RunOne().ToHex(), "0e0e");
EXPECT_EQ(RunOne().ToHex(), "0d0d0d");
EXPECT_EQ(RunOne().ToHex(), "10101010");
}
} // namespace fuzzing