Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

loader: Make error_code in evmc_load_and_create() optional #311

Merged
merged 3 commits into from
Jun 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

- Changed: [[#293](https://github.com/ethereum/evmc/pull/293)]
In C++ API `evmc::result::raw()` renamed to `evmc::result::release_raw()`.
- Changed: [[#311](https://github.com/ethereum/evmc/pull/311)]
In `evmc_load_and_create()` the `error_code` is optional (can be `NULL`).
- Fixed:
[[#261](https://github.com/ethereum/evmc/issues/261),
[#263](https://github.com/ethereum/evmc/pull/263)]
Expand Down
32 changes: 20 additions & 12 deletions include/evmc/loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ enum evmc_loader_error_code
};

/**
* Dynamically loads the shared object (DLL) with an EVM implementation.
* Dynamically loads the EVMC module with a VM implementation.
*
* This function tries to open a DLL at the given `filename`. On UNIX-like systems dlopen() function
* is used. On Windows LoadLibrary() function is used.
* This function tries to open a dynamically loaded library (DLL) at the given `filename`.
* On UNIX-like systems dlopen() function is used. On Windows LoadLibrary() function is used.
*
* If the file does not exist or is not a valid shared library the ::EVMC_LOADER_CANNOT_OPEN error
* code is signaled and NULL is returned.
Expand Down Expand Up @@ -77,28 +77,36 @@ enum evmc_loader_error_code
* It is safe to call this function with the same filename argument multiple times
* (the DLL is not going to be loaded multiple times).
*
* @param filename The null terminated path (absolute or relative) to the shared library
* containing the EVM implementation. If the value is NULL, an empty C-string
* or longer than the path maximum length the ::EVMC_LOADER_INVALID_ARGUMENT is
* signaled.
* @param filename The null terminated path (absolute or relative) to an EVMC module
* (dynamically loaded library) containing the VM implementation.
* If the value is NULL, an empty C-string or longer than the path maximum length
* the ::EVMC_LOADER_INVALID_ARGUMENT is signaled.
* @param error_code The pointer to the error code. If not NULL the value is set to
* ::EVMC_LOADER_SUCCESS on success or any other error code as described above.
* @return The pointer to the EVM create function or NULL.
* @return The pointer to the EVM create function or NULL in case of error.
*/
evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* error_code);

/**
* Dynamically loads the VM DLL and creates the VM instance.
* Dynamically loads the EVMC module and creates the VM instance.
*
* This is a macro for creating the VM instance with the function returned from evmc_load().
* The function signals the same errors as evmc_load() and additionally:
* - ::EVMC_LOADER_INSTANCE_CREATION_FAILURE when the create function returns NULL,
* - ::EVMC_LOADER_ABI_VERSION_MISMATCH when the created VM instance has ABI version different
* from the ABI version of this library (::EVMC_ABI_VERSION).
* - ::EVMC_LOADER_INSTANCE_CREATION_FAILURE when the create function returns NULL,
* - ::EVMC_LOADER_ABI_VERSION_MISMATCH when the created VM instance has ABI version different
* from the ABI version of this library (::EVMC_ABI_VERSION).
*
* It is safe to call this function with the same filename argument multiple times:
* the DLL is not going to be loaded multiple times, but the function will return new VM instance
* each time.
*
* @param filename The null terminated path (absolute or relative) to an EVMC module
* (dynamically loaded library) containing the VM implementation.
* If the value is NULL, an empty C-string or longer than the path maximum length
* the ::EVMC_LOADER_INVALID_ARGUMENT is signaled.
* @param error_code The pointer to the error code. If not NULL the value is set to
* ::EVMC_LOADER_SUCCESS on success or any other error code as described above.
* @return The pointer to the created VM or NULL in case of error.
*/
struct evmc_instance* evmc_load_and_create(const char* filename,
enum evmc_loader_error_code* error_code);
Expand Down
21 changes: 14 additions & 7 deletions lib/loader/loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,22 +212,29 @@ struct evmc_instance* evmc_load_and_create(const char* filename,
if (!create_fn)
return NULL;

enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS;

struct evmc_instance* instance = create_fn();
if (!instance)
{
*error_code = set_error(EVMC_LOADER_INSTANCE_CREATION_FAILURE,
"creating EVMC instance of %s has failed", filename);
return NULL;
ec = set_error(EVMC_LOADER_INSTANCE_CREATION_FAILURE,
"creating EVMC instance of %s has failed", filename);
goto exit;
}

if (!evmc_is_abi_compatible(instance))
{
ec = 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);
evmc_destroy(instance);
*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;
instance = NULL;
goto exit;
}

exit:
if (error_code)
*error_code = ec;

return instance;
}
11 changes: 11 additions & 0 deletions test/unittests/test_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,11 @@ TEST_F(loader, load_and_create_failure)
EXPECT_TRUE(vm == nullptr);
EXPECT_EQ(ec, EVMC_LOADER_INSTANCE_CREATION_FAILURE);
EXPECT_STREQ(evmc_last_error_msg(), "creating EVMC instance of failure.vm has failed");
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
axic marked this conversation as resolved.
Show resolved Hide resolved

vm = evmc_load_and_create(evmc_test_library_path, nullptr);
EXPECT_TRUE(vm == nullptr);
EXPECT_STREQ(evmc_last_error_msg(), "creating EVMC instance of failure.vm has failed");
}

TEST_F(loader, load_and_create_abi_mismatch)
Expand All @@ -315,5 +320,11 @@ TEST_F(loader, load_and_create_abi_mismatch)
"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);
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
EXPECT_EQ(destroy_count, create_count);

vm = evmc_load_and_create(evmc_test_library_path, nullptr);
EXPECT_TRUE(vm == nullptr);
EXPECT_EQ(evmc_last_error_msg(), expected_error_msg);
EXPECT_EQ(destroy_count, create_count);
}