{"id":2032,"date":"2025-05-21T13:17:02","date_gmt":"2025-05-21T19:17:02","guid":{"rendered":"https:\/\/embeddedor.com\/blog\/?p=2032"},"modified":"2026-04-14T15:53:11","modified_gmt":"2026-04-14T21:53:11","slug":"fixing-the-_define_flex-helper-in-the-linux-kernel","status":"publish","type":"post","link":"https:\/\/embeddedor.com\/blog\/2025\/05\/21\/fixing-the-_define_flex-helper-in-the-linux-kernel\/","title":{"rendered":"Fixing the _DEFINE_FLEX() helper in the Linux kernel"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"400\" src=\"https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2025\/05\/DALL\u00b7E-2025-05-20-13.27.46-A-visually-engaging-blogpost-header-image-illustrating-a-technical-concept-related-to-Linux-kernel-development.-The-scene-includes-symbolic-representa-700x400.webp\" alt=\"\" class=\"wp-image-2035\" srcset=\"https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2025\/05\/DALL\u00b7E-2025-05-20-13.27.46-A-visually-engaging-blogpost-header-image-illustrating-a-technical-concept-related-to-Linux-kernel-development.-The-scene-includes-symbolic-representa-700x400.webp 700w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2025\/05\/DALL\u00b7E-2025-05-20-13.27.46-A-visually-engaging-blogpost-header-image-illustrating-a-technical-concept-related-to-Linux-kernel-development.-The-scene-includes-symbolic-representa-300x171.webp 300w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2025\/05\/DALL\u00b7E-2025-05-20-13.27.46-A-visually-engaging-blogpost-header-image-illustrating-a-technical-concept-related-to-Linux-kernel-development.-The-scene-includes-symbolic-representa-768x439.webp 768w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2025\/05\/DALL\u00b7E-2025-05-20-13.27.46-A-visually-engaging-blogpost-header-image-illustrating-a-technical-concept-related-to-Linux-kernel-development.-The-scene-includes-symbolic-representa-1536x878.webp 1536w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2025\/05\/DALL\u00b7E-2025-05-20-13.27.46-A-visually-engaging-blogpost-header-image-illustrating-a-technical-concept-related-to-Linux-kernel-development.-The-scene-includes-symbolic-representa-800x457.webp 800w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2025\/05\/DALL\u00b7E-2025-05-20-13.27.46-A-visually-engaging-blogpost-header-image-illustrating-a-technical-concept-related-to-Linux-kernel-development.-The-scene-includes-symbolic-representa.webp 1792w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>A couple of months ago, I submitted a patch to address a dozen <a href=\"https:\/\/embeddedor.com\/blog\/presentations\/#Enhancing_spatial_safety_Fixing_thousands_of_-Wflex-array-member-not-at-end_warnings_LPCEU\" target=\"_blank\" rel=\"noreferrer noopener\"><code>-Wflex-array-member-not-at-end<\/code> <\/a>warnings in ACPI:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/lore.kernel.org\/linux-hardening\/Z618ILbAR8YAvTkd@kspp\/#r\" target=\"_blank\" rel=\"noreferrer noopener\">UAPI: ndctl \/ acpi: intel: Avoid multiple -Wflex-array-member-not-at-end warnings<\/a><\/li>\n<\/ul>\n\n\n\n<p>Originally, I opted for the <code>__struct_group()<\/code> approach to fix these issues.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"diff\" class=\"EnlighterJSRAW\">diff --git a\/include\/uapi\/linux\/ndctl.h b\/include\/uapi\/linux\/ndctl.h\nindex 73516e263627..34c11644d5d7 100644\n--- a\/include\/uapi\/linux\/ndctl.h\n+++ b\/include\/uapi\/linux\/ndctl.h\n@@ -227,12 +227,15 @@ enum ars_masks {\n  *\/\n \n struct nd_cmd_pkg {\n-\t__u64   nd_family;\t\t\/* family of commands *\/\n-\t__u64   nd_command;\n-\t__u32   nd_size_in;\t\t\/* INPUT: size of input args *\/\n-\t__u32   nd_size_out;\t\t\/* INPUT: size of payload *\/\n-\t__u32   nd_reserved2&#91;9];\t\/* reserved must be zero *\/\n-\t__u32   nd_fw_size;\t\t\/* OUTPUT: size fw wants to return *\/\n+\t\/* New members MUST be added within the __struct_group() macro below. *\/\n+\t__struct_group(nd_cmd_pkg_hdr, __hdr, \/* no attrs *\/,\n+\t\t__u64   nd_family;\t\t\/* family of commands *\/\n+\t\t__u64   nd_command;\n+\t\t__u32   nd_size_in;\t\t\/* INPUT: size of input args *\/\n+\t\t__u32   nd_size_out;\t\t\/* INPUT: size of payload *\/\n+\t\t__u32   nd_reserved2&#91;9];\t\/* reserved must be zero *\/\n+\t\t__u32   nd_fw_size;\t\t\/* OUTPUT: size fw wants to return *\/\n+\t);\n \tunsigned char nd_payload&#91;];\t\/* Contents of call      *\/\n };<\/code><\/code><\/pre>\n\n\n\n<p>The idea behind this approach is to _separate_ the <code>flexible-array member<\/code> from the rest of the members in the flexible structure, while at the same time a new type for the &#8220;header part&#8221; of the flexible structure is created. We then proceed to use the newly created type to replace the type of the objects causing trouble &#8211;the ones causing the <code>-Wflex-array-member-not-at-end<\/code> warnings&#8211; in the composite structures.<\/p>\n\n\n\n<p>However, the approach briefly described above is usually better suited for fixing instances of structures with a <code>flexible-array member<\/code> in the middle that are intended to live on the <code>heap<\/code> &#8211;I&#8217;ll go into more detail about this approach in a future post.<\/p>\n\n\n\n<p>So, after some time, I realized that using the <code>DEFINE_RAW_FLEX()<\/code> helper was probably a better approach in this particular case, since basically all the instances triggering the <code>-Wflex-array-member-not-at-end<\/code> warnings were <code>on-stack<\/code> objects.<\/p>\n\n\n\n<p>The <code>DEFINE_FLEX()<\/code> and <code>DEFINE_RAW_FLEX()<\/code> macros were specifically designed to define automatic (on-stack) objects of a <code>flexible structure<\/code> type, where the size of the <code>flexible-array member<\/code> is known at compile time.<\/p>\n\n\n\n<p>So, I submitted a new version of the patch above, this time using <code>DEFINE_RAW_FLEX()<\/code>, and without any changes in the <code>UAPI<\/code> header because we didn&#8217;t need to change <code><code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">struct d_cmd_pkg<\/code><\/code> anymore:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"diff\" class=\"EnlighterJSRAW\">\ndiff --git a\/drivers\/acpi\/nfit\/intel.c b\/drivers\/acpi\/nfit\/intel.c\nindex 3902759abcba..114d5b3bb39b 100644\n--- a\/drivers\/acpi\/nfit\/intel.c\n+++ b\/drivers\/acpi\/nfit\/intel.c\n@@ -55,21 +55,17 @@ static unsigned long intel_security_flags(struct nvdimm *nvdimm,\n {\n \tstruct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);\n \tunsigned long security_flags = 0;\n-\tstruct {\n-\t\tstruct nd_cmd_pkg pkg;\n-\t\tstruct nd_intel_get_security_state cmd;\n-\t} nd_cmd = {\n-\t\t.pkg = {\n-\t\t\t.nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,\n-\t\t\t.nd_family = NVDIMM_FAMILY_INTEL,\n-\t\t\t.nd_size_out =\n-\t\t\t\tsizeof(struct nd_intel_get_security_state),\n-\t\t\t.nd_fw_size =\n-\t\t\t\tsizeof(struct nd_intel_get_security_state),\n-\t\t},\n-\t};\n+\tDEFINE_RAW_FLEX(struct nd_cmd_pkg, nd_cmd, nd_payload,\n+\t\t\tsizeof(struct nd_intel_get_security_state));\n+\tstruct nd_intel_get_security_state *cmd =\n+\t\t\t(struct nd_intel_get_security_state *)nd_cmd-&gt;nd_payload;\n \tint rc;\n \n+\tnd_cmd-&gt;nd_command = NVDIMM_INTEL_GET_SECURITY_STATE;\n+\tnd_cmd-&gt;nd_family = NVDIMM_FAMILY_INTEL;\n+\tnd_cmd-&gt;nd_size_out = sizeof(struct nd_intel_get_security_state);\n+\tnd_cmd-&gt;nd_fw_size = sizeof(struct nd_intel_get_security_state);\n+\n \tif (!test_bit(NVDIMM_INTEL_GET_SECURITY_STATE, &amp;nfit_mem-&gt;dsm_mask))\n \t\treturn 0;<\/code><\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/lore.kernel.org\/linux-hardening\/Z-QpUcxFCRByYcTA@kspp\/\" target=\"_blank\" rel=\"noreferrer noopener\">acpi: nfit: intel: Avoid multiple -Wflex-array-member-not-at-end warnings<\/a><\/li>\n<\/ul>\n\n\n\n<p>To what Dan Williams replied:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Can this keep the C99 init-style with something like (untested):\n\n<code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">_DEFINE_FLEX(struct nd_cmd_pkg, nd_cmd, nd_payload,\n             sizeof(struct nd_intel_get_security_state), {\n\t\t.pkg = {\n\t\t        .nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,\n\t\t        .nd_family = NVDIMM_FAMILY_INTEL,\n\t\t        .nd_size_out =\n\t\t                sizeof(struct nd_intel_get_security_state),\n\t\t        .nd_fw_size =\n\t\t                sizeof(struct nd_intel_get_security_state),\n\t\t},\n\t});<\/code>\n\t\n\n?<\/code><\/pre>\n\n\n\n<p>At the moment, the short answer was: no &#8211;the helper was not able to do that &#8220;cleanly.&#8221;<\/p>\n\n\n\n<p>However, Dan&#8217;s question along with another issue I was recently trying to address, led me to take another look at the internals of <code><a href=\"https:\/\/elixir.bootlin.com\/linux\/v6.15-rc4\/source\/include\/linux\/overflow.h#L391\">_DEFINE_FLEX()<\/a><\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">391 \/**\n392  * _DEFINE_FLEX() - helper macro for DEFINE_FLEX() family.\n393  * Enables caller macro to pass (different) initializer.\n394  *\n395  * @type: structure type name, including \"struct\" keyword.\n396  * @name: Name for a variable to define.\n397  * @member: Name of the array member.\n398  * @count: Number of elements in the array; must be compile-time const.\n399  * @initializer: initializer expression (could be empty for no init).\n400  *\/\n401 #define _DEFINE_FLEX(type, name, member, count, initializer...)                 \\\n402         _Static_assert(__builtin_constant_p(count),                             \\\n403                        \"onstack flex array members require compile-time...\"); \\\n404         union {                                                                 \\\n405                 u8 bytes&#91;struct_size_t(type, member, count)];                   \\\n406                 type obj;                                                       \\\n407         } name##_u initializer;                                                 \\\n408         type *name = (type *)&amp;name##_u<\/code><\/code><\/pre>\n\n\n\n<p>The &#8220;macro wizardry&#8221; behind this helper allows for the allocation of the total space needed for an instance of a <code>flexible structure<\/code> along with its <code>flexible-array member<\/code> on the stack. As mentioned above, there are situations where the size of the flexible-array member is known at compile time. In these cases, we can rely on the <code>DEFINE_FLEX()<\/code> family of helpers to declare the necessary objects, ensuring that any flexible-array member remains the last member of the composite structure &#8211;not placed in the middle.<\/p>\n\n\n\n<p>Dan noticed that <code>DEFINE_FLEX()<\/code> and <code>DEFINE_RAW_FLEX()<\/code> are just wrappers for <code>_DEFINE_FLEX()<\/code>, and that these wrappers don&#8217;t allow for external static initialization:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">424 #define DEFINE_RAW_FLEX(type, name, member, count)      \\\n425         _DEFINE_FLEX(type, name, member, count, = {})\n\n...\n\n442 #define DEFINE_FLEX(TYPE, NAME, MEMBER, COUNTER, COUNT) \\\n443         _DEFINE_FLEX(TYPE, NAME, MEMBER, COUNT, = { .obj.COUNTER = COUNT, })<\/code><\/code><\/pre>\n\n\n\n<p>However, <code>_DEFINE_FLEX()<\/code> _does_ have the infrastructure to initialize the members of the <code>TYPE<\/code> object created by this helper &#8211;with just a _small_ tweak: the <code>obj<\/code> member created by the helper at line <code>406<\/code> must be exposed to the call site, as shown in <code>DEFINE_FLEX()<\/code> at line <code>443<\/code> above when <code>COUNTER<\/code> is set to <code>COUNT<\/code>.<\/p>\n\n\n\n<p>So I replied the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>The code below works - however, notice that in this case we should\ngo through 'obj', which is an object defined in _DEFINE_FLEX().\n\n<code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">         _DEFINE_FLEX(struct nd_cmd_pkg, nd_cmd, nd_payload,\n                         sizeof(struct nd_intel_get_security_state), = {\n                 .obj = {\n                         .nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,\n                         .nd_family = NVDIMM_FAMILY_INTEL,\n                         .nd_size_out =\n                                 sizeof(struct nd_intel_get_security_state),\n                         .nd_fw_size =\n                                 sizeof(struct nd_intel_get_security_state),\n                 },\n         });<\/code><\/code><\/pre>\n\n\n\n<p>Then, in a subsequent e-mail I commented:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Now, I can modify the helper like this:\n\n<code data-enlighter-language=\"diff\" class=\"EnlighterJSRAW\">diff --git a\/include\/linux\/overflow.h b\/include\/linux\/overflow.h\nindex 69533e703be5..170d3cfe7ecc 100644\n--- a\/include\/linux\/overflow.h\n+++ b\/include\/linux\/overflow.h\n@@ -404,7 +404,7 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)\n         union {                                                                 \\\n                 u8 bytes&#91;struct_size_t(type, member, count)];                   \\\n                 type obj;                                                       \\\n-       } name##_u initializer;                                                 \\\n+       } name##_u = { .obj initializer };                                      \\\n         type *name = (type *)&amp;name##_u\n\n  \/**<\/code>\n\nand then we can use the helper as follows:\n\n<code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">         _DEFINE_FLEX(struct nd_cmd_pkg, nd_cmd, nd_payload,\n                         sizeof(struct nd_intel_get_security_state), = {\n                         .nd_command = NVDIMM_INTEL_GET_SECURITY_STATE,\n                         .nd_family = NVDIMM_FAMILY_INTEL,\n                         .nd_size_out =\n                                 sizeof(struct nd_intel_get_security_state),\n                         .nd_fw_size =\n                                 sizeof(struct nd_intel_get_security_state),\n         });<\/code>\n\nOK, I'll go and update the helper.\n\n-Gustavo<\/code><\/pre>\n\n\n\n<p>And that&#8217;s exactly what I did in the patch below. With that change, the <code>_DEFINE_FLEX()<\/code> helper now works correctly and can statically initialize struct members without exposing any internals. \ud83d\ude42<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"diff\" class=\"EnlighterJSRAW\">diff --git a\/include\/linux\/overflow.h b\/include\/linux\/overflow.h\nindex f33d74dac06f2b..7b7be27ca11318 100644\n--- a\/include\/linux\/overflow.h\n+++ b\/include\/linux\/overflow.h\n@@ -396,7 +396,7 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)\n  * @name: Name for a variable to define.\n  * @member: Name of the array member.\n  * @count: Number of elements in the array; must be compile-time const.\n- * @initializer: initializer expression (could be empty for no init).\n+ * @initializer: Initializer expression (e.g., pass `= { }` at minimum).\n  *\/\n #define _DEFINE_FLEX(type, name, member, count, initializer...)\t\t\t\\\n \t_Static_assert(__builtin_constant_p(count),\t\t\t\t\\\n@@ -404,7 +404,7 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)\n \tunion {\t\t\t\t\t\t\t\t\t\\\n \t\tu8 bytes&#91;struct_size_t(type, member, count)];\t\t\t\\\n \t\ttype obj;\t\t\t\t\t\t\t\\\n-\t} name##_u initializer;\t\t\t\t\t\t\t\\\n+\t} name##_u = { .obj initializer };\t\t\t\t\t\\\n \ttype *name = (type *)&amp;name##_u\n \n \/**\n@@ -444,7 +444,7 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)\n  * elements in array @member.\n  *\/\n #define DEFINE_FLEX(TYPE, NAME, MEMBER, COUNTER, COUNT)\t\\\n-\t_DEFINE_FLEX(TYPE, NAME, MEMBER, COUNT, = { .obj.COUNTER = COUNT, })\n+\t_DEFINE_FLEX(TYPE, NAME, MEMBER, COUNT, = { .COUNTER = COUNT, })<\/code><\/code><\/pre>\n\n\n\n<p>Also, as seen in the patch above, I also fixed the <code>DEFINE_FLEX()<\/code> wrapper. <\/p>\n\n\n\n<p>So, here is a short example of how to use this helper to statically initialize members in a structure &#8211;let&#8217;s assume <code>FIXED_SIZE == 1<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">struct flex {\n        int a;\n        int b;\n        struct foo flex_array&#91;];\n};\n\n_DEFINE_FLEX(struct flex, instance, flex_array, \n             FIXED_SIZE, = {\n                .a = 0, \n                .b = 1,\n             });<\/code><\/code><\/pre>\n\n\n\n<p>In case you don&#8217;t need to initialize any members to specific values, just pass <code>= {}<\/code> as argument, or probably you should just use <code>DEFINE_RAW_FLEX()<\/code> or <code>DEFINE_FLEX()<\/code> instead.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">_DEFINE_FLEX(struct flex, instance, flex_array, FIXED_SIZE, = {});<\/code><\/code><\/pre>\n\n\n\n<p>For more details, take a look at the patch already in <a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/next\/linux-next.git\/\" target=\"_blank\" rel=\"noreferrer noopener\">linux-next<\/a>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/next\/linux-next.git\/commit\/?id=47e36ed7840661a9f7fb53554a1b04a5f8daffea\" target=\"_blank\" rel=\"noreferrer noopener\">overflow: Fix direct struct member initialization in _DEFINE_FLEX()<\/a><\/li>\n<\/ul>\n\n\n\n<p>Thanks! &#x2694;&#xfe0f;&#x1f6e1;&#xfe0f;&#x1f427;<\/p>\n\n\n\n<p>My next post will be titled &#8220;(ab)using DEFINE_FLEX() &amp; DEFINE_RAW_FLEX().&#8221; Stay tune!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A couple of months ago, I submitted a patch to address a dozen -Wflex-array-member-not-at-end warnings in ACPI: Originally, I opted for the __struct_group() approach to fix these issues. The idea behind this approach is to _separate_ the flexible-array member from the rest of the members in the flexible structure, while at the same time a&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[31,13,9,22],"tags":[],"class_list":["post-2032","post","type-post","status-publish","format-standard","hentry","category-wfamnae","category-kernel-self-protection-project","category-linux-kernel-hardening","category-mentoring"],"_links":{"self":[{"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/posts\/2032","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/comments?post=2032"}],"version-history":[{"count":28,"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/posts\/2032\/revisions"}],"predecessor-version":[{"id":2063,"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/posts\/2032\/revisions\/2063"}],"wp:attachment":[{"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/media?parent=2032"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/categories?post=2032"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/tags?post=2032"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}