mirror of https://github.com/status-im/evmc.git
loader: Add loading error messages
This commit is contained in:
parent
51fe9f48d4
commit
4484a8b74a
|
@ -8,7 +8,9 @@
|
|||
#include <evmc/evmc.h>
|
||||
#include <evmc/helpers.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(EVMC_LOADER_MOCK)
|
||||
|
@ -48,6 +50,27 @@ static void strcpy_s(char* dest, size_t destsz, const char* src)
|
|||
|
||||
static const char* last_error_msg = NULL;
|
||||
|
||||
#define LAST_ERROR_MSG_BUFFER_SIZE 511
|
||||
|
||||
// Buffer for formatted error messages.
|
||||
// It has one null byte extra to avoid buffer read overflow during concurrent access.
|
||||
static char last_error_msg_buffer[LAST_ERROR_MSG_BUFFER_SIZE + 1];
|
||||
|
||||
// TODO: Change that into a macro - will be simpler and we will get compilers warnings for snprintf
|
||||
// misuse.
|
||||
static enum evmc_loader_error_code set_error(enum evmc_loader_error_code error_code,
|
||||
const char* format,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
if (vsnprintf(last_error_msg_buffer, LAST_ERROR_MSG_BUFFER_SIZE, format, args) <
|
||||
LAST_ERROR_MSG_BUFFER_SIZE)
|
||||
last_error_msg = last_error_msg_buffer;
|
||||
va_end(args);
|
||||
return error_code;
|
||||
}
|
||||
|
||||
|
||||
evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* error_code)
|
||||
{
|
||||
|
@ -57,14 +80,21 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
|
|||
|
||||
if (!filename)
|
||||
{
|
||||
ec = EVMC_LOADER_INVALID_ARGUMENT;
|
||||
ec = set_error(EVMC_LOADER_INVALID_ARGUMENT, "invalid argument: file name cannot be null");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
const size_t length = strlen(filename);
|
||||
if (length == 0 || length > PATH_MAX_LENGTH)
|
||||
if (length == 0)
|
||||
{
|
||||
ec = EVMC_LOADER_INVALID_ARGUMENT;
|
||||
ec = set_error(EVMC_LOADER_INVALID_ARGUMENT, "invalid argument: file name cannot be empty");
|
||||
goto exit;
|
||||
}
|
||||
else if (length > PATH_MAX_LENGTH)
|
||||
{
|
||||
ec = set_error(EVMC_LOADER_INVALID_ARGUMENT,
|
||||
"invalid argument: file name is too long (%d, maximum allowed length is %d)",
|
||||
(int)length, PATH_MAX_LENGTH);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
@ -73,7 +103,10 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
|
|||
{
|
||||
// Get error message if available.
|
||||
last_error_msg = DLL_GET_ERROR_MSG();
|
||||
ec = EVMC_LOADER_CANNOT_OPEN;
|
||||
if (last_error_msg)
|
||||
ec = EVMC_LOADER_CANNOT_OPEN;
|
||||
else
|
||||
ec = set_error(EVMC_LOADER_CANNOT_OPEN, "cannot open %s", filename);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
@ -128,7 +161,8 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
|
|||
if (!create_fn)
|
||||
{
|
||||
DLL_CLOSE(handle);
|
||||
ec = EVMC_LOADER_SYMBOL_NOT_FOUND;
|
||||
ec = set_error(EVMC_LOADER_SYMBOL_NOT_FOUND, "EVMC create function not found in %s",
|
||||
filename);
|
||||
}
|
||||
|
||||
exit:
|
||||
|
@ -156,13 +190,16 @@ struct evmc_instance* evmc_load_and_create(const char* filename,
|
|||
struct evmc_instance* instance = create_fn();
|
||||
if (!instance)
|
||||
{
|
||||
*error_code = EVMC_LOADER_INSTANCE_CREATION_FAILURE;
|
||||
*error_code = set_error(EVMC_LOADER_INSTANCE_CREATION_FAILURE,
|
||||
"creating EVMC instance of %s has failed", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!evmc_is_abi_compatible(instance))
|
||||
{
|
||||
*error_code = EVMC_LOADER_ABI_VERSION_MISMATCH;
|
||||
*error_code = set_error(EVMC_LOADER_ABI_VERSION_MISMATCH,
|
||||
"EVMC ABI version %d of %s mismatches the expected version %d",
|
||||
instance->abi_version, filename, EVMC_ABI_VERSION);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,8 +66,14 @@ TEST_F(loader, load_long_path)
|
|||
const std::string path(5000, 'a');
|
||||
evmc_loader_error_code ec;
|
||||
EXPECT_EQ(evmc_load(path.c_str(), &ec), nullptr);
|
||||
EXPECT_STREQ(evmc_last_error_msg(),
|
||||
"invalid argument: file name is too long (5000, maximum allowed length is 4096)");
|
||||
EXPECT_EQ(evmc_last_error_msg(), nullptr);
|
||||
EXPECT_EQ(ec, EVMC_LOADER_INVALID_ARGUMENT);
|
||||
EXPECT_EQ(evmc_load(path.c_str(), nullptr), nullptr);
|
||||
EXPECT_STREQ(evmc_last_error_msg(),
|
||||
"invalid argument: file name is too long (5000, maximum allowed length is 4096)");
|
||||
EXPECT_EQ(evmc_last_error_msg(), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(loader, load_null_path)
|
||||
|
@ -75,15 +81,23 @@ TEST_F(loader, load_null_path)
|
|||
evmc_loader_error_code ec;
|
||||
EXPECT_EQ(evmc_load(nullptr, &ec), nullptr);
|
||||
EXPECT_EQ(ec, EVMC_LOADER_INVALID_ARGUMENT);
|
||||
EXPECT_STREQ(evmc_last_error_msg(), "invalid argument: file name cannot be null");
|
||||
EXPECT_EQ(evmc_last_error_msg(), nullptr);
|
||||
EXPECT_EQ(evmc_load(nullptr, nullptr), nullptr);
|
||||
EXPECT_STREQ(evmc_last_error_msg(), "invalid argument: file name cannot be null");
|
||||
EXPECT_EQ(evmc_last_error_msg(), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(loader, load_empty_path)
|
||||
{
|
||||
evmc_loader_error_code ec;
|
||||
EXPECT_EQ(evmc_load("", &ec), nullptr);
|
||||
EXPECT_STREQ(evmc_last_error_msg(), "invalid argument: file name cannot be empty");
|
||||
EXPECT_EQ(evmc_last_error_msg(), nullptr);
|
||||
EXPECT_EQ(ec, EVMC_LOADER_INVALID_ARGUMENT);
|
||||
EXPECT_EQ(evmc_load("", nullptr), nullptr);
|
||||
EXPECT_STREQ(evmc_last_error_msg(), "invalid argument: file name cannot be empty");
|
||||
EXPECT_EQ(evmc_last_error_msg(), nullptr);
|
||||
}
|
||||
|
||||
TEST_F(loader, load_prefix_aaa)
|
||||
|
@ -104,6 +118,7 @@ TEST_F(loader, load_prefix_aaa)
|
|||
EXPECT_EQ(ec, EVMC_LOADER_SUCCESS);
|
||||
ASSERT_NE(fn, nullptr);
|
||||
EXPECT_EQ((uintptr_t)fn(), 0xaaa);
|
||||
EXPECT_EQ(evmc_last_error_msg(), nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,6 +130,7 @@ TEST_F(loader, load_eee_bbb)
|
|||
ASSERT_NE(fn, nullptr);
|
||||
EXPECT_EQ(ec, EVMC_LOADER_SUCCESS);
|
||||
EXPECT_EQ((uintptr_t)fn(), 0xeeebbb);
|
||||
EXPECT_EQ(evmc_last_error_msg(), nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -162,6 +178,8 @@ TEST_F(loader, load_symbol_not_found)
|
|||
evmc_loader_error_code ec;
|
||||
EXPECT_EQ(evmc_load(evmc_test_library_path, &ec), nullptr);
|
||||
EXPECT_EQ(ec, EVMC_LOADER_SYMBOL_NOT_FOUND);
|
||||
EXPECT_EQ(evmc_last_error_msg(), "EVMC create function not found in " + std::string(path));
|
||||
EXPECT_EQ(evmc_last_error_msg(), nullptr);
|
||||
EXPECT_EQ(evmc_load(evmc_test_library_path, nullptr), nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -187,6 +205,7 @@ TEST_F(loader, load_and_create_failure)
|
|||
auto vm = evmc_load_and_create(evmc_test_library_path, &ec);
|
||||
EXPECT_EQ(vm, nullptr);
|
||||
EXPECT_EQ(ec, EVMC_LOADER_INSTANCE_CREATION_FAILURE);
|
||||
EXPECT_STREQ(evmc_last_error_msg(), "creating EVMC instance of failure.vm has failed");
|
||||
}
|
||||
|
||||
TEST_F(loader, load_and_create_abi_mismatch)
|
||||
|
@ -197,4 +216,6 @@ TEST_F(loader, load_and_create_abi_mismatch)
|
|||
auto vm = evmc_load_and_create(evmc_test_library_path, &ec);
|
||||
EXPECT_EQ(vm, nullptr);
|
||||
EXPECT_EQ(ec, EVMC_LOADER_ABI_VERSION_MISMATCH);
|
||||
EXPECT_STREQ(evmc_last_error_msg(),
|
||||
"EVMC ABI version 42 of abi42.vm mismatches the expected version 6");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue