blob: 0561cc07e84d6782e844db261a3c5c8e26790ffe [file] [log] [blame]
// Copyright 2018 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 <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <fbl/auto_call.h>
#include <fbl/string_printf.h>
#include <unittest/unittest.h>
#include "fuzzer-fixture.h"
#include "test-fuzzer.h"
namespace fuzzing {
namespace testing {
#define ZXDEBUG 0
// Public methods
TestFuzzer::TestFuzzer()
: out_(nullptr), outbuf_(nullptr), outbuflen_(0), err_(nullptr), errbuf_(nullptr),
errbuflen_(0) {}
TestFuzzer::~TestFuzzer() {
Reset();
}
void TestFuzzer::Reset() {
Fuzzer::Reset();
args_.clear();
executable_.clear();
manifest_.clear();
dictionary_.clear();
data_path_.Reset();
if (out_) {
fclose(out_);
#if ZXDEBUG
fprintf(stdout, "%s", outbuf_);
fflush(stdout);
#endif
free(outbuf_);
outbuflen_ = 0;
outbuf_ = nullptr;
out_ = nullptr;
}
if (err_) {
fclose(err_);
#if ZXDEBUG
fprintf(stderr, "%s", errbuf_);
fflush(stderr);
#endif
free(errbuf_);
errbuflen_ = 0;
errbuf_ = nullptr;
err_ = nullptr;
}
}
bool TestFuzzer::InitZircon() {
BEGIN_HELPER;
ASSERT_TRUE(fixture_.CreateZircon());
ASSERT_TRUE(Init());
END_HELPER;
}
bool TestFuzzer::InitFuchsia() {
BEGIN_HELPER;
ASSERT_TRUE(fixture_.CreateFuchsia());
ASSERT_TRUE(Init());
END_HELPER;
}
zx_status_t TestFuzzer::Eval(const char* cmdline) {
BEGIN_HELPER;
ASSERT_TRUE(Init());
char* buf = strdup(cmdline);
ASSERT_NONNULL(buf);
auto cleanup = fbl::MakeAutoCall([&buf]() { free(buf); });
char* ptr = buf;
char* arg;
while ((arg = strsep(&ptr, " "))) {
if (arg && *arg) {
args_.push_back(arg);
}
}
END_HELPER;
}
bool TestFuzzer::InStdOut(const char* needle) {
fflush(out_);
return strcasestr(outbuf_, needle) != nullptr;
}
bool TestFuzzer::InStdErr(const char* needle) {
fflush(err_);
return strcasestr(errbuf_, needle) != nullptr;
}
int TestFuzzer::FindArg(const char* fmt, ...) {
fbl::StringBuffer<PATH_MAX> buffer;
va_list ap;
va_start(ap, fmt);
buffer.AppendVPrintf(fmt, ap);
va_end(ap);
int result = 0;
for (const char* arg = args_.first(); arg; arg = args_.next()) {
if (strcmp(arg, buffer.c_str()) == 0) {
return result;
}
++result;
}
return -1;
}
bool TestFuzzer::CheckProcess(zx_handle_t process, const char* target) {
if (target) {
set_target(target);
}
return Fuzzer::CheckProcess(process);
}
// Protected methods
zx_status_t TestFuzzer::Execute(bool wait_for_completion) {
zx_status_t rc;
GetArgs(&args_);
fbl::String package, target;
const char* s = args_.first();
executable_.Set(s);
if (strcmp(s, "/system/bin/run") != 0) {
// BootFS path
// .../boot/test/fuzz/<target>
package.Set("zircon_fuzzers");
target.Set(s + fixture_.path("boot/test/fuzz/").length());
} else {
// PkgFS path
// fuchsia-pkg://fuchsia.com/<package>#meta/<target>.cmx
s = args_.next();
manifest_.Set(s);
s += strlen("fuchsia-pkg://fuchsia.com/");
const char* t = strchr(s, '#');
package.Set(s, t - s);
s = t + strlen("#meta/");
t = strrchr(s, '.');
target.Set(s, t - s);
dictionary_ = fixture_.path("pkgfs/packages/%s/%s/data/%s/dictionary", package.c_str(),
fixture_.max_version(package.c_str()), target.c_str());
}
data_path_.Reset();
if ((rc = data_path_.Push(fixture_.path("data/fuzzing").c_str())) != ZX_OK ||
(rc = data_path_.Push(package.c_str())) != ZX_OK ||
(rc = data_path_.Push(target.c_str())) != ZX_OK) {
return rc;
}
return ZX_OK;
}
// Private methods
bool TestFuzzer::Init() {
BEGIN_HELPER;
Reset();
out_ = open_memstream(&outbuf_, &outbuflen_);
ASSERT_NONNULL(out_);
err_ = open_memstream(&errbuf_, &errbuflen_);
ASSERT_NONNULL(err_);
// Configure base object
set_root(fixture_.path().c_str());
set_out(out_);
set_err(err_);
END_HELPER;
}
} // namespace testing
} // namespace fuzzing