Merge pull request #311 from ethereum/loader_error_code

loader: Make error_code in evmc_load_and_create() optional
This commit is contained in:
Paweł Bylica 2019-06-05 16:17:17 +02:00 committed by GitHub
commit 1b6158349b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 47 additions and 19 deletions

View File

@ -4,6 +4,8 @@
- Changed: [[#293](https://github.com/ethereum/evmc/pull/293)] - Changed: [[#293](https://github.com/ethereum/evmc/pull/293)]
In C++ API `evmc::result::raw()` renamed to `evmc::result::release_raw()`. 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: - Fixed:
[[#261](https://github.com/ethereum/evmc/issues/261), [[#261](https://github.com/ethereum/evmc/issues/261),
[#263](https://github.com/ethereum/evmc/pull/263)] [#263](https://github.com/ethereum/evmc/pull/263)]

View File

@ -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 * This function tries to open a dynamically loaded library (DLL) at the given `filename`.
* is used. On Windows LoadLibrary() function is used. * 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 * 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. * code is signaled and NULL is returned.
@ -77,28 +77,36 @@ enum evmc_loader_error_code
* It is safe to call this function with the same filename argument multiple times * It is safe to call this function with the same filename argument multiple times
* (the DLL is not going to be loaded 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 * @param filename The null terminated path (absolute or relative) to an EVMC module
* containing the EVM implementation. If the value is NULL, an empty C-string * (dynamically loaded library) containing the VM implementation.
* or longer than the path maximum length the ::EVMC_LOADER_INVALID_ARGUMENT is * If the value is NULL, an empty C-string or longer than the path maximum length
* signaled. * the ::EVMC_LOADER_INVALID_ARGUMENT is signaled.
* @param error_code The pointer to the error code. If not NULL the value is set to * @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. * ::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); 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(). * 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: * The function signals the same errors as evmc_load() and additionally:
* - ::EVMC_LOADER_INSTANCE_CREATION_FAILURE when the create function returns NULL, * - ::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 * - ::EVMC_LOADER_ABI_VERSION_MISMATCH when the created VM instance has ABI version different
* from the ABI version of this library (::EVMC_ABI_VERSION). * from the ABI version of this library (::EVMC_ABI_VERSION).
* *
* It is safe to call this function with the same filename argument multiple times: * 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 * the DLL is not going to be loaded multiple times, but the function will return new VM instance
* each time. * 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, struct evmc_instance* evmc_load_and_create(const char* filename,
enum evmc_loader_error_code* error_code); enum evmc_loader_error_code* error_code);

View File

@ -212,22 +212,29 @@ struct evmc_instance* evmc_load_and_create(const char* filename,
if (!create_fn) if (!create_fn)
return NULL; return NULL;
enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS;
struct evmc_instance* instance = create_fn(); struct evmc_instance* instance = create_fn();
if (!instance) if (!instance)
{ {
*error_code = set_error(EVMC_LOADER_INSTANCE_CREATION_FAILURE, ec = set_error(EVMC_LOADER_INSTANCE_CREATION_FAILURE,
"creating EVMC instance of %s has failed", filename); "creating EVMC instance of %s has failed", filename);
return NULL; goto exit;
} }
if (!evmc_is_abi_compatible(instance)) 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); evmc_destroy(instance);
*error_code = set_error(EVMC_LOADER_ABI_VERSION_MISMATCH, instance = NULL;
"EVMC ABI version %d of %s mismatches the expected version %d", goto exit;
instance->abi_version, filename, EVMC_ABI_VERSION);
return NULL;
} }
exit:
if (error_code)
*error_code = ec;
return instance; return instance;
} }

View File

@ -301,6 +301,11 @@ TEST_F(loader, load_and_create_failure)
EXPECT_TRUE(vm == nullptr); EXPECT_TRUE(vm == nullptr);
EXPECT_EQ(ec, EVMC_LOADER_INSTANCE_CREATION_FAILURE); EXPECT_EQ(ec, EVMC_LOADER_INSTANCE_CREATION_FAILURE);
EXPECT_STREQ(evmc_last_error_msg(), "creating EVMC instance of failure.vm has failed"); EXPECT_STREQ(evmc_last_error_msg(), "creating EVMC instance of failure.vm has failed");
EXPECT_TRUE(evmc_last_error_msg() == nullptr);
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) TEST_F(loader, load_and_create_abi_mismatch)
@ -315,5 +320,11 @@ TEST_F(loader, load_and_create_abi_mismatch)
"EVMC ABI version 1985 of abi1985.vm mismatches the expected version " + "EVMC ABI version 1985 of abi1985.vm mismatches the expected version " +
std::to_string(EVMC_ABI_VERSION); std::to_string(EVMC_ABI_VERSION);
EXPECT_EQ(evmc_last_error_msg(), expected_error_msg); 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); EXPECT_EQ(destroy_count, create_count);
} }