Skip to content

Windows Vulkan runtime bundles a mismatched MinGW libstdc++ #1160

Description

@ApexDevelopment

Summary

The Windows x86_64 Vulkan native runtime ships a libstdc++-6.dll built for a
different MinGW-w64 configuration than the DLLs that import it. As a result
libllama.dll cannot be loaded at all: LoadLibraryEx fails with
ERROR_PROC_NOT_FOUND (127). No GPU backend is registered and the node falls
back to CPU only.

Affected versions

  • 0.74.0
  • 0.75.0-rc1

sha256(lib/libstdc++-6.dll) is
3529d11c422b2aaf0bbad7221bf62ba7b5a39f854e89a015bb58b6b55a677da1 in both
releases.

Environment

  • Windows 10 (10.0.19044), x86_64
  • Runtime: meshllm-native-runtime-windows-x86_64-vulkan

Steps to reproduce

  1. Install the Windows Vulkan native runtime.
  2. From the runtime lib directory, call LoadLibraryExW on libllama.dll
    with LOAD_WITH_ALTERED_SEARCH_PATH.
  3. The call fails with error 127.

Expected

libllama.dll loads and the Vulkan backend registers its devices.

Actual

Load fails with error 127. Diffing the PE import tables of the shipped DLLs
against the export table of the shipped libstdc++-6.dll shows 16 imported
symbols that the bundled libstdc++-6.dll does not export.

ggml.dll (5 missing):

_ZNKSt25__codecvt_utf8_utf16_baseIwE10do_unshiftER9_MbstatetPcS3_RS3_
_ZNKSt25__codecvt_utf8_utf16_baseIwE5do_inER9_MbstatetPKcS4_RS4_PwS6_RS6_
_ZNKSt25__codecvt_utf8_utf16_baseIwE6do_outER9_MbstatetPKwS4_RS4_PcS6_RS6_
_ZNKSt25__codecvt_utf8_utf16_baseIwE9do_lengthER9_MbstatetPKcS4_y
_ZNSt7codecvtIwc9_MbstatetEC2Ey

libllama.dll (3 missing):

_ZNSo5seekpESt4fposI9_MbstatetE
__emutls_v._ZSt11__once_call
__emutls_v._ZSt15__once_callable

libllama-common.dll (8 missing): the five above plus

_ZNSt15basic_streambufIcSt11char_traitsIcEE7seekposESt4fposI9_MbstatetESt13_Ios_Openmode
__emutls_v._ZSt11__once_call
__emutls_v._ZSt15__once_callable

Analysis

The missing symbols identify a mismatch on two independent axes.

  1. Threading model. The importers reference __emutls_v._ZSt11__once_call and
    __emutls_v._ZSt15__once_callable, which a posix-threads libstdc++ emits.
    The bundled libstdc++-6.dll instead exports __get_once_callv and
    __get_once_callablev, which is the win32-threads form.

  2. C runtime. The importers reference symbols mangled with 9_Mbstatet, which
    is the UCRT mbstate_t. The bundled libstdc++-6.dll imports msvcrt.dll,
    not the api-ms-win-crt-* UCRT stubs that the other runtime DLLs import.

So the ggml and llama DLLs are built with a UCRT posix-threads toolchain while
the bundled support DLL is an MSVCRT win32-threads build.

Confirmed by replacing only libstdc++-6.dll, libgcc_s_seh-1.dll and
libwinpthread-1.dll with the UCRT posix-threads equivalents (WinLibs
winlibs-x86_64-posix-seh-gcc-16.1.0-mingw-w64ucrt-14.0.0-r2). After the swap
the import diff reports zero missing symbols for every DLL in the package, all
11 DLLs load, and the Vulkan backend enumerates the device correctly.

Likely origin

scripts/windows-native-runtime-deps.py:

  • default_search_dirs() puts $VULKAN_SDK/Bin and $VULKAN_SDK/Bin32 ahead
    of every PATH entry.
  • collect_dependencies() builds a filename keyed index and copies the first
    match, with no check that the resolved DLL is ABI compatible with the
    importer.

The LunarG SDK ships its own GCC runtime DLLs, so it wins that lookup.

scripts/build-llama.sh already documents this exact hazard around line 166,
including the resulting STATUS_ENTRYPOINT_NOT_FOUND (0xc0000139), and works
around it by putting the selected compiler's runtime directory first on PATH.
That workaround is applied to the build step only. The packaging script never
received the equivalent fix.

verify_dependencies() only reports missing files, so a resolved but ABI
incompatible DLL passes verification and ships.

Suggested fix

  1. In windows-native-runtime-deps.py, resolve MinGW runtime DLLs from the
    toolchain that built the artifacts (for example the directory of the g++
    used by build-llama.sh) and search that before $VULKAN_SDK.
  2. Extend verify_dependencies() to check that every imported symbol is
    exported by the DLL that was actually bundled. That turns this class of
    failure into a build error instead of a broken release.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions