blob: 8cc138727e71d52adc245f5364106d940ae6eade [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/process-proxy.h"
#include <lib/sync/completion.h>
#include <sstream>
#include <gtest/gtest.h>
#include "src/sys/fuzzing/common/options.h"
#include "src/sys/fuzzing/framework/engine/process-proxy-test.h"
#include "src/sys/fuzzing/framework/target/module.h"
#include "src/sys/fuzzing/framework/testing/module.h"
#include "src/sys/fuzzing/framework/testing/target.h"
namespace fuzzing {
namespace {
// Unit tests.
TEST_F(ProcessProxyTest, AddDefaults) {
Options options;
ProcessProxy::AddDefaults(&options);
EXPECT_EQ(options.malloc_exitcode(), kDefaultMallocExitcode);
EXPECT_EQ(options.death_exitcode(), kDefaultDeathExitcode);
EXPECT_EQ(options.leak_exitcode(), kDefaultLeakExitcode);
EXPECT_EQ(options.oom_exitcode(), kDefaultOomExitcode);
}
TEST_F(ProcessProxyTest, Connect) {
auto process_proxy = MakeProcessProxy();
uint32_t runs = 1000;
int64_t run_limit = 20;
auto options1 = ProcessProxyTest::DefaultOptions();
options1->set_runs(runs);
options1->set_run_limit(run_limit);
process_proxy->Configure(options1);
TestTarget target(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreAll()), ZX_OK);
}
TEST_F(ProcessProxyTest, AddFeedback) {
auto process_proxy = MakeProcessProxy();
FakeModule fake;
fake[0] = 1;
fake[1] = 4;
fake[2] = 8;
// Add before connecting.
Module module1(fake.counters(), fake.pcs(), fake.num_pcs());
auto llvm_module1 = module1.GetLlvmModule();
EXPECT_EQ(process_proxy->AddLlvmModule(std::move(llvm_module1)), ZX_ERR_PEER_CLOSED);
// Add after connecting.
Module module2(fake.counters(), fake.pcs(), fake.num_pcs());
EXPECT_EQ(process_proxy->Connect(IgnoreAll()), ZX_OK);
auto llvm_module2 = module2.GetLlvmModule();
EXPECT_EQ(process_proxy->AddLlvmModule(std::move(llvm_module2)), ZX_OK);
auto* module_impl = pool()->Get(module2.id(), fake.num_pcs());
EXPECT_EQ(module_impl->Measure(), 3U);
}
TEST_F(ProcessProxyTest, Signals) {
auto process_proxy = MakeProcessProxy();
process_proxy->Configure(ProcessProxyTest::DefaultOptions());
AsyncEventPair eventpair(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreTarget(eventpair.Create())), ZX_OK);
FUZZING_EXPECT_OK(eventpair.WaitFor(kSync));
RunUntilIdle();
EXPECT_EQ(eventpair.SignalSelf(kSync, 0), ZX_OK);
FUZZING_EXPECT_OK(process_proxy->Start(/* detect_leaks= */ false));
FUZZING_EXPECT_OK(eventpair.WaitFor(kStart).and_then([&](const zx_signals_t& signals) {
EXPECT_EQ(eventpair.SignalPeer(0, kStart), ZX_OK);
return fpromise::ok();
}));
RunUntilIdle();
EXPECT_EQ(eventpair.SignalSelf(kStart, 0), ZX_OK);
FUZZING_EXPECT_OK(process_proxy->AwaitFinish(), /* leaks_suspected= */ true);
EXPECT_EQ(process_proxy->Finish(), ZX_OK);
FUZZING_EXPECT_OK(eventpair.WaitFor(kFinish).and_then([&](const zx_signals_t& signals) {
EXPECT_EQ(eventpair.SignalPeer(0, kFinishWithLeaks), ZX_OK);
return fpromise::ok();
}));
RunUntilIdle();
EXPECT_EQ(eventpair.SignalSelf(kFinish, 0), ZX_OK);
FUZZING_EXPECT_OK(process_proxy->Start(/* detect_leaks= */ true));
FUZZING_EXPECT_OK(eventpair.WaitFor(kStartLeakCheck).and_then([&](const zx_signals_t& signals) {
EXPECT_EQ(eventpair.SignalPeer(0, kStart), ZX_OK);
return fpromise::ok();
}));
RunUntilIdle();
EXPECT_EQ(eventpair.SignalSelf(kStartLeakCheck, 0), ZX_OK);
FUZZING_EXPECT_OK(process_proxy->AwaitFinish(), /* leaks_suspected= */ false);
EXPECT_EQ(process_proxy->Finish(), ZX_OK);
FUZZING_EXPECT_OK(eventpair.WaitFor(kFinish).and_then([&](const zx_signals_t& signals) {
EXPECT_EQ(eventpair.SignalPeer(0, kFinish), ZX_OK);
return fpromise::ok();
}));
RunUntilIdle();
}
TEST_F(ProcessProxyTest, GetStats) {
auto process_proxy = MakeProcessProxy();
process_proxy->Configure(ProcessProxyTest::DefaultOptions());
TestTarget target(executor());
zx::process spawned = target.Launch();
zx_info_handle_basic_t info;
EXPECT_EQ(spawned.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr), ZX_OK);
EXPECT_EQ(process_proxy->Connect(IgnoreSentSignals(std::move(spawned))), ZX_OK);
ProcessStats stats;
EXPECT_EQ(process_proxy->GetStats(&stats), ZX_OK);
EXPECT_EQ(stats.koid, info.koid);
// The kernel stats are a bit jittery when requested in quick succession. Just check that some
// data was received.
EXPECT_NE(stats.mem_mapped_bytes, 0U);
EXPECT_NE(stats.mem_private_bytes, 0U);
EXPECT_NE(stats.cpu_time, 0U);
}
TEST_F(ProcessProxyTest, DefaultBadMalloc) {
auto process_proxy = MakeProcessProxy();
process_proxy->Configure(ProcessProxyTest::DefaultOptions());
TestTarget target(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreSentSignals(target.Launch())), ZX_OK);
FUZZING_EXPECT_OK(target.Exit(kDefaultMallocExitcode));
FUZZING_EXPECT_OK(process_proxy->GetResult(), FuzzResult::BAD_MALLOC);
RunUntilIdle();
}
TEST_F(ProcessProxyTest, CustomBadMalloc) {
auto process_proxy = MakeProcessProxy();
int32_t exitcode = 1234;
auto options = ProcessProxyTest::DefaultOptions();
options->set_malloc_exitcode(exitcode);
process_proxy->Configure(options);
TestTarget target(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreSentSignals(target.Launch())), ZX_OK);
FUZZING_EXPECT_OK(target.Exit(exitcode));
FUZZING_EXPECT_OK(process_proxy->GetResult(), FuzzResult::BAD_MALLOC);
RunUntilIdle();
}
TEST_F(ProcessProxyTest, DefaultDeath) {
auto process_proxy = MakeProcessProxy();
process_proxy->Configure(ProcessProxyTest::DefaultOptions());
TestTarget target(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreSentSignals(target.Launch())), ZX_OK);
FUZZING_EXPECT_OK(target.Exit(kDefaultDeathExitcode));
FUZZING_EXPECT_OK(process_proxy->GetResult(), FuzzResult::DEATH);
RunUntilIdle();
}
TEST_F(ProcessProxyTest, CustomDeath) {
auto process_proxy = MakeProcessProxy();
int32_t exitcode = 4321;
auto options = ProcessProxyTest::DefaultOptions();
options->set_death_exitcode(exitcode);
process_proxy->Configure(options);
TestTarget target(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreSentSignals(target.Launch())), ZX_OK);
FUZZING_EXPECT_OK(target.Exit(exitcode));
FUZZING_EXPECT_OK(process_proxy->GetResult(), FuzzResult::DEATH);
RunUntilIdle();
}
TEST_F(ProcessProxyTest, Exit) {
auto process_proxy = MakeProcessProxy();
process_proxy->Configure(ProcessProxyTest::DefaultOptions());
TestTarget target(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreSentSignals(target.Launch())), ZX_OK);
FUZZING_EXPECT_OK(target.Exit(1));
FUZZING_EXPECT_OK(process_proxy->GetResult(), FuzzResult::EXIT);
RunUntilIdle();
}
TEST_F(ProcessProxyTest, DefaultLeak) {
auto process_proxy = MakeProcessProxy();
process_proxy->Configure(ProcessProxyTest::DefaultOptions());
TestTarget target(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreSentSignals(target.Launch())), ZX_OK);
FUZZING_EXPECT_OK(target.Exit(kDefaultLeakExitcode));
FUZZING_EXPECT_OK(process_proxy->GetResult(), FuzzResult::LEAK);
RunUntilIdle();
}
TEST_F(ProcessProxyTest, CustomLeak) {
auto process_proxy = MakeProcessProxy();
int32_t exitcode = 5678309;
auto options = ProcessProxyTest::DefaultOptions();
options->set_leak_exitcode(exitcode);
process_proxy->Configure(options);
TestTarget target(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreSentSignals(target.Launch())), ZX_OK);
FUZZING_EXPECT_OK(target.Exit(exitcode));
FUZZING_EXPECT_OK(process_proxy->GetResult(), FuzzResult::LEAK);
RunUntilIdle();
}
TEST_F(ProcessProxyTest, DefaultOom) {
auto process_proxy = MakeProcessProxy();
process_proxy->Configure(ProcessProxyTest::DefaultOptions());
TestTarget target(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreSentSignals(target.Launch())), ZX_OK);
FUZZING_EXPECT_OK(target.Exit(kDefaultOomExitcode));
FUZZING_EXPECT_OK(process_proxy->GetResult(), FuzzResult::OOM);
RunUntilIdle();
}
TEST_F(ProcessProxyTest, CustomOom) {
auto process_proxy = MakeProcessProxy();
int32_t exitcode = 24601;
auto options = ProcessProxyTest::DefaultOptions();
options->set_oom_exitcode(exitcode);
process_proxy->Configure(options);
TestTarget target(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreSentSignals(target.Launch())), ZX_OK);
FUZZING_EXPECT_OK(target.Exit(exitcode));
FUZZING_EXPECT_OK(process_proxy->GetResult(), FuzzResult::OOM);
RunUntilIdle();
}
TEST_F(ProcessProxyTest, Timeout) {
auto process_proxy = MakeProcessProxy();
process_proxy->Configure(ProcessProxyTest::DefaultOptions());
TestTarget target(executor());
EXPECT_EQ(process_proxy->Connect(IgnoreSentSignals(target.Launch())), ZX_OK);
constexpr size_t kBufSize = 1U << 20;
auto buf = std::make_unique<char[]>(kBufSize);
// On timeout, the runner invokes |ProcessProxy::Dump|.
auto len = process_proxy->Dump(buf.get(), kBufSize);
EXPECT_GT(len, 0U);
EXPECT_LT(len, kBufSize);
}
} // namespace
} // namespace fuzzing