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 )