From 4822d1dc430233f23611a9865bbe11373c29a75b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Thu, 10 Sep 2026 23:27:56 -0400 Subject: [PATCH] pipewire: read a modifier choice at the right offset extract_modifier_choice stepped past SPA_POD_CONTENTS(spa_pod_choice, ..) by another sizeof(spa_pod_choice_body). The macro already skips the pod header and the choice body, so it points at the first value; adding the body size again dropped the first two modifiers and read two entries past the end. What a consumer gets back is then a list of neighbouring pod bytes. Fixating on one of those asks the producer to import the dma-buf with a modifier nobody offered, and vkAllocateMemory fails with VK_ERROR_OUT_OF_DEVICE_MEMORY on every frame because the image that layout implies does not fit the buffer. Use SPA_POD_CHOICE_VALUES and SPA_POD_CHOICE_N_VALUES instead, and ignore a choice whose values are not 8 bytes wide, since a modifier is a Long. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_019QWYTEhFJonuUNTEmBfv7Q --- .../backends/linux/pipewire/format.hpp | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/include/libremidi/backends/linux/pipewire/format.hpp b/include/libremidi/backends/linux/pipewire/format.hpp index 6d11780c..f7190a0b 100644 --- a/include/libremidi/backends/linux/pipewire/format.hpp +++ b/include/libremidi/backends/linux/pipewire/format.hpp @@ -179,21 +179,19 @@ inline bool extract_modifier_choice( if (spa_pod_is_choice(val)) { - const auto* choice = reinterpret_cast(val); - const spa_pod* child = SPA_POD_CHOICE_CHILD(reinterpret_cast(val)); - const std::uint32_t child_size = SPA_POD_BODY_SIZE(child); - const std::uint32_t n_values - = (SPA_POD_BODY_SIZE(val) - sizeof(spa_pod_choice_body)) / child_size; - const std::uint8_t* p = static_cast(SPA_POD_CONTENTS(spa_pod_choice, val)) - + sizeof(spa_pod_choice_body); - for (std::uint32_t i = 0; i < n_values; ++i) + // SPA_POD_CHOICE_VALUES already skips the pod header and the choice body. + const std::uint32_t value_size = SPA_POD_CHOICE_VALUE_SIZE(val); + const std::uint32_t n_values = SPA_POD_CHOICE_N_VALUES(val); + const auto* p = static_cast(SPA_POD_CHOICE_VALUES(val)); + if (value_size == sizeof(std::int64_t)) { - std::int64_t v; - std::memcpy(&v, p, sizeof(v)); - out_choices.push_back(static_cast(v)); - p += child_size; + for (std::uint32_t i = 0; i < n_values; ++i, p += value_size) + { + std::int64_t v; + std::memcpy(&v, p, sizeof(v)); + out_choices.push_back(static_cast(v)); + } } - (void)choice; return true; }