/* EVMC: Ethereum Client-VM Connector API. * Copyright 2018 The EVMC Authors. * Licensed under the Apache License, Version 2.0. See the LICENSE file. */ #include #include #include #include #include #if _WIN32 #include #define DLL_HANDLE HMODULE #define DLL_OPEN(filename) LoadLibrary(filename) #define DLL_CLOSE(handle) FreeLibrary(handle) #define DLL_GET_CREATE_FN(handle, name) (evmc_create_fn) GetProcAddress(handle, name) #define HAVE_STRCPY_S 1 #else #include #define DLL_HANDLE void* #define DLL_OPEN(filename) dlopen(filename, RTLD_LAZY) #define DLL_CLOSE(handle) dlclose(handle) #define DLL_GET_CREATE_FN(handle, name) (evmc_create_fn)(uintptr_t) dlsym(handle, name) #define HAVE_STRCPY_S 0 #endif #define PATH_MAX_LENGTH 4096 #if !HAVE_STRCPY_S static void strcpy_s(char* dest, size_t destsz, const char* src) { size_t len = strlen(src); if (len > destsz - 1) len = destsz - 1; memcpy(dest, src, len); dest[len] = 0; } #endif evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* error_code) { enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS; evmc_create_fn create_fn = NULL; if (!filename) { ec = EVMC_LOADER_INVALID_ARGUMENT; goto exit; } const size_t length = strlen(filename); if (length == 0 || length > PATH_MAX_LENGTH) { ec = EVMC_LOADER_INVALID_ARGUMENT; goto exit; } DLL_HANDLE handle = DLL_OPEN(filename); if (!handle) { ec = EVMC_LOADER_CANNOT_OPEN; goto exit; } // Create name buffer with the prefix. const char prefix[] = "evmc_create_"; const size_t prefix_length = strlen(prefix); char name[sizeof(prefix) + PATH_MAX_LENGTH]; strcpy_s(name, sizeof(name), prefix); // Find filename in the path. const char* sep_pos = strrchr(filename, '/'); #if _WIN32 // On Windows check also Windows classic path separator. const char* sep_pos_windows = strrchr(filename, '\\'); sep_pos = sep_pos_windows > sep_pos ? sep_pos_windows : sep_pos; #endif const char* name_pos = sep_pos ? sep_pos + 1 : filename; // Skip "lib" prefix if present. const char lib_prefix[] = "lib"; const size_t lib_prefix_length = strlen(lib_prefix); if (strncmp(name_pos, lib_prefix, lib_prefix_length) == 0) name_pos += lib_prefix_length; strcpy_s(name + prefix_length, PATH_MAX_LENGTH, name_pos); // Trim the file extension. char* ext_pos = strrchr(name, '.'); if (ext_pos) *ext_pos = 0; // Replace all "-" with "_". char* dash_pos = name; while ((dash_pos = strchr(dash_pos, '-')) != NULL) *dash_pos++ = '_'; // Search for the "full name" based function name. create_fn = DLL_GET_CREATE_FN(handle, name); if (!create_fn) { // Try the "short name" based function name. const char* short_name_pos = strrchr(name, '_'); if (short_name_pos) { short_name_pos += 1; memmove(name + prefix_length, short_name_pos, strlen(short_name_pos) + 1); create_fn = DLL_GET_CREATE_FN(handle, name); } } if (!create_fn) create_fn = DLL_GET_CREATE_FN(handle, "evmc_create"); if (!create_fn) { DLL_CLOSE(handle); ec = EVMC_LOADER_SYMBOL_NOT_FOUND; } exit: if (error_code) *error_code = ec; return create_fn; } struct evmc_instance* evmc_load_and_create(const char* filename, enum evmc_loader_error_code* error_code) { evmc_create_fn create_fn = evmc_load(filename, error_code); if (!create_fn) return NULL; struct evmc_instance* instance = create_fn(); if (!instance) { *error_code = EVMC_LOADER_INSTANCE_CREATION_FAILURE; return NULL; } if (!evmc_is_abi_compatible(instance)) { *error_code = EVMC_LOADER_ABI_VERSION_MISMATCH; return NULL; } return instance; }