2018-07-04 23:10:33 +00:00
|
|
|
// EVMC: Ethereum Client-VM Connector API.
|
2019-04-24 14:12:13 +00:00
|
|
|
// Copyright 2018-2019 The EVMC Authors.
|
2019-03-13 12:33:07 +00:00
|
|
|
// Licensed under the Apache License, Version 2.0.
|
2018-07-04 23:10:33 +00:00
|
|
|
|
2019-05-30 12:10:00 +00:00
|
|
|
#include <evmc/evmc.h>
|
2018-07-04 23:10:33 +00:00
|
|
|
#include <evmc/loader.h>
|
|
|
|
#include <gtest/gtest.h>
|
2018-07-10 09:08:33 +00:00
|
|
|
#include <cstring>
|
2019-05-30 12:10:00 +00:00
|
|
|
#include <unordered_map>
|
|
|
|
#include <vector>
|
2018-07-10 09:08:33 +00:00
|
|
|
|
|
|
|
#if _WIN32
|
|
|
|
static constexpr bool is_windows = true;
|
|
|
|
#else
|
|
|
|
static constexpr bool is_windows = false;
|
|
|
|
#endif
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
extern "C" {
|
2019-05-30 12:10:00 +00:00
|
|
|
/// The library path expected by mocked evmc_test_load_library().
|
2019-03-13 18:31:50 +00:00
|
|
|
extern const char* evmc_test_library_path;
|
2019-05-30 12:10:00 +00:00
|
|
|
|
|
|
|
/// The symbol name expected by mocked evmc_test_get_symbol_address().
|
2019-03-13 18:31:50 +00:00
|
|
|
extern const char* evmc_test_library_symbol;
|
2019-05-30 12:10:00 +00:00
|
|
|
|
|
|
|
/// The pointer to function returned by evmc_test_get_symbol_address().
|
2019-03-13 18:31:50 +00:00
|
|
|
extern evmc_create_fn evmc_test_create_fn;
|
|
|
|
}
|
|
|
|
|
|
|
|
class loader : public ::testing::Test
|
2018-07-04 23:10:33 +00:00
|
|
|
{
|
2019-03-13 18:31:50 +00:00
|
|
|
protected:
|
2019-05-30 12:10:00 +00:00
|
|
|
static int create_count;
|
|
|
|
static int destroy_count;
|
|
|
|
static std::unordered_map<std::string, const char*> supported_options;
|
|
|
|
static std::vector<std::pair<std::string, std::string>> recorded_options;
|
|
|
|
|
|
|
|
loader() noexcept
|
|
|
|
{
|
|
|
|
create_count = 0;
|
|
|
|
destroy_count = 0;
|
|
|
|
supported_options.clear();
|
|
|
|
recorded_options.clear();
|
|
|
|
}
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
void setup(const char* path, const char* symbol, evmc_create_fn fn) noexcept
|
|
|
|
{
|
|
|
|
evmc_test_library_path = path;
|
|
|
|
evmc_test_library_symbol = symbol;
|
|
|
|
evmc_test_create_fn = fn;
|
|
|
|
}
|
2019-05-30 12:10:00 +00:00
|
|
|
|
|
|
|
static void destroy(evmc_instance*) noexcept { ++destroy_count; }
|
|
|
|
|
|
|
|
static evmc_set_option_result set_option(evmc_instance*,
|
|
|
|
const char* name,
|
|
|
|
const char* value) noexcept
|
|
|
|
{
|
|
|
|
recorded_options.push_back({name, value ? value : "<null>"}); // NOLINT
|
|
|
|
|
|
|
|
auto it = supported_options.find(name);
|
|
|
|
if (it == supported_options.end())
|
|
|
|
return EVMC_SET_OPTION_INVALID_NAME;
|
|
|
|
if (it->second == nullptr)
|
|
|
|
return value == nullptr ? EVMC_SET_OPTION_SUCCESS : EVMC_SET_OPTION_INVALID_VALUE;
|
|
|
|
if (value == nullptr)
|
|
|
|
return EVMC_SET_OPTION_INVALID_VALUE;
|
|
|
|
return std::string{value} == it->second ? EVMC_SET_OPTION_SUCCESS :
|
|
|
|
EVMC_SET_OPTION_INVALID_VALUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates a VM mock with only destroy() method.
|
|
|
|
static evmc_instance* create_vm_barebone()
|
|
|
|
{
|
|
|
|
static auto instance =
|
|
|
|
evmc_instance{EVMC_ABI_VERSION, "", "", destroy, nullptr, nullptr, nullptr, nullptr};
|
|
|
|
++create_count;
|
|
|
|
return &instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates a VM mock with ABI version different than in this project.
|
|
|
|
static evmc_instance* create_vm_with_wrong_abi()
|
|
|
|
{
|
|
|
|
constexpr auto wrong_abi_version = 1985;
|
|
|
|
static_assert(wrong_abi_version != EVMC_ABI_VERSION, "");
|
|
|
|
static auto instance =
|
|
|
|
evmc_instance{wrong_abi_version, "", "", destroy, nullptr, nullptr, nullptr, nullptr};
|
|
|
|
++create_count;
|
|
|
|
return &instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates a VM mock with optional set_option() method.
|
|
|
|
static evmc_instance* create_vm_with_set_option() noexcept
|
|
|
|
{
|
|
|
|
static auto instance =
|
|
|
|
evmc_instance{EVMC_ABI_VERSION, "", "", destroy, nullptr, nullptr, nullptr, set_option};
|
|
|
|
++create_count;
|
|
|
|
return &instance;
|
|
|
|
}
|
2019-03-13 18:31:50 +00:00
|
|
|
};
|
2018-07-04 23:10:33 +00:00
|
|
|
|
2019-05-30 12:10:00 +00:00
|
|
|
int loader::create_count = 0;
|
|
|
|
int loader::destroy_count = 0;
|
|
|
|
std::unordered_map<std::string, const char*> loader::supported_options;
|
|
|
|
std::vector<std::pair<std::string, std::string>> loader::recorded_options;
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
static evmc_instance* create_aaa()
|
|
|
|
{
|
|
|
|
return (evmc_instance*)0xaaa;
|
2018-07-04 23:10:33 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
static evmc_instance* create_eee_bbb()
|
2018-07-04 23:10:33 +00:00
|
|
|
{
|
2019-03-13 18:31:50 +00:00
|
|
|
return (evmc_instance*)0xeeebbb;
|
|
|
|
}
|
2018-07-04 23:10:33 +00:00
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
static evmc_instance* create_failure()
|
|
|
|
{
|
|
|
|
return nullptr;
|
2018-07-04 23:10:33 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
TEST_F(loader, load_nonexistent)
|
|
|
|
{
|
|
|
|
constexpr auto path = "nonexistent";
|
2018-07-04 23:10:33 +00:00
|
|
|
evmc_loader_error_code ec;
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_load(path, &ec) == nullptr);
|
2018-07-04 23:10:33 +00:00
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_CANNOT_OPEN);
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_load(path, nullptr) == nullptr);
|
2018-07-04 23:10:33 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
TEST_F(loader, load_long_path)
|
2018-07-04 23:10:33 +00:00
|
|
|
{
|
2019-03-13 18:31:50 +00:00
|
|
|
const std::string path(5000, 'a');
|
2018-07-04 23:10:33 +00:00
|
|
|
evmc_loader_error_code ec;
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_load(path.c_str(), &ec) == nullptr);
|
2019-04-16 18:12:15 +00:00
|
|
|
EXPECT_STREQ(evmc_last_error_msg(),
|
|
|
|
"invalid argument: file name is too long (5000, maximum allowed length is 4096)");
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
|
2018-07-04 23:10:33 +00:00
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_INVALID_ARGUMENT);
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_load(path.c_str(), nullptr) == nullptr);
|
2019-04-16 18:12:15 +00:00
|
|
|
EXPECT_STREQ(evmc_last_error_msg(),
|
|
|
|
"invalid argument: file name is too long (5000, maximum allowed length is 4096)");
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
|
2018-07-04 23:10:33 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
TEST_F(loader, load_null_path)
|
2018-07-04 23:10:33 +00:00
|
|
|
{
|
|
|
|
evmc_loader_error_code ec;
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_load(nullptr, &ec) == nullptr);
|
2018-07-04 23:10:33 +00:00
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_INVALID_ARGUMENT);
|
2019-04-16 18:12:15 +00:00
|
|
|
EXPECT_STREQ(evmc_last_error_msg(), "invalid argument: file name cannot be null");
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
|
|
|
|
EXPECT_TRUE(evmc_load(nullptr, nullptr) == nullptr);
|
2019-04-16 18:12:15 +00:00
|
|
|
EXPECT_STREQ(evmc_last_error_msg(), "invalid argument: file name cannot be null");
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
|
2018-07-04 23:10:33 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
TEST_F(loader, load_empty_path)
|
2018-07-04 23:10:33 +00:00
|
|
|
{
|
|
|
|
evmc_loader_error_code ec;
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_load("", &ec) == nullptr);
|
2019-04-16 18:12:15 +00:00
|
|
|
EXPECT_STREQ(evmc_last_error_msg(), "invalid argument: file name cannot be empty");
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
|
2019-03-13 18:31:50 +00:00
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_INVALID_ARGUMENT);
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_load("", nullptr) == nullptr);
|
2019-04-16 18:12:15 +00:00
|
|
|
EXPECT_STREQ(evmc_last_error_msg(), "invalid argument: file name cannot be empty");
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
|
2018-07-04 23:10:33 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
TEST_F(loader, load_prefix_aaa)
|
2018-07-04 23:10:33 +00:00
|
|
|
{
|
2019-03-13 18:31:50 +00:00
|
|
|
auto paths = {
|
|
|
|
"./aaa.evm",
|
|
|
|
"aaa.evm",
|
|
|
|
"unittests/libaaa.so",
|
|
|
|
"unittests/double-prefix-aaa.evm",
|
|
|
|
"unittests/double_prefix_aaa.evm",
|
|
|
|
};
|
2018-07-04 23:10:33 +00:00
|
|
|
|
|
|
|
for (auto& path : paths)
|
|
|
|
{
|
2019-03-13 18:31:50 +00:00
|
|
|
setup(path, "evmc_create_aaa", create_aaa);
|
2018-07-04 23:10:33 +00:00
|
|
|
evmc_loader_error_code ec;
|
2018-07-05 12:51:03 +00:00
|
|
|
auto fn = evmc_load(path, &ec);
|
2018-07-04 23:10:33 +00:00
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_SUCCESS);
|
2019-05-05 21:33:41 +00:00
|
|
|
ASSERT_TRUE(fn != nullptr);
|
2018-07-05 12:51:03 +00:00
|
|
|
EXPECT_EQ((uintptr_t)fn(), 0xaaa);
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
|
2018-07-04 23:10:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
TEST_F(loader, load_eee_bbb)
|
2018-07-04 23:10:33 +00:00
|
|
|
{
|
2019-03-13 18:31:50 +00:00
|
|
|
setup("unittests/eee-bbb.dll", "evmc_create_eee_bbb", create_eee_bbb);
|
2018-07-04 23:10:33 +00:00
|
|
|
evmc_loader_error_code ec;
|
2019-03-13 18:31:50 +00:00
|
|
|
auto fn = evmc_load(evmc_test_library_path, &ec);
|
2019-05-05 21:33:41 +00:00
|
|
|
ASSERT_TRUE(fn != nullptr);
|
2018-07-04 23:10:33 +00:00
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_SUCCESS);
|
2018-07-05 12:51:03 +00:00
|
|
|
EXPECT_EQ((uintptr_t)fn(), 0xeeebbb);
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
|
2018-07-04 23:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
TEST_F(loader, load_windows_path)
|
2018-07-10 09:08:33 +00:00
|
|
|
{
|
|
|
|
auto paths = {
|
2019-03-13 18:31:50 +00:00
|
|
|
"./eee-bbb.evm",
|
|
|
|
".\\eee-bbb.evm",
|
2018-07-10 09:08:33 +00:00
|
|
|
"./unittests/eee-bbb.dll",
|
|
|
|
"./unittests\\eee-bbb.dll",
|
|
|
|
".\\unittests\\eee-bbb.dll",
|
|
|
|
".\\unittests/eee-bbb.dll",
|
|
|
|
"unittests\\eee-bbb.dll",
|
|
|
|
};
|
|
|
|
|
|
|
|
for (auto& path : paths)
|
|
|
|
{
|
2019-03-13 18:31:50 +00:00
|
|
|
bool should_open = is_windows || std::strchr(path, '\\') == nullptr;
|
|
|
|
setup(should_open ? path : nullptr, "evmc_create_eee_bbb", create_eee_bbb);
|
2018-07-10 09:08:33 +00:00
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
evmc_loader_error_code ec;
|
|
|
|
evmc_load(path, &ec);
|
2019-04-17 15:02:10 +00:00
|
|
|
if (should_open)
|
|
|
|
{
|
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_SUCCESS);
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
|
2019-04-17 15:02:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_CANNOT_OPEN);
|
|
|
|
EXPECT_STREQ(evmc_last_error_msg(), "cannot load library");
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
|
2019-04-17 15:02:10 +00:00
|
|
|
}
|
2018-07-10 09:08:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
TEST_F(loader, load_symbol_not_found)
|
2018-07-04 23:10:33 +00:00
|
|
|
{
|
2019-03-13 18:31:50 +00:00
|
|
|
auto paths = {"libaaa1.so", "eee2.so", "libeee3.x", "eee4", "_", "lib_.so"};
|
2018-07-04 23:10:33 +00:00
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
for (auto& path : paths)
|
|
|
|
{
|
|
|
|
setup(path, "evmc_create_aaa", create_aaa);
|
2018-07-10 09:08:33 +00:00
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
evmc_loader_error_code ec;
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_load(evmc_test_library_path, &ec) == nullptr);
|
2019-03-13 18:31:50 +00:00
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_SYMBOL_NOT_FOUND);
|
2019-04-16 18:12:15 +00:00
|
|
|
EXPECT_EQ(evmc_last_error_msg(), "EVMC create function not found in " + std::string(path));
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
|
|
|
|
EXPECT_TRUE(evmc_load(evmc_test_library_path, nullptr) == nullptr);
|
2019-03-13 18:31:50 +00:00
|
|
|
}
|
2018-07-10 09:08:33 +00:00
|
|
|
}
|
2018-07-13 13:31:49 +00:00
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
TEST_F(loader, load_default_symbol)
|
2018-08-27 19:18:10 +00:00
|
|
|
{
|
2019-03-13 18:31:50 +00:00
|
|
|
setup("default.evmc", "evmc_create", create_aaa);
|
2018-08-27 19:18:10 +00:00
|
|
|
|
|
|
|
evmc_loader_error_code ec;
|
2019-03-13 18:31:50 +00:00
|
|
|
auto fn = evmc_load(evmc_test_library_path, &ec);
|
2018-08-27 19:18:10 +00:00
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_SUCCESS);
|
2019-03-13 18:31:50 +00:00
|
|
|
EXPECT_EQ(fn, &create_aaa);
|
2018-08-27 19:18:10 +00:00
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
fn = evmc_load(evmc_test_library_path, nullptr);
|
|
|
|
EXPECT_EQ(fn, &create_aaa);
|
2018-08-27 19:18:10 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
TEST_F(loader, load_and_create_failure)
|
2018-07-13 13:31:49 +00:00
|
|
|
{
|
2019-03-13 18:31:50 +00:00
|
|
|
setup("failure.vm", "evmc_create", create_failure);
|
|
|
|
|
2018-07-13 13:31:49 +00:00
|
|
|
evmc_loader_error_code ec;
|
2019-03-13 18:31:50 +00:00
|
|
|
auto vm = evmc_load_and_create(evmc_test_library_path, &ec);
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(vm == nullptr);
|
2018-07-13 13:31:49 +00:00
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_INSTANCE_CREATION_FAILURE);
|
2019-04-16 18:12:15 +00:00
|
|
|
EXPECT_STREQ(evmc_last_error_msg(), "creating EVMC instance of failure.vm has failed");
|
2018-07-13 13:31:49 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 18:31:50 +00:00
|
|
|
TEST_F(loader, load_and_create_abi_mismatch)
|
2018-07-13 13:31:49 +00:00
|
|
|
{
|
2019-05-30 12:15:20 +00:00
|
|
|
setup("abi1985.vm", "evmc_create", create_vm_with_wrong_abi);
|
2019-03-13 18:31:50 +00:00
|
|
|
|
2018-07-13 13:31:49 +00:00
|
|
|
evmc_loader_error_code ec;
|
2019-03-13 18:31:50 +00:00
|
|
|
auto vm = evmc_load_and_create(evmc_test_library_path, &ec);
|
2019-05-05 21:33:41 +00:00
|
|
|
EXPECT_TRUE(vm == nullptr);
|
2018-07-13 13:31:49 +00:00
|
|
|
EXPECT_EQ(ec, EVMC_LOADER_ABI_VERSION_MISMATCH);
|
2019-05-30 12:15:20 +00:00
|
|
|
const auto expected_error_msg =
|
|
|
|
"EVMC ABI version 1985 of abi1985.vm mismatches the expected version " +
|
|
|
|
std::to_string(EVMC_ABI_VERSION);
|
|
|
|
EXPECT_EQ(evmc_last_error_msg(), expected_error_msg);
|
2018-07-13 13:31:49 +00:00
|
|
|
}
|