loader: Expose DLL load errors with evmc_last_error_msg()

Currently only works for errors by dlopen() on Linux and macos, otherwise returns NULL.
This commit is contained in:
Paweł Bylica 2019-04-16 18:04:42 +02:00
parent 4408da2758
commit 14c5356ae6
No known key found for this signature in database
GPG Key ID: 7A0C037434FE77EF
5 changed files with 44 additions and 5 deletions

View File

@ -158,7 +158,13 @@ func Load(filename string) (instance *Instance, err error) {
case C.EVMC_LOADER_SUCCESS:
instance = &Instance{handle}
case C.EVMC_LOADER_CANNOT_OPEN:
err = fmt.Errorf("evmc loader: cannot open %s", filename)
optionalErrMsg := C.evmc_last_error_msg()
if optionalErrMsg != nil {
msg := C.GoString(optionalErrMsg)
err = fmt.Errorf("evmc loader: %s", msg)
} else {
err = fmt.Errorf("evmc loader: cannot open %s", filename)
}
case C.EVMC_LOADER_SYMBOL_NOT_FOUND:
err = fmt.Errorf("evmc loader: the EVMC create function not found in %s", filename)
case C.EVMC_LOADER_INVALID_ARGUMENT:

View File

@ -1,6 +1,6 @@
/* EVMC: Ethereum Client-VM Connector API.
* Copyright 2018 The EVMC Authors.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
* Copyright 2019 The EVMC Authors.
* Licensed under the Apache License, Version 2.0.
*/
/**
@ -103,6 +103,19 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
struct evmc_instance* evmc_load_and_create(const char* filename,
enum evmc_loader_error_code* error_code);
/**
* Returns the human-readable message describing the most recent error
* that occurred in EVMC loading.
*
* In case any loading function returned ::EVMC_LOADER_SUCCESS this function always returns NULL.
* In case of error code other than success returned, this function MAY return the error message.
* This function is not thread-safe.
*
* @return Error message or NULL if no additional information is available.
* The returned pointer MUST NOT be freed by the caller.
*/
const char* evmc_last_error_msg();
#if __cplusplus
}
#endif

View File

@ -44,9 +44,12 @@ static void strcpy_s(char* dest, size_t destsz, const char* src)
}
#endif
static const char* last_error_msg = NULL;
evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* error_code)
{
last_error_msg = NULL; // Reset last error.
enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS;
evmc_create_fn create_fn = NULL;
@ -66,6 +69,11 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
DLL_HANDLE handle = DLL_OPEN(filename);
if (!handle)
{
#if !defined(EVMC_LOADER_MOCK) && !_WIN32
// If available, get the error message from dlerror().
last_error_msg = dlerror();
#endif
ec = EVMC_LOADER_CANNOT_OPEN;
goto exit;
}
@ -130,9 +138,15 @@ exit:
return create_fn;
}
const char* evmc_last_error_msg()
{
return last_error_msg;
}
struct evmc_instance* evmc_load_and_create(const char* filename,
enum evmc_loader_error_code* error_code)
{
// First load the DLL. This also resets the last_error_msg;
evmc_create_fn create_fn = evmc_load(filename, error_code);
if (!create_fn)

View File

@ -18,7 +18,7 @@ add_test(NAME vmtester/help COMMAND evmc-vmtester --version --help)
set_tests_properties(vmtester/help PROPERTIES PASS_REGULAR_EXPRESSION "Usage:")
add_test(NAME vmtester/nonexistingvm COMMAND evmc-vmtester nonexistingvm)
set_tests_properties(vmtester/nonexistingvm PROPERTIES PASS_REGULAR_EXPRESSION "Cannot open")
set_tests_properties(vmtester/nonexistingvm PROPERTIES PASS_REGULAR_EXPRESSION "[Cc]annot open")
add_test(NAME vmtester/noarg COMMAND evmc-vmtester)
set_tests_properties(vmtester/noarg PROPERTIES PASS_REGULAR_EXPRESSION "is required")

View File

@ -140,8 +140,14 @@ int main(int argc, char* argv[])
case EVMC_LOADER_SUCCESS:
break;
case EVMC_LOADER_CANNOT_OPEN:
std::cerr << "Cannot open " << evmc_module << "\n";
{
const auto error = evmc_last_error_msg();
if (error)
std::cerr << error << "\n";
else
std::cerr << "Cannot open " << evmc_module << "\n";
return static_cast<int>(ec);
}
case EVMC_LOADER_SYMBOL_NOT_FOUND:
std::cerr << "EVMC create function not found in " << evmc_module << "\n";
return static_cast<int>(ec);