From a80d3d31a34dc34b8fddbf585786cd51edafa7ad Mon Sep 17 00:00:00 2001 From: Simao Gomes Viana Date: Wed, 25 Mar 2026 13:57:23 +0100 Subject: [PATCH] ggml-vulkan: probe vkGetBufferDeviceAddress before enabling BDA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some Vulkan drivers (observed on Adreno, Qualcomm build 923a446bf8, driver date 09/05/24) report bufferDeviceAddress support in VkPhysicalDeviceVulkan12Features but crash with SIGSEGV when vkGetBufferDeviceAddress is actually called: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 #01 ggml_vk_create_buffer+4084 #02 ggml_vk_create_buffer_device+148 #03 ggml_backend_vk_buffer_type_alloc_buffer+240 #07 whisper_model_load+5996 The crash occurs inside ggml_vk_create_buffer when device->device.getBufferAddress() is called — the driver-internal function pointer dereferences null. After creating the logical device, verify that the function pointer resolves via vkGetDeviceProcAddr and that a test call returns a non-zero address. If either check fails, disable buffer_device_address so all guarded code paths skip BDA. --- ggml/src/ggml-vulkan/ggml-vulkan.cpp | 57 ++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/ggml/src/ggml-vulkan/ggml-vulkan.cpp b/ggml/src/ggml-vulkan/ggml-vulkan.cpp index 7092361d2..50efff144 100644 --- a/ggml/src/ggml-vulkan/ggml-vulkan.cpp +++ b/ggml/src/ggml-vulkan/ggml-vulkan.cpp @@ -5379,6 +5379,63 @@ static vk_device ggml_vk_get_device(size_t idx) { // Queues ggml_vk_create_queue(device, device->compute_queue, compute_queue_family_index, 0, { vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer }, false); + // Verify vkGetBufferDeviceAddress actually works — some drivers + // (e.g. certain Adreno builds) report bufferDeviceAddress support + // in the feature bits but crash (SIGSEGV) when the function is + // actually called. Probe it here and disable if broken. + if (device->buffer_device_address) { + PFN_vkGetBufferDeviceAddress pfn = (PFN_vkGetBufferDeviceAddress) + vkGetDeviceProcAddr(device->device, "vkGetBufferDeviceAddress"); + if (pfn == nullptr) { + GGML_LOG_WARN("ggml_vulkan: vkGetBufferDeviceAddress proc addr is null, disabling BDA\n"); + device->buffer_device_address = false; + } else { + // Create a tiny test buffer and verify the call returns non-zero + VkBufferCreateInfo test_bci = {}; + test_bci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + test_bci.size = 256; + test_bci.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + VkBuffer test_buf = VK_NULL_HANDLE; + if (vkCreateBuffer(device->device, &test_bci, nullptr, &test_buf) == VK_SUCCESS) { + VkMemoryRequirements test_req; + vkGetBufferMemoryRequirements(device->device, test_buf, &test_req); + VkPhysicalDeviceMemoryProperties test_mem_props; + vkGetPhysicalDeviceMemoryProperties(device->physical_device, &test_mem_props); + uint32_t test_mtype = UINT32_MAX; + for (uint32_t j = 0; j < test_mem_props.memoryTypeCount; j++) { + if (test_req.memoryTypeBits & (1u << j)) { test_mtype = j; break; } + } + if (test_mtype != UINT32_MAX) { + VkMemoryAllocateFlagsInfo test_flags = {}; + test_flags.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + test_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT; + VkMemoryAllocateInfo test_alloc = {}; + test_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + test_alloc.pNext = &test_flags; + test_alloc.allocationSize = test_req.size; + test_alloc.memoryTypeIndex = test_mtype; + VkDeviceMemory test_mem = VK_NULL_HANDLE; + if (vkAllocateMemory(device->device, &test_alloc, nullptr, &test_mem) == VK_SUCCESS) { + vkBindBufferMemory(device->device, test_buf, test_mem, 0); + VkBufferDeviceAddressInfo test_addr = {}; + test_addr.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; + test_addr.buffer = test_buf; + VkDeviceAddress addr = pfn(device->device, &test_addr); + if (addr == 0) { + GGML_LOG_WARN("ggml_vulkan: vkGetBufferDeviceAddress returned 0, disabling BDA\n"); + device->buffer_device_address = false; + } + vkFreeMemory(device->device, test_mem, nullptr); + } else { + GGML_LOG_WARN("ggml_vulkan: BDA test alloc failed, disabling BDA\n"); + device->buffer_device_address = false; + } + } + vkDestroyBuffer(device->device, test_buf, nullptr); + } + } + } + // Shaders // Disable matmul tile sizes early if performance low or not supported for (uint32_t i = 0; i < GGML_TYPE_COUNT; ++i) {