| // 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 |