Affix
view release on metacpan or search on metacpan
infix/src/core/loader.c view on Meta::CPAN
_infix_set_system_error(INFIX_CATEGORY_GENERAL, INFIX_CODE_LIBRARY_LOAD_FAILED, GetLastError(), nullptr);
#else
// On POSIX, dlerror() returns a human-readable string.
_infix_set_system_error(INFIX_CATEGORY_GENERAL, INFIX_CODE_LIBRARY_LOAD_FAILED, 0, dlerror());
#endif
infix_free(lib);
return nullptr;
}
return lib;
}
/**
* @brief Closes a dynamic library handle and frees associated resources.
*
* This is a cross-platform wrapper around `FreeLibrary` (Windows) and `dlclose` (POSIX).
*
* @param[in] lib The library handle to close. It is safe to call this function with `nullptr`.
*/
INFIX_API void infix_library_close(infix_library_t * lib) {
if (lib == nullptr)
return;
if (lib->handle) {
#if defined(INFIX_OS_WINDOWS)
// Only call FreeLibrary on real handles obtained from LoadLibrary.
// Never call it on a pseudo-handle from GetModuleHandle.
if (!lib->is_pseudo_handle)
FreeLibrary((HMODULE)lib->handle);
#else
dlclose(lib->handle);
#endif
}
infix_free(lib);
}
/**
* @brief Retrieves the address of a symbol (function or variable) from a loaded library.
*
* This is a cross-platform wrapper around `GetProcAddress` (Windows) and `dlsym` (POSIX).
*
* @note On POSIX, `dlsym` returning `NULL` is not a definitive error condition, as a
* symbol's address could itself be `NULL`. The official way to check for an
* error is to call `dlerror()` afterwards. This function does not perform
* that check and does not set the `infix` error state, as its primary callers
* (`infix_read_global`, etc.) will set a more specific `INFIX_CODE_SYMBOL_NOT_FOUND`
* error if the lookup fails.
*
* @param[in] lib The library handle.
* @param[in] symbol_name The name of the symbol to look up (e.g., `"my_function"`).
* @return A `void*` pointer to the symbol's address, or `nullptr` if not found.
*/
INFIX_API INFIX_NODISCARD void * infix_library_get_symbol(infix_library_t * lib, const char * symbol_name) {
if (lib == nullptr || lib->handle == nullptr || symbol_name == nullptr)
return nullptr;
#if defined(INFIX_OS_WINDOWS)
return (void *)GetProcAddress((HMODULE)lib->handle, symbol_name);
#else
return dlsym(lib->handle, symbol_name);
#endif
}
/**
* @brief Reads the value of an exported global variable from a library into a buffer.
*
* This function first looks up the symbol's address. It then uses the `infix`
* signature parser (`infix_type_from_signature`) to determine the size of the
* variable. This ensures that the correct number of bytes are copied from the
* library's data segment into the user's buffer, preventing buffer overflows.
*
* @param[in] lib The library handle.
* @param[in] symbol_name The name of the global variable.
* @param[in] type_signature The `infix` signature string describing the variable's type (e.g., `"int32"`,
* `"{double,double}"`).
* @param[out] buffer A pointer to the destination buffer to receive the data. This buffer must be large enough to hold
* the type described by the signature.
* @param[in] registry An optional registry for resolving named types in the signature.
* @return `INFIX_SUCCESS` on success, or an error code on failure (e.g., symbol not found, invalid signature).
*/
INFIX_API INFIX_NODISCARD infix_status infix_read_global(infix_library_t * lib,
const char * symbol_name,
const char * type_signature,
void * buffer,
infix_registry_t * registry) {
if (buffer == nullptr)
return INFIX_ERROR_INVALID_ARGUMENT;
void * symbol_addr = infix_library_get_symbol(lib, symbol_name);
if (symbol_addr == nullptr) {
_infix_set_error(INFIX_CATEGORY_GENERAL, INFIX_CODE_SYMBOL_NOT_FOUND, 0);
return INFIX_ERROR_INVALID_ARGUMENT;
}
// Parse the signature to get the type's size.
infix_type * type = nullptr;
infix_arena_t * arena = nullptr;
infix_status status = infix_type_from_signature(&type, &arena, type_signature, registry);
if (status != INFIX_SUCCESS)
return status;
// Safely copy the data using the parsed size.
infix_memcpy(buffer, symbol_addr, type->size);
infix_arena_destroy(arena);
return INFIX_SUCCESS;
}
/**
* @brief Writes data from a buffer into an exported global variable in a library.
*
* @details This function is analogous to `infix_read_global`. It finds the symbol's
* address and uses the signature string to determine the correct number of bytes
* to copy from the source buffer to the library's memory.
*
* @note This operation assumes that the memory page containing the global variable
* is writable. This is typical for `.data` or `.bss` segments but may fail
* if the variable is in a read-only segment (e.g., a `const` global). The
* function does not attempt to change memory permissions.
*
* @param[in] lib The library handle.
* @param[in] symbol_name The name of the global variable.
* @param[in] type_signature The `infix` signature string describing the variable's type.
* @param[in] buffer A pointer to the source buffer containing the data to write.
* @param[in] registry An optional registry for resolving named types in the signature.
* @return `INFIX_SUCCESS` on success, or an error code on failure.
*/
INFIX_API INFIX_NODISCARD infix_status infix_write_global(infix_library_t * lib,
const char * symbol_name,
const char * type_signature,
void * buffer,
infix_registry_t * registry) {
( run in 0.700 second using v1.01-cache-2.11-cpan-39bf76dae61 )