Show a patch.

GET /api/patches/27494/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 27494,
    "url": "https://patchwork.libcamera.org/api/patches/27494/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/27494/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20260723174644.6580-2-magdum.foss@gmail.com>",
    "date": "2026-07-23T17:46:43",
    "name": "[1/2] libcamera: Serialize local control names in IPA format v3",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "a37d778779b100564af2cc4b2589711690f429fc",
    "submitter": {
        "id": 453,
        "url": "https://patchwork.libcamera.org/api/people/453/?format=api",
        "name": "Magdum",
        "email": "magdum.foss@gmail.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/27494/mbox/",
    "series": [
        {
            "id": 6076,
            "url": "https://patchwork.libcamera.org/api/series/6076/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=6076",
            "date": "2026-07-23T17:46:42",
            "name": "libcamera: Control name serialization v3 and input validation hardening",
            "version": 1,
            "mbox": "https://patchwork.libcamera.org/series/6076/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/27494/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/27494/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 54021BDE17\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 23 Jul 2026 17:46:55 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 0674F67EDD;\n\tThu, 23 Jul 2026 19:46:55 +0200 (CEST)",
            "from mail-wm1-x32f.google.com (mail-wm1-x32f.google.com\n\t[IPv6:2a00:1450:4864:20::32f])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 747C667EC4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 23 Jul 2026 19:46:53 +0200 (CEST)",
            "by mail-wm1-x32f.google.com with SMTP id\n\t5b1f17b1804b1-4954dff6536so7687925e9.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 23 Jul 2026 10:46:53 -0700 (PDT)",
            "from magdum-System-Product-Name.vodafone.ultrahub\n\t([2a02:810d:4b14:4600:72e8:99a4:5b87:2e43])\n\tby smtp.gmail.com with ESMTPSA id\n\tffacd0b85a97d-47f85c67339sm18199270f8f.31.2026.07.23.10.46.51\n\t(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n\tThu, 23 Jul 2026 10:46:52 -0700 (PDT)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"O1O+tzdD\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=gmail.com; s=20251104; t=1784828813; x=1785433613;\n\tdarn=lists.libcamera.org; \n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:from:to:cc:subject:date\n\t:message-id:reply-to:content-type;\n\tbh=j4D5mNG5s332TGUbFpj1QOe0ssQFlCkxx51z8IEuXdQ=;\n\tb=O1O+tzdDyprFtq5mWetLFm2JhScWzL6Uve64ZLAjTSwi7ocNkT0guvNeH+XcNe0+8r\n\tQ89yf68WT7TDGSCVWBsR7jsAKPWu42vubiocwQmM9DZMZGPBo2siLEyXOs94nGp+7/Oc\n\tc/haeIhJEk4uKvniFEugF+A1LTrmtLCXXkxMzelONN/UbeHL+Rvv3n28YYI6pl7d4mq5\n\t9G3Quj2Zx14L0lsvQhxNwAKik5XrHToytXvNgKmx+uboSs4dPiSSSl8hAYtqWrbwOWwL\n\tlZz3U8z7b/J96vbXlKKIj23UI/uAusToIDgtudgAfUBzLbFL4Upzbf2JzX0RLZAyP8dg\n\tnwQQ==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1784828813; x=1785433613;\n\th=content-transfer-encoding:mime-version:references:in-reply-to\n\t:message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n\t:to:cc:subject:date:message-id:reply-to:content-type;\n\tbh=j4D5mNG5s332TGUbFpj1QOe0ssQFlCkxx51z8IEuXdQ=;\n\tb=mf36EOB3/jLqz2XgVbvduapfEQmPdXnqJOyaI8kXPg8tsH/LDRITpQv7hLAQ5cwB3q\n\tUg8uKJAZw5qCyzQzkG5BbZjb34at0Rv5felCZUn0vBzKGB7ULXHNP52jIV8S+oXLVsfk\n\tvmWxo5j69cVogaXQLb+5WkLg8ztbFASQf3iqFOUPShXlyAVaZCqUFZgscljeyx3uofxJ\n\tshca08YnbbaD+TnkwKvAtzBxdEFaWmFXZPQ2C2mRu47mcc53aNKoCuY5DctQQU2zUloS\n\t+paLZq/pvv40W//eqhMAXMuvr7UHyCVCyIzfpMLJyks2dHwv4AHqJUXxe09VAOPqu7Nk\n\twSag==",
        "X-Gm-Message-State": "AOJu0YwdVB9Lw07kXqglfzFSHoDU7wLfz0UKDTV41V/A1wcby0tf4X4F\n\tbLsIXnSHJSB536PDQHQKnGj5MV4EW/pY26Ai6aYDRTRBimeJ6Ja+ePD5eQNh/YhAHic=",
        "X-Gm-Gg": "AR+sD13SQL7qrGwDrEI6cZuDLc4q3UhLUDFvfTOcWNc2xpgO9TGxkifQnY+KjiR6mwN\n\twW7TBUdR5ZWEyYFxF83NrxNMaLmc6EO0b/IwJjeOJczFKGj/AQh6IPKSEm1tNHI0ypC9tQ9KFOe\n\tHRm6frgsdrkENUmI4sVzH3sWPNUBw1jNlBR3DhfPlFNCTTPqSjUVehavJNj0yys5WJgnmUInv8U\n\tNHVPZk4ILoJ8ZE/56P04sIlUi8awTiR2xduJtUftPq1sk+jsMZZ8Ovj2+2wfiWA6dYKu0GZU1Y0\n\te5CWYAyw7wyovR547ZiYZM1oPB/adh2T0QyFJT7zqtwlxV0tWCnxUjZu15VNyc1dlRuJ5VNd4tn\n\tOv/q0LDHh+lcmpq1O3tUxEDB7Z9M6jg1bnKOejCE3G9/pinJtsBnYYIjAQT2QRktEIVUtiJ7k6t\n\tdFXkYt0hgYFxUr3oeOEGLdZVA37SsL47WwBKdyrg==",
        "X-Received": "by 2002:a7b:cd14:0:b0:493:bb0:3b43 with SMTP id\n\t5b1f17b1804b1-49573cbfb7fmr32446045e9.2.1784828812765; \n\tThu, 23 Jul 2026 10:46:52 -0700 (PDT)",
        "From": "Magdum <magdum.foss@gmail.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Magdum <magdum.foss@gmail.com>",
        "Subject": "[PATCH 1/2] libcamera: Serialize local control names in IPA format\n\tv3",
        "Date": "Thu, 23 Jul 2026 19:46:43 +0200",
        "Message-ID": "<20260723174644.6580-2-magdum.foss@gmail.com>",
        "X-Mailer": "git-send-email 2.43.0",
        "In-Reply-To": "<20260723174644.6580-1-magdum.foss@gmail.com>",
        "References": "<20260723174644.6580-1-magdum.foss@gmail.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "Bump IPA controls serialization format to v3 and add name_len to\nControlInfoMap entries.\n\nSerialize null-terminated control names for local (V4L2-style) id\nmaps to preserve names across IPC.\n\nExtend serializer tests with V4L2-like name round-trip coverage and\nmalformed payload rejection for oversized length, missing terminator,\nand too-long serialize input.\n\nSigned-off-by: Magdum <magdum.foss@gmail.com>\n---\n include/libcamera/ipa/ipa_controls.h         |   6 +-\n src/libcamera/control_serializer.cpp         | 133 +++++++++++++------\n test/serialization/control_serialization.cpp | 109 +++++++++++++++\n 3 files changed, 207 insertions(+), 41 deletions(-)",
    "diff": "diff --git a/include/libcamera/ipa/ipa_controls.h b/include/libcamera/ipa/ipa_controls.h\nindex 6af962ff..7a7873d9 100644\n--- a/include/libcamera/ipa/ipa_controls.h\n+++ b/include/libcamera/ipa/ipa_controls.h\n@@ -15,7 +15,7 @@ namespace libcamera {\n extern \"C\" {\n #endif\n \n-#define IPA_CONTROLS_FORMAT_VERSION\t2\n+#define IPA_CONTROLS_FORMAT_VERSION 3\n \n enum ipa_controls_id_map_type {\n \tIPA_CONTROL_ID_MAP_CONTROLS,\n@@ -50,7 +50,9 @@ struct ipa_control_info_entry {\n \tuint32_t id;\n \tuint32_t type;\n \tuint8_t direction;\n-\tuint8_t padding[7];\n+\tuint8_t padding[3];\n+\t/* Length of the control name without the terminating null byte. */\n+\tuint32_t name_len;\n \tstruct ipa_control_value_entry min;\n \tstruct ipa_control_value_entry max;\n \tstruct ipa_control_value_entry def;\ndiff --git a/src/libcamera/control_serializer.cpp b/src/libcamera/control_serializer.cpp\nindex c0285cc6..b3c44ed0 100644\n--- a/src/libcamera/control_serializer.cpp\n+++ b/src/libcamera/control_serializer.cpp\n@@ -31,6 +31,27 @@ namespace libcamera {\n \n LOG_DEFINE_CATEGORY(Serializer)\n \n+namespace {\n+\n+constexpr uint32_t kMaxControlNameLength = 1024;\n+\n+enum ipa_controls_id_map_type idMapTypeFor(const ControlIdMap &idmap)\n+{\n+\tif (&idmap == &controls::controls)\n+\t\treturn IPA_CONTROL_ID_MAP_CONTROLS;\n+\tif (&idmap == &properties::properties)\n+\t\treturn IPA_CONTROL_ID_MAP_PROPERTIES;\n+\n+\treturn IPA_CONTROL_ID_MAP_V4L2;\n+}\n+\n+bool idMapRequiresLocalIds(enum ipa_controls_id_map_type idMapType)\n+{\n+\treturn idMapType == IPA_CONTROL_ID_MAP_V4L2;\n+}\n+\n+} /* namespace */\n+\n /**\n  * \\class ControlSerializer\n  * \\brief Serializer and deserializer for control-related classes\n@@ -165,10 +186,16 @@ size_t ControlSerializer::binarySize(const ControlInfoMap &infoMap)\n {\n \tsize_t size = sizeof(struct ipa_controls_header)\n \t\t    + infoMap.size() * sizeof(struct ipa_control_info_entry);\n+\tenum ipa_controls_id_map_type idMapType = idMapTypeFor(infoMap.idmap());\n \n-\tfor (const auto &ctrl : infoMap)\n+\tfor (const auto &ctrl : infoMap) {\n \t\tsize += binarySize(ctrl.second);\n \n+\t\tsize += idMapRequiresLocalIds(idMapType)\n+\t\t\t\t? ctrl.first->name().size() + 1\n+\t\t\t\t: 1;\n+\t}\n+\n \treturn size;\n }\n \n@@ -183,8 +210,7 @@ size_t ControlSerializer::binarySize(const ControlInfoMap &infoMap)\n  */\n size_t ControlSerializer::binarySize(const ControlList &list)\n {\n-\tsize_t size = sizeof(struct ipa_controls_header)\n-\t\t    + list.size() * sizeof(struct ipa_control_list_entry);\n+\tsize_t size = sizeof(struct ipa_controls_header) + list.size() * sizeof(struct ipa_control_list_entry);\n \n \tfor (const auto &ctrl : list)\n \t\tsize += binarySize(ctrl.second);\n@@ -231,24 +257,21 @@ int ControlSerializer::serialize(const ControlInfoMap &infoMap,\n \t\treturn 0;\n \t}\n \n+\tenum ipa_controls_id_map_type idMapType = idMapTypeFor(infoMap.idmap());\n+\n \t/* Compute entries and data required sizes. */\n \tsize_t entriesSize = infoMap.size()\n \t\t\t   * sizeof(struct ipa_control_info_entry);\n \tsize_t valuesSize = 0;\n-\tfor (const auto &ctrl : infoMap)\n+\tfor (const auto &ctrl : infoMap) {\n \t\tvaluesSize += binarySize(ctrl.second);\n-\n-\tconst ControlIdMap *idmap = &infoMap.idmap();\n-\tenum ipa_controls_id_map_type idMapType;\n-\tif (idmap == &controls::controls)\n-\t\tidMapType = IPA_CONTROL_ID_MAP_CONTROLS;\n-\telse if (idmap == &properties::properties)\n-\t\tidMapType = IPA_CONTROL_ID_MAP_PROPERTIES;\n-\telse\n-\t\tidMapType = IPA_CONTROL_ID_MAP_V4L2;\n+\t\tvaluesSize += idMapRequiresLocalIds(idMapType)\n+\t\t\t\t      ? ctrl.first->name().size() + 1\n+\t\t\t\t      : 1;\n+\t}\n \n \t/* Prepare the packet header. */\n-\tstruct ipa_controls_header hdr;\n+\tstruct ipa_controls_header hdr = {};\n \thdr.version = IPA_CONTROLS_FORMAT_VERSION;\n \thdr.handle = serial_;\n \thdr.entries = infoMap.size();\n@@ -267,21 +290,29 @@ int ControlSerializer::serialize(const ControlInfoMap &infoMap,\n \t */\n \tserial_ += 2;\n \n-\t/*\n-\t * Serialize all entries.\n-\t * \\todo Serialize the control name too\n-\t */\n+\t/* Serialize all entries. */\n \tByteStreamBuffer entries = buffer.carveOut(entriesSize);\n \tByteStreamBuffer values = buffer.carveOut(valuesSize);\n+\tstatic const std::string emptyName;\n \n \tfor (const auto &ctrl : infoMap) {\n \t\tconst ControlId *id = ctrl.first;\n \t\tconst ControlInfo &info = ctrl.second;\n+\t\tconst std::string &name = idMapRequiresLocalIds(idMapType)\n+\t\t\t\t\t\t  ? id->name()\n+\t\t\t\t\t\t  : emptyName;\n+\n+\t\tif (name.size() > kMaxControlNameLength) {\n+\t\t\tLOG(Serializer, Error)\n+\t\t\t\t<< \"Control name too long: \" << name.size();\n+\t\t\treturn -EINVAL;\n+\t\t}\n \n-\t\tstruct ipa_control_info_entry entry;\n+\t\tstruct ipa_control_info_entry entry = {};\n \t\tentry.id = id->id();\n \t\tentry.type = id->type();\n \t\tentry.direction = static_cast<ControlId::DirectionFlags::Type>(id->direction());\n+\t\tentry.name_len = static_cast<uint32_t>(name.size());\n \n \t\tpopulateControlValueEntry(entry.min, info.min(), values.offset());\n \t\tstore(info.min(), values);\n@@ -292,6 +323,10 @@ int ControlSerializer::serialize(const ControlInfoMap &infoMap,\n \t\tpopulateControlValueEntry(entry.def, info.def(), values.offset());\n \t\tstore(info.def(), values);\n \n+\t\tvalues.write(Span<const uint8_t>(\n+\t\t\treinterpret_cast<const uint8_t *>(name.c_str()),\n+\t\t\tname.size() + 1));\n+\n \t\tentries.write(&entry);\n \t}\n \n@@ -355,7 +390,7 @@ int ControlSerializer::serialize(const ControlList &list,\n \t\tvaluesSize += binarySize(ctrl.second);\n \n \t/* Prepare the packet header. */\n-\tstruct ipa_controls_header hdr;\n+\tstruct ipa_controls_header hdr = {};\n \thdr.version = IPA_CONTROLS_FORMAT_VERSION;\n \thdr.handle = infoMapHandle;\n \thdr.entries = list.size();\n@@ -485,25 +520,6 @@ ControlInfoMap ControlSerializer::deserialize<ControlInfoMap>(ByteStreamBuffer &\n \n \t\tControlType type = static_cast<ControlType>(entry->type);\n \n-\t\t/* If we're using a local id map, populate it. */\n-\t\tif (localIdMap) {\n-\t\t\tControlId::DirectionFlags flags{\n-\t\t\t\tstatic_cast<ControlId::Direction>(entry->direction)\n-\t\t\t};\n-\n-\t\t\t/**\n-\t\t\t * \\todo Find a way to preserve the control name for\n-\t\t\t * debugging purpose.\n-\t\t\t */\n-\t\t\tcontrolIds_.emplace_back(std::make_unique<ControlId>(entry->id,\n-\t\t\t\t\t\t\t\t\t     \"\", \"local\", type,\n-\t\t\t\t\t\t\t\t\t     flags));\n-\t\t\t(*localIdMap)[entry->id] = controlIds_.back().get();\n-\t\t}\n-\n-\t\tconst ControlId *controlId = idMap->at(entry->id);\n-\t\tASSERT(controlId);\n-\n \t\tconst ipa_control_value_entry &min_entry = entry->min;\n \t\tconst ipa_control_value_entry &max_entry = entry->max;\n \t\tconst ipa_control_value_entry &def_entry = entry->def;\n@@ -538,6 +554,45 @@ ControlInfoMap ControlSerializer::deserialize<ControlInfoMap>(ByteStreamBuffer &\n \t\t\tloadControlValue(values, static_cast<ControlType>(def_entry.type),\n \t\t\t\t\t def_entry.is_array, def_entry.count);\n \n+\t\t/*\n+\t\t * Deserialize the null-terminated control name from the values\n+\t\t * section. Reject unreasonably long names to guard against\n+\t\t * malformed packets.\n+\t\t */\n+\t\tif (entry->name_len > kMaxControlNameLength) {\n+\t\t\tLOG(Serializer, Error)\n+\t\t\t\t<< \"Control name too long: \" << entry->name_len;\n+\t\t\treturn {};\n+\t\t}\n+\n+\t\tconst auto *nameData = values.read<const uint8_t>(entry->name_len + 1);\n+\t\tif (!nameData) {\n+\t\t\tLOG(Serializer, Error) << \"Out of data reading control name\";\n+\t\t\treturn {};\n+\t\t}\n+\n+\t\tif (nameData[entry->name_len] != '\\0') {\n+\t\t\tLOG(Serializer, Error) << \"Control name is not null-terminated\";\n+\t\t\treturn {};\n+\t\t}\n+\n+\t\t/* If we're using a local id map, populate it with the restored name. */\n+\t\tif (localIdMap) {\n+\t\t\tstd::string ctrlName(reinterpret_cast<const char *>(nameData),\n+\t\t\t\t\t     entry->name_len);\n+\n+\t\t\tControlId::DirectionFlags flags{\n+\t\t\t\tstatic_cast<ControlId::Direction>(entry->direction)\n+\t\t\t};\n+\n+\t\t\tcontrolIds_.emplace_back(std::make_unique<ControlId>(entry->id,\n+\t\t\t\t\t\t\t\t\t     ctrlName, \"local\",\n+\t\t\t\t\t\t\t\t\t     type, flags));\n+\t\t\t(*localIdMap)[entry->id] = controlIds_.back().get();\n+\t\t}\n+\n+\t\tconst ControlId *controlId = idMap->at(entry->id);\n+\t\tASSERT(controlId);\n \n \t\t/* Create and store the ControlInfo. */\n \t\tctrls.emplace(controlId, ControlInfo(min, max, def));\ndiff --git a/test/serialization/control_serialization.cpp b/test/serialization/control_serialization.cpp\nindex 06c572b7..b1638db9 100644\n--- a/test/serialization/control_serialization.cpp\n+++ b/test/serialization/control_serialization.cpp\n@@ -11,6 +11,8 @@\n #include <libcamera/control_ids.h>\n #include <libcamera/controls.h>\n \n+#include <libcamera/ipa/ipa_controls.h>\n+\n #include \"libcamera/internal/byte_stream_buffer.h\"\n #include \"libcamera/internal/control_serializer.h\"\n \n@@ -169,6 +171,113 @@ protected:\n \t\t\treturn TestFail;\n \t\t}\n \n+\t\t/* Build a local (V4L2-like) ControlInfoMap and verify name round-trip. */\n+\t\tvector<unique_ptr<ControlId>> v4l2ControlIds;\n+\t\tControlIdMap v4l2IdMap;\n+\t\tconstexpr uint32_t kV4L2TestControlId = 0x009a2001;\n+\t\tconst string kV4L2ControlName = \"V4L2_CID_TEST_GAIN\";\n+\n+\t\tv4l2ControlIds.emplace_back(std::make_unique<ControlId>(\n+\t\t\tkV4L2TestControlId, kV4L2ControlName, \"v4l2\",\n+\t\t\tControlTypeInteger32, ControlId::Direction::In));\n+\t\tv4l2IdMap.emplace(kV4L2TestControlId, v4l2ControlIds.back().get());\n+\n+\t\tControlInfoMap::Map v4l2Info;\n+\t\tv4l2Info.emplace(v4l2ControlIds.back().get(),\n+\t\t\t\t ControlInfo(ControlValue(int32_t{ 0 }),\n+\t\t\t\t\t     ControlValue(int32_t{ 255 }),\n+\t\t\t\t\t     ControlValue(int32_t{ 16 })));\n+\t\tControlInfoMap v4l2InfoMap(std::move(v4l2Info), v4l2IdMap);\n+\n+\t\tControlSerializer v4l2Serializer(ControlSerializer::Role::Proxy);\n+\t\tControlSerializer v4l2Deserializer(ControlSerializer::Role::Worker);\n+\n+\t\tsize = v4l2Serializer.binarySize(v4l2InfoMap);\n+\t\tinfoData.resize(size);\n+\t\tbuffer = ByteStreamBuffer(infoData.data(), infoData.size());\n+\n+\t\tret = v4l2Serializer.serialize(v4l2InfoMap, buffer);\n+\t\tif (ret < 0 || buffer.overflow()) {\n+\t\t\tcerr << \"Failed to serialize V4L2-like ControlInfoMap\" << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n+\t\tbuffer = ByteStreamBuffer(const_cast<const uint8_t *>(infoData.data()),\n+\t\t\t\t\t  infoData.size());\n+\t\tControlInfoMap v4l2InfoMapDes =\n+\t\t\tv4l2Deserializer.deserialize<ControlInfoMap>(buffer);\n+\t\tif (v4l2InfoMapDes.empty()) {\n+\t\t\tcerr << \"Failed to deserialize V4L2-like ControlInfoMap\" << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n+\t\tauto idIt = v4l2InfoMapDes.idmap().find(kV4L2TestControlId);\n+\t\tif (idIt == v4l2InfoMapDes.idmap().end()) {\n+\t\t\tcerr << \"Deserialized V4L2-like id map misses test control\" << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n+\t\tif (idIt->second->name() != kV4L2ControlName) {\n+\t\t\tcerr << \"Deserialized V4L2-like control name doesn't match\" << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n+\t\t/* Reject malformed packets with over-sized names. */\n+\t\tvector<uint8_t> badNameLenData = infoData;\n+\t\tauto *badNameLenHeader =\n+\t\t\treinterpret_cast<ipa_controls_header *>(badNameLenData.data());\n+\t\tauto *badNameLenEntry = reinterpret_cast<ipa_control_info_entry *>(\n+\t\t\tbadNameLenData.data() + sizeof(*badNameLenHeader));\n+\t\tbadNameLenEntry->name_len = 2048;\n+\n+\t\tControlSerializer badNameLenDeserializer(ControlSerializer::Role::Worker);\n+\t\tbuffer = ByteStreamBuffer(const_cast<const uint8_t *>(badNameLenData.data()),\n+\t\t\t\t\t  badNameLenData.size());\n+\t\tif (!badNameLenDeserializer.deserialize<ControlInfoMap>(buffer).empty()) {\n+\t\t\tcerr << \"Oversized control name should be rejected\" << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n+\t\t/* Reject malformed packets with non-null-terminated names. */\n+\t\tvector<uint8_t> badTermData = infoData;\n+\t\tbadTermData.back() = 'X';\n+\n+\t\tControlSerializer badTermDeserializer(ControlSerializer::Role::Worker);\n+\t\tbuffer = ByteStreamBuffer(const_cast<const uint8_t *>(badTermData.data()),\n+\t\t\t\t\t  badTermData.size());\n+\t\tif (!badTermDeserializer.deserialize<ControlInfoMap>(buffer).empty()) {\n+\t\t\tcerr << \"Control name without null terminator should be rejected\" << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n+\t\t/* Reject too-long names at serialization time. */\n+\t\tvector<unique_ptr<ControlId>> longNameControlIds;\n+\t\tControlIdMap longNameIdMap;\n+\t\tstring longName(1025, 'n');\n+\n+\t\tlongNameControlIds.emplace_back(std::make_unique<ControlId>(\n+\t\t\t0x009a2002, longName, \"v4l2\", ControlTypeInteger32,\n+\t\t\tControlId::Direction::In));\n+\t\tlongNameIdMap.emplace(0x009a2002, longNameControlIds.back().get());\n+\n+\t\tControlInfoMap::Map longNameInfo;\n+\t\tlongNameInfo.emplace(longNameControlIds.back().get(),\n+\t\t\t\t     ControlInfo(ControlValue(int32_t{ 0 }),\n+\t\t\t\t\t\t ControlValue(int32_t{ 255 }),\n+\t\t\t\t\t\t ControlValue(int32_t{ 16 })));\n+\t\tControlInfoMap longNameInfoMap(std::move(longNameInfo), longNameIdMap);\n+\n+\t\tControlSerializer longNameSerializer(ControlSerializer::Role::Proxy);\n+\t\tsize = longNameSerializer.binarySize(longNameInfoMap);\n+\t\tinfoData.resize(size);\n+\t\tbuffer = ByteStreamBuffer(infoData.data(), infoData.size());\n+\n+\t\tret = longNameSerializer.serialize(longNameInfoMap, buffer);\n+\t\tif (ret != -EINVAL) {\n+\t\t\tcerr << \"Too-long control name should fail serialization\" << endl;\n+\t\t\treturn TestFail;\n+\t\t}\n+\n \t\treturn TestPass;\n \t}\n };\n",
    "prefixes": [
        "1/2"
    ]
}