From dbf8d6513bf544cf4fa683ff01ccd86b15515c9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Pr=C3=BCsse?= Date: Fri, 14 Jun 2024 15:33:48 -0300 Subject: [PATCH] Update the sdk bootstrap code to fail fast on clear problems with the lib from alfasim The problems covered in this update: - Can not load the lib (not found or corrupted); - Can not fetch the address of a function from the lib; ASIM-5532 --- src/alfasim_sdk/alfasim_sdk_api/common.h | 2 + .../alfasim_sdk_api/detail/bootstrap_linux.h | 116 +++++++++++------- .../alfasim_sdk_api/detail/bootstrap_win.h | 110 ++++++++++------- 3 files changed, 136 insertions(+), 92 deletions(-) diff --git a/src/alfasim_sdk/alfasim_sdk_api/common.h b/src/alfasim_sdk/alfasim_sdk_api/common.h index 9aa1ea8a..31182708 100644 --- a/src/alfasim_sdk/alfasim_sdk_api/common.h +++ b/src/alfasim_sdk/alfasim_sdk_api/common.h @@ -107,6 +107,8 @@ struct VariableScope It holds the possible returning error code when trying to open ALFAsim-SDK API. */ enum sdk_load_error_code { + SDK_FAILED_TO_LOAD_FUNCTION=-4, /*!< Some function from SDK dll could not be loaded.*/ + SDK_FAILED_TO_LOAD_DLL=-3, /*!< SDK dll could not be loaded.*/ SDK_DLL_PATH_TOO_LONG=-2, /*!< Path to SDK dll too long (Windows limitation).*/ SDK_ALREADY_OPEN_ERROR=-1, /*!< SDK dll already Opened.*/ SDK_OK=0 /*!< Everything was fine.*/ diff --git a/src/alfasim_sdk/alfasim_sdk_api/detail/bootstrap_linux.h b/src/alfasim_sdk/alfasim_sdk_api/detail/bootstrap_linux.h index 44285089..b4f03d73 100644 --- a/src/alfasim_sdk/alfasim_sdk_api/detail/bootstrap_linux.h +++ b/src/alfasim_sdk/alfasim_sdk_api/detail/bootstrap_linux.h @@ -44,56 +44,80 @@ inline int alfasim_sdk_open(ALFAsimSDK_API* api) // Load shared object char *full_filepath = NULL; asprintf(&full_filepath, "%s%s", alfasim_executable_dir, SO_FILENAME); + + // https://www.man7.org/linux/man-pages/man3/dlopen.3.html + // > If dlopen() fails for any reason, it returns NULL. api->handle = dlopen(full_filepath, RTLD_LAZY); free(full_filepath); + if (api->handle == NULL) { + return SDK_FAILED_TO_LOAD_DLL; + } + + // https://man7.org/linux/man-pages/man3/dlsym.3.html + // > In unusual cases (see NOTES) the value of the symbol could actually be NULL. Therefore, + // > a NULL return from dlsym() need not indicate an error. The correct way to distinguish an + // > error from a symbol whose value is NULL is to call dlerror(3) to clear any old error + // > conditions, then call dlsym(), and then call dlerror(3) again, saving its return value + // > into a variable, and check whether this saved value is not NULL. + #define LOAD_SDK_PROC_MAP_TYPE(func_name, func_type) {\ + dlerror();\ + api->func_name = (func_type)dlsym(api->handle, #func_name);\ + char *last_error = dlerror();\ + if (last_error != NULL) {\ + dlclose(api->handle);\ + api->handle = nullptr;\ + return SDK_FAILED_TO_LOAD_FUNCTION;\ + }\ + } + #define LOAD_SDK_PROC(func_name) LOAD_SDK_PROC_MAP_TYPE(func_name, func_name ## _func) // Register alfasim API - api->set_plugin_data = (set_plugin_data_func)dlsym(api->handle, "set_plugin_data"); - api->get_plugin_data = (get_plugin_data_func)dlsym(api->handle, "get_plugin_data"); - api->get_number_of_threads = (get_number_of_threads_func)dlsym(api->handle, "get_number_of_threads"); - api->get_thread_id = (get_thread_id_func)dlsym(api->handle, "get_thread_id"); - api->get_plugin_input_data_boolean = (get_plugin_input_data_boolean_func)dlsym(api->handle, "get_plugin_input_data_boolean"); - api->get_plugin_input_data_enum = (get_plugin_input_data_enum_func)dlsym(api->handle, "get_plugin_input_data_enum"); - api->get_plugin_input_data_quantity = (get_plugin_input_data_quantity_func)dlsym(api->handle, "get_plugin_input_data_quantity"); - api->get_plugin_input_data_string = (get_plugin_input_data_string_func)dlsym(api->handle, "get_plugin_input_data_string"); - api->get_plugin_input_data_string_size = (get_plugin_input_data_string_size_func)dlsym(api->handle, "get_plugin_input_data_string_size"); - api->get_plugin_input_data_file_content = (get_plugin_input_data_file_content_func)dlsym(api->handle, "get_plugin_input_data_file_content"); - api->get_plugin_input_data_file_content_size = (get_plugin_input_data_file_content_size_func)dlsym(api->handle, "get_plugin_input_data_file_content_size"); - api->get_plugin_input_data_reference = (get_plugin_input_data_reference_func)dlsym(api->handle, "get_plugin_input_data_reference"); - api->get_plugin_variable = (get_plugin_variable_func)dlsym(api->handle, "get_plugin_variable"); - api->get_field_id = (get_field_id_func)dlsym(api->handle, "get_field_id"); - api->get_phase_id = (get_phase_id_func)dlsym(api->handle, "get_phase_id"); - api->get_layer_id = (get_layer_id_func)dlsym(api->handle, "get_layer_id"); - api->get_number_of_fields = (get_number_of_fields_func)dlsym(api->handle, "get_number_of_fields"); - api->get_number_of_phases = (get_number_of_phases_func)dlsym(api->handle, "get_number_of_phases"); - api->get_number_of_layers = (get_number_of_layers_func)dlsym(api->handle, "get_number_of_layers"); - api->get_number_of_phase_pairs = (get_number_of_phase_pairs_func)dlsym(api->handle, "get_number_of_phase_pairs"); - api->get_primary_field_id_of_phase = (get_field_id_func)dlsym(api->handle, "get_primary_field_id_of_phase"); - api->get_phase_id_of_fields = (get_phase_id_of_fields_func)dlsym(api->handle, "get_phase_id_of_fields"); - api->get_field_ids_in_layer = (get_field_ids_in_layer_func)dlsym(api->handle, "get_field_ids_in_layer"); - api->get_phase_pair_id = (get_phase_pair_id_func)dlsym(api->handle, "get_phase_pair_id"); - api->get_state_variable_array = (get_state_variable_array_func)dlsym(api->handle, "get_state_variable_array"); - api->get_simulation_array = (get_simulation_array_func)dlsym(api->handle, "get_simulation_array"); - api->get_simulation_tracer_array = (get_simulation_tracer_array_func)dlsym(api->handle, "get_simulation_tracer_array"); - api->get_simulation_quantity = (get_simulation_quantity_func)dlsym(api->handle, "get_simulation_quantity"); - api->get_wall_interfaces_temperature = (get_wall_interfaces_temperature_func)dlsym(api->handle, "get_wall_interfaces_temperature"); - api->get_flow_pattern = (get_flow_pattern_func)dlsym(api->handle, "get_flow_pattern"); - api->get_liqliq_flow_pattern = (get_flow_pattern_func)dlsym(api->handle, "get_liqliq_flow_pattern"); - api->get_deposition_thickness = (get_deposition_thickness_func)dlsym(api->handle, "get_deposition_thickness"); - api->get_plugin_input_data_table_quantity = (get_plugin_input_data_table_quantity_func)dlsym(api->handle, "get_plugin_input_data_table_quantity"); - api->get_tracer_id = (get_tracer_id_func)dlsym(api->handle, "get_tracer_id"); - api->get_tracer_name_size = (get_tracer_name_size_func)dlsym(api->handle, "get_tracer_name_size"); - api->get_tracer_name = (get_tracer_name_func)dlsym(api->handle, "get_tracer_name"); - api->get_tracer_ref_by_name = (get_tracer_ref_by_name_func)dlsym(api->handle, "get_tracer_ref_by_name"); - api->get_tracer_partition_coefficient = (get_tracer_partition_coefficient_func)dlsym(api->handle, "get_tracer_partition_coefficient"); - api->get_plugin_input_data_multiplereference_selected_size = (get_plugin_input_data_multiplereference_selected_size_func)dlsym(api->handle, "get_plugin_input_data_multiplereference_selected_size"); - api->get_ucm_friction_factor_input_variable = (get_input_variable_func)dlsym(api->handle, "get_ucm_friction_factor_input_variable"); - api->get_ucm_fluid_geometrical_properties = (get_ucm_fluid_geometrical_properties_func)dlsym(api->handle, "get_ucm_fluid_geometrical_properties"); - api->get_liq_liq_flow_pattern_input_variable = (get_input_variable_func)dlsym(api->handle, "get_liq_liq_flow_pattern_input_variable"); - api->get_liquid_effective_viscosity_input_variable = (get_input_variable_func)dlsym(api->handle, "get_liquid_effective_viscosity_input_variable"); - api->get_gas_liq_surface_tension_input_variable = (get_input_variable_func)dlsym(api->handle, "get_gas_liq_surface_tension_input_variable"); - api->get_liq_liq_shear_force_per_volume_input_variable = (get_input_variable_func)dlsym(api->handle, "get_liq_liq_shear_force_per_volume_input_variable"); - api->get_relative_emulsion_viscosity = (get_relative_emulsion_viscosity_func)dlsym(api->handle, "get_relative_emulsion_viscosity"); + LOAD_SDK_PROC(set_plugin_data) + LOAD_SDK_PROC(get_plugin_data) + LOAD_SDK_PROC(get_number_of_threads) + LOAD_SDK_PROC(get_thread_id) + LOAD_SDK_PROC(get_plugin_input_data_boolean) + LOAD_SDK_PROC(get_plugin_input_data_enum) + LOAD_SDK_PROC(get_plugin_input_data_quantity) + LOAD_SDK_PROC(get_plugin_input_data_string) + LOAD_SDK_PROC(get_plugin_input_data_string_size) + LOAD_SDK_PROC(get_plugin_input_data_file_content) + LOAD_SDK_PROC(get_plugin_input_data_file_content_size) + LOAD_SDK_PROC(get_plugin_input_data_reference) + LOAD_SDK_PROC(get_plugin_variable) + LOAD_SDK_PROC(get_field_id) + LOAD_SDK_PROC(get_phase_id) + LOAD_SDK_PROC(get_layer_id) + LOAD_SDK_PROC(get_number_of_fields) + LOAD_SDK_PROC(get_number_of_phases) + LOAD_SDK_PROC(get_number_of_layers) + LOAD_SDK_PROC(get_number_of_phase_pairs) + LOAD_SDK_PROC_MAP_TYPE(get_primary_field_id_of_phase, get_field_id_func) + LOAD_SDK_PROC(get_phase_id_of_fields) + LOAD_SDK_PROC(get_field_ids_in_layer) + LOAD_SDK_PROC(get_phase_pair_id) + LOAD_SDK_PROC(get_state_variable_array) + LOAD_SDK_PROC(get_simulation_array) + LOAD_SDK_PROC(get_simulation_tracer_array) + LOAD_SDK_PROC(get_simulation_quantity) + LOAD_SDK_PROC(get_wall_interfaces_temperature) + LOAD_SDK_PROC(get_flow_pattern) + LOAD_SDK_PROC_MAP_TYPE(get_liqliq_flow_pattern, get_flow_pattern_func) + LOAD_SDK_PROC(get_deposition_thickness) + LOAD_SDK_PROC(get_plugin_input_data_table_quantity) + LOAD_SDK_PROC(get_tracer_id) + LOAD_SDK_PROC(get_tracer_name_size) + LOAD_SDK_PROC(get_tracer_name) + LOAD_SDK_PROC(get_tracer_ref_by_name) + LOAD_SDK_PROC(get_tracer_partition_coefficient) + LOAD_SDK_PROC(get_plugin_input_data_multiplereference_selected_size) + LOAD_SDK_PROC_MAP_TYPE(get_ucm_friction_factor_input_variable, get_input_variable_func) + LOAD_SDK_PROC(get_ucm_fluid_geometrical_properties) + LOAD_SDK_PROC_MAP_TYPE(get_liq_liq_flow_pattern_input_variable, get_input_variable_func) + LOAD_SDK_PROC_MAP_TYPE(get_liquid_effective_viscosity_input_variable, get_input_variable_func) + LOAD_SDK_PROC_MAP_TYPE(get_gas_liq_surface_tension_input_variable, get_input_variable_func) + LOAD_SDK_PROC_MAP_TYPE(get_liq_liq_shear_force_per_volume_input_variable, get_input_variable_func) + LOAD_SDK_PROC(get_relative_emulsion_viscosity) return SDK_OK; } diff --git a/src/alfasim_sdk/alfasim_sdk_api/detail/bootstrap_win.h b/src/alfasim_sdk/alfasim_sdk_api/detail/bootstrap_win.h index 797eb24b..b87c8a96 100644 --- a/src/alfasim_sdk/alfasim_sdk_api/detail/bootstrap_win.h +++ b/src/alfasim_sdk/alfasim_sdk_api/detail/bootstrap_win.h @@ -68,56 +68,74 @@ inline int alfasim_sdk_open(ALFAsimSDK_API* api) full_filepath[0] = '\0'; StringCchCatW(full_filepath, MAX_PATH_SIZE, alfasim_executable_dir); StringCchCatW(full_filepath, MAX_PATH_SIZE, DLL_FILENAME); + + // https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw + // > If the function fails, the return value is NULL. api->handle = LoadLibraryW(full_filepath); free(executable_dir_from_env); + if (api->handle == NULL) { + return SDK_FAILED_TO_LOAD_DLL; + } + + // https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress + // > If the function fails, the return value is NULL. + #define LOAD_SDK_PROC_MAP_TYPE(func_name, func_type) {\ + api->func_name = (func_type)GetProcAddress(api->handle, #func_name);\ + if (api->func_name == NULL) {\ + FreeLibrary(api->handle);\ + api->handle = nullptr;\ + return SDK_FAILED_TO_LOAD_FUNCTION;\ + }\ + } + #define LOAD_SDK_PROC(func_name) LOAD_SDK_PROC_MAP_TYPE(func_name, func_name ## _func) // Register alfasim API - api->set_plugin_data = (set_plugin_data_func)GetProcAddress(api->handle, "set_plugin_data"); - api->get_plugin_data = (get_plugin_data_func)GetProcAddress(api->handle, "get_plugin_data"); - api->get_number_of_threads = (get_number_of_threads_func)GetProcAddress(api->handle, "get_number_of_threads"); - api->get_thread_id = (get_thread_id_func)GetProcAddress(api->handle, "get_thread_id"); - api->get_plugin_input_data_boolean = (get_plugin_input_data_boolean_func)GetProcAddress(api->handle, "get_plugin_input_data_boolean"); - api->get_plugin_input_data_enum = (get_plugin_input_data_enum_func)GetProcAddress(api->handle, "get_plugin_input_data_enum"); - api->get_plugin_input_data_quantity = (get_plugin_input_data_quantity_func)GetProcAddress(api->handle, "get_plugin_input_data_quantity"); - api->get_plugin_input_data_string = (get_plugin_input_data_string_func)GetProcAddress(api->handle, "get_plugin_input_data_string"); - api->get_plugin_input_data_string_size = (get_plugin_input_data_string_size_func)GetProcAddress(api->handle, "get_plugin_input_data_string_size"); - api->get_plugin_input_data_file_content = (get_plugin_input_data_file_content_func)GetProcAddress(api->handle, "get_plugin_input_data_file_content"); - api->get_plugin_input_data_file_content_size = (get_plugin_input_data_file_content_size_func)GetProcAddress(api->handle, "get_plugin_input_data_file_content_size"); - api->get_plugin_input_data_reference = (get_plugin_input_data_reference_func)GetProcAddress(api->handle, "get_plugin_input_data_reference"); - api->get_plugin_variable = (get_plugin_variable_func)GetProcAddress(api->handle, "get_plugin_variable"); - api->get_field_id = (get_field_id_func)GetProcAddress(api->handle, "get_field_id"); - api->get_phase_id = (get_phase_id_func)GetProcAddress(api->handle, "get_phase_id"); - api->get_layer_id = (get_layer_id_func)GetProcAddress(api->handle, "get_layer_id"); - api->get_number_of_fields = (get_number_of_fields_func)GetProcAddress(api->handle, "get_number_of_fields"); - api->get_number_of_phases = (get_number_of_phases_func)GetProcAddress(api->handle, "get_number_of_phases"); - api->get_number_of_layers = (get_number_of_layers_func)GetProcAddress(api->handle, "get_number_of_layers"); - api->get_number_of_phase_pairs = (get_number_of_phase_pairs_func)GetProcAddress(api->handle, "get_number_of_phase_pairs"); - api->get_primary_field_id_of_phase = (get_primary_field_id_of_phase_func)GetProcAddress(api->handle, "get_primary_field_id_of_phase"); - api->get_phase_id_of_fields = (get_phase_id_of_fields_func)GetProcAddress(api->handle, "get_phase_id_of_fields"); - api->get_field_ids_in_layer = (get_field_ids_in_layer_func)GetProcAddress(api->handle, "get_field_ids_in_layer"); - api->get_phase_pair_id = (get_phase_pair_id_func)GetProcAddress(api->handle, "get_phase_pair_id"); - api->get_state_variable_array = (get_state_variable_array_func)GetProcAddress(api->handle, "get_state_variable_array"); - api->get_simulation_array = (get_simulation_array_func)GetProcAddress(api->handle, "get_simulation_array"); - api->get_simulation_tracer_array = (get_simulation_tracer_array_func)GetProcAddress(api->handle, "get_simulation_tracer_array"); - api->get_simulation_quantity = (get_simulation_quantity_func)GetProcAddress(api->handle, "get_simulation_quantity"); - api->get_wall_interfaces_temperature = (get_wall_interfaces_temperature_func)GetProcAddress(api->handle, "get_wall_interfaces_temperature"); - api->get_flow_pattern = (get_flow_pattern_func)GetProcAddress(api->handle, "get_flow_pattern"); - api->get_liqliq_flow_pattern = (get_flow_pattern_func)GetProcAddress(api->handle, "get_liqliq_flow_pattern"); - api->get_deposition_thickness = (get_deposition_thickness_func)GetProcAddress(api->handle, "get_deposition_thickness"); - api->get_plugin_input_data_table_quantity = (get_plugin_input_data_table_quantity_func)GetProcAddress(api->handle, "get_plugin_input_data_table_quantity"); - api->get_tracer_id = (get_tracer_id_func)GetProcAddress(api->handle, "get_tracer_id"); - api->get_tracer_name_size = (get_tracer_name_size_func)GetProcAddress(api->handle, "get_tracer_name_size"); - api->get_tracer_name = (get_tracer_name_func)GetProcAddress(api->handle, "get_tracer_name"); - api->get_tracer_ref_by_name = (get_tracer_ref_by_name_func)GetProcAddress(api->handle, "get_tracer_ref_by_name"); - api->get_tracer_partition_coefficient = (get_tracer_partition_coefficient_func)GetProcAddress(api->handle, "get_tracer_partition_coefficient"); - api->get_plugin_input_data_multiplereference_selected_size = (get_plugin_input_data_multiplereference_selected_size_func)GetProcAddress(api->handle, "get_plugin_input_data_multiplereference_selected_size"); - api->get_ucm_friction_factor_input_variable = (get_input_variable_func)GetProcAddress(api->handle, "get_ucm_friction_factor_input_variable"); - api->get_ucm_fluid_geometrical_properties = (get_ucm_fluid_geometrical_properties_func)GetProcAddress(api->handle, "get_ucm_fluid_geometrical_properties"); - api->get_liq_liq_flow_pattern_input_variable = (get_input_variable_func)GetProcAddress(api->handle, "get_liq_liq_flow_pattern_input_variable"); - api->get_liquid_effective_viscosity_input_variable = (get_input_variable_func)GetProcAddress(api->handle, "get_liquid_effective_viscosity_input_variable"); - api->get_gas_liq_surface_tension_input_variable = (get_input_variable_func)GetProcAddress(api->handle, "get_gas_liq_surface_tension_input_variable"); - api->get_liq_liq_shear_force_per_volume_input_variable = (get_input_variable_func)GetProcAddress(api->handle, "get_liq_liq_shear_force_per_volume_input_variable"); - api->get_relative_emulsion_viscosity = (get_relative_emulsion_viscosity_func)GetProcAddress(api->handle, "get_relative_emulsion_viscosity"); + LOAD_SDK_PROC(set_plugin_data) + LOAD_SDK_PROC(get_plugin_data) + LOAD_SDK_PROC(get_number_of_threads) + LOAD_SDK_PROC(get_thread_id) + LOAD_SDK_PROC(get_plugin_input_data_boolean) + LOAD_SDK_PROC(get_plugin_input_data_enum) + LOAD_SDK_PROC(get_plugin_input_data_quantity) + LOAD_SDK_PROC(get_plugin_input_data_string) + LOAD_SDK_PROC(get_plugin_input_data_string_size) + LOAD_SDK_PROC(get_plugin_input_data_file_content) + LOAD_SDK_PROC(get_plugin_input_data_file_content_size) + LOAD_SDK_PROC(get_plugin_input_data_reference) + LOAD_SDK_PROC(get_plugin_variable) + LOAD_SDK_PROC(get_field_id) + LOAD_SDK_PROC(get_phase_id) + LOAD_SDK_PROC(get_layer_id) + LOAD_SDK_PROC(get_number_of_fields) + LOAD_SDK_PROC(get_number_of_phases) + LOAD_SDK_PROC(get_number_of_layers) + LOAD_SDK_PROC(get_number_of_phase_pairs) + LOAD_SDK_PROC(get_primary_field_id_of_phase) + LOAD_SDK_PROC(get_phase_id_of_fields) + LOAD_SDK_PROC(get_field_ids_in_layer) + LOAD_SDK_PROC(get_phase_pair_id) + LOAD_SDK_PROC(get_state_variable_array) + LOAD_SDK_PROC(get_simulation_array) + LOAD_SDK_PROC(get_simulation_tracer_array) + LOAD_SDK_PROC(get_simulation_quantity) + LOAD_SDK_PROC(get_wall_interfaces_temperature) + LOAD_SDK_PROC(get_flow_pattern) + LOAD_SDK_PROC_MAP_TYPE(get_liqliq_flow_pattern, get_flow_pattern_func) + LOAD_SDK_PROC(get_deposition_thickness) + LOAD_SDK_PROC(get_plugin_input_data_table_quantity) + LOAD_SDK_PROC(get_tracer_id) + LOAD_SDK_PROC(get_tracer_name_size) + LOAD_SDK_PROC(get_tracer_name) + LOAD_SDK_PROC(get_tracer_ref_by_name) + LOAD_SDK_PROC(get_tracer_partition_coefficient) + LOAD_SDK_PROC(get_plugin_input_data_multiplereference_selected_size) + LOAD_SDK_PROC_MAP_TYPE(get_ucm_friction_factor_input_variable, get_input_variable_func) + LOAD_SDK_PROC(get_ucm_fluid_geometrical_properties) + LOAD_SDK_PROC_MAP_TYPE(get_liq_liq_flow_pattern_input_variable, get_input_variable_func) + LOAD_SDK_PROC_MAP_TYPE(get_liquid_effective_viscosity_input_variable, get_input_variable_func) + LOAD_SDK_PROC_MAP_TYPE(get_gas_liq_surface_tension_input_variable, get_input_variable_func) + LOAD_SDK_PROC_MAP_TYPE(get_liq_liq_shear_force_per_volume_input_variable, get_input_variable_func) + LOAD_SDK_PROC(get_relative_emulsion_viscosity) return SDK_OK; }