{"id":2636,"date":"2026-04-18T20:39:05","date_gmt":"2026-04-19T02:39:05","guid":{"rendered":"https:\/\/embeddedor.com\/blog\/?p=2636"},"modified":"2026-04-25T16:10:52","modified_gmt":"2026-04-25T22:10:52","slug":"wflex-array-member-not-at-end-and-a-misalignment-bug-in-the-linux-kernel","status":"publish","type":"post","link":"https:\/\/embeddedor.com\/blog\/2026\/04\/18\/wflex-array-member-not-at-end-and-a-misalignment-bug-in-the-linux-kernel\/","title":{"rendered":"-Wflex-array-member-not-at-end and a misalignment bug in the Linux kernel"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"467\" src=\"https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/ChatGPT-Image-Apr-18-2026-02_50_27-PM-700x467.png\" alt=\"\" class=\"wp-image-2983\" style=\"width:700px;height:auto\" srcset=\"https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/ChatGPT-Image-Apr-18-2026-02_50_27-PM-700x467.png 700w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/ChatGPT-Image-Apr-18-2026-02_50_27-PM-300x200.png 300w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/ChatGPT-Image-Apr-18-2026-02_50_27-PM-768x512.png 768w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/ChatGPT-Image-Apr-18-2026-02_50_27-PM-800x533.png 800w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/ChatGPT-Image-Apr-18-2026-02_50_27-PM.png 1536w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_68 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title \" >Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/embeddedor.com\/blog\/2026\/04\/18\/wflex-array-member-not-at-end-and-a-misalignment-bug-in-the-linux-kernel\/#The_warning\" title=\"The warning\">The warning<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/embeddedor.com\/blog\/2026\/04\/18\/wflex-array-member-not-at-end-and-a-misalignment-bug-in-the-linux-kernel\/#flexible-array_members_and_tail_padding\" title=\"flexible-array members and tail padding\">flexible-array members and tail padding<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/embeddedor.com\/blog\/2026\/04\/18\/wflex-array-member-not-at-end-and-a-misalignment-bug-in-the-linux-kernel\/#The_bug\" title=\"The bug\">The bug<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/embeddedor.com\/blog\/2026\/04\/18\/wflex-array-member-not-at-end-and-a-misalignment-bug-in-the-linux-kernel\/#flexible-array_members_and_implicit_unions\" title=\"flexible-array members and implicit unions\">flexible-array members and implicit unions<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/embeddedor.com\/blog\/2026\/04\/18\/wflex-array-member-not-at-end-and-a-misalignment-bug-in-the-linux-kernel\/#The_bugfix\" title=\"The bugfix\">The bugfix<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/embeddedor.com\/blog\/2026\/04\/18\/wflex-array-member-not-at-end-and-a-misalignment-bug-in-the-linux-kernel\/#Conclusion\" title=\"Conclusion\">Conclusion<\/a><\/li><\/ul><\/nav><\/div>\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"The_warning\"><\/span>The warning<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>During one of my presentations at Open Source Summit Japan<sup data-fn=\"8f534952-d1bb-4c3f-aef8-a02ea6895374\" class=\"fn\"><a href=\"#8f534952-d1bb-4c3f-aef8-a02ea6895374\" id=\"8f534952-d1bb-4c3f-aef8-a02ea6895374-link\">1<\/a><\/sup> &#x1f1ef;&#x1f1f5; the past year, I talked about a bug I found while addressing <code>-Wflex-array-member-not-at-end<\/code> issues in the Linux kernel. The warning reported by the compiler was the following.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>drivers\/net\/virtio_net.c:429:46: warning: structure containing a flexible array member is not at the end of another structure &#91;-Wflex-array-member-not-at-end]<\/code><\/pre>\n\n\n\n<p>See the related code below.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">\n 392 struct virtnet_info {\n  ...\n\n 429   struct virtio_net_rss_config_trailer rss_trailer; \/* &lt;- -Wfamnae warning *\/\n 430   u8 rss_hash_key_data&#91;VIRTIO_NET_RSS_MAX_KEY_SIZE];\n 431 \n  ...\n  \n 496 };<\/code><\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>According to the compiler, <code>struct virtio_net_rss_config_trailer<\/code> at line 429 above is a flexible structure; this is a structure that contains a <code>flexible-array member<\/code> (FAM), and the issue is that the FAM in this structure is not at the end of <code>struct virtnet_info<\/code>.<\/p>\n\n\n\n<p>Let&#8217;s remember that <code>not-at-end<\/code> FAMs are a compiler extension that may cause <code>undefined behavior<\/code>, and compilers do not handle the sizes of objects containing them consistently. For this reason, they are now deprecated:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<pre class=\"wp-block-preformatted\">struct flex  {<br>    int length;<br>    char data[];<br>};<br><br>struct mid_flex {<br>    int m;<br>    struct flex flex_data;<br>    int n;<br>};<\/pre>\n\n\n\n<p>In the above, accessing a member of the array <code>mid_flex.flex_data.data[]<\/code> might have undefined behavior. Compilers do not handle such a case consistently. Any code relying on this case should be modified to ensure that flexible array members only end up at the ends of structures.<sup data-fn=\"11de6685-74ba-4a88-bf1b-aaa1174f31a1\" class=\"fn\"><a href=\"#11de6685-74ba-4a88-bf1b-aaa1174f31a1\" id=\"11de6685-74ba-4a88-bf1b-aaa1174f31a1-link\">2<\/a><\/sup><\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"flexible-array_members_and_tail_padding\"><\/span>flexible-array members and tail padding<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Now, let&#8217;s take a look at the internals of <code>struct virtio_net_rss_config_trailer<\/code> using the Poke a Hole (pahole) tool.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"raw\" class=\"EnlighterJSRAW\">pahole -C virtio_net_rss_config_trailer drivers\/net\/virtio_net.o<\/code>\n<code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">struct virtio_net_rss_config_trailer {\n        __le16                     max_tx_vq;            \/*     0     2 *\/\n        __u8                       hash_key_length;      \/*     2     1 *\/\n        __u8                       hash_key_data&#91;];      \/*     3     0 *\/\n\n        \/* size: 4, cachelines: 1, members: 3 *\/\n        \/* padding: 1 *\/\n        \/* last cacheline: 4 bytes *\/\n};<\/code><\/code><\/pre>\n\n\n\n<p>As we can see above, the FAM <code>hash_key_data[]<\/code> is located at <code>offset 3<\/code> and, of course, its size is <code>0 bytes<\/code>. However, the size of the structure is <code>4 bytes<\/code>, which means that between the end of the struct and the address of the FAM there is <code>1 byte<\/code> of padding. As shown above, this is also displayed by pahole: <code>\/* padding: 1 *\/<\/code>.<\/p>\n\n\n\n<p>This type of padding between the last member and the end of a structure is called <strong>tail padding<\/strong>, and it&#8217;s quite common. However, it can be problematic if people are not familiar with the nuances of <code>flexible-array members<\/code>. This is one of those subtle details developers should be acutely aware of when working with FAMs, in particular.<\/p>\n\n\n\n<p>Based on the work over the past few years making <code>flexible-array members<\/code> safer<sup data-fn=\"c6b105f2-c52b-4f7d-8e0f-1ec9500797f7\" class=\"fn\"><a href=\"#c6b105f2-c52b-4f7d-8e0f-1ec9500797f7\" id=\"c6b105f2-c52b-4f7d-8e0f-1ec9500797f7-link\">3<\/a><\/sup> and addressing <code>-Wflex-array-member-not-at-end<\/code> issues across the whole kernel tree, I&#8217;ve come to notice that it&#8217;s not uncommon for people to assume that the offset of a FAM is always at the very end of the flexible structure. That is, people tend to assume that <code>offsetof(struct flex, fam) == sizeof(struct flex)<\/code> is always true. However, due to <strong>tail padding<\/strong>, this is not always the case and, as we&#8217;re about to see, it should not be taken for granted.<\/p>\n\n\n\n<p>So, what we have here is the following.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">struct virtio_net_rss_config_trailer {\n        __le16                     max_tx_vq;            \/*     0     2 *\/\n        __u8                       hash_key_length;      \/*     2     1 *\/\n        __u8                       hash_key_data&#91;];      \/*     3     0 *\/\n\n        \/* size: 4, cachelines: 1, members: 3 *\/\n        \/* padding: 1 *\/\n        \/* last cacheline: 4 bytes *\/\n};\n\noffsetof(struct virtio_net_rss_config_trailer, hash_key_data) == 3\nsizeof(struct virtio_net_rss_config_trailer) == 4\n\noffsetof(struct virtio_net_rss_config_trailer, hash_key_data) != sizeof(struct virtio_net_rss_config_trailer)<\/code><\/code><\/pre>\n\n\n\n<p><strong>Key takeaway: <code>offsetof(struct flex, fam) != sizeof(struct flex)<\/code> when tail padding is present.<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"The_bug\"><\/span>The bug<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Okay, now let&#8217;s take a closer look at <code>struct virtnet_info<\/code> with the help of pahole. Note how the next member after the flexible structure is a fixed-size array: <code>u8 rss_hash_key_data[40]<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"raw\" class=\"EnlighterJSRAW\">pahole -C virtnet_info drivers\/net\/virtio_net.o<\/code><code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">struct virtnet_info {\n...\n        struct virtio_net_rss_config_trailer rss_trailer; \/*    80     4 *\/\n\n        \/* XXX last struct has 1 byte of padding *\/\n\n        u8                         rss_hash_key_data&#91;40]; \/*    84    40 *\/\n...\n\n};<\/code><\/code><\/pre>\n\n\n\n<p>Aside from the tail padding in <code>struct virtio_net_rss_config_trailer<\/code>, two more things caught my attention here:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>a) The name of the fixed-size array: <code>rss_hash_key_data,<\/code> is suspiciously similar to the FAM&#8217;s name: <code>rss_trailer.hash_key_data[]<\/code>.<\/li>\n\n\n\n<li>b) The type of the fixed-size array is basically the same as the element type of the FAM.<\/li>\n<\/ul>\n\n\n\n<p>These two things tell me that, probably, the original intention here was to <strong>overlap<\/strong> both the FAM and the fixed-size array; what could also be thought of as an <code>implicit union<\/code> between the two arrays.<\/p>\n\n\n\n<p>So we effectively have an implicit union between <code>rss_trailer.hash_key_data[]<\/code> and <code>rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE]<\/code>. However, due to the tail padding in <code>struct virtio_net_rss_config_trailer<\/code> previously described, these arrays do not actually share the same address in memory: <code>hash_key_data<\/code> being at <code>offset 83<\/code>, and <code>rss_hash_key_data<\/code> at <code>offset 84<\/code> in <code>struct virtnet_info<\/code>. See below.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">struct virtio_net_rss_config_trailer {\n        __le16                     max_tx_vq;            \/*     0     2 *\/\n        __u8                       hash_key_length;      \/*     2     1 *\/\n        __u8                       hash_key_data&#91;];      \/*     3     0 *\/\n\n        \/* size: 4, cachelines: 1, members: 3 *\/\n        \/* padding: 1 *\/\n        \/* last cacheline: 4 bytes *\/\n};\n\nstruct virtnet_info {\n...\n        struct virtio_net_rss_config_trailer rss_trailer; \/*    80     4 *\/\n\n        \/* XXX last struct has 1 byte of padding *\/\n\n        u8                         rss_hash_key_data&#91;40]; \/*    84    40 *\/\n...\n\n};\n\noffsetof(struct virtnet_info, rss_trailer.hash_key_data) == 83\noffsetof(struct virtnet_info, rss_hash_key_data) == 84\n<\/code><\/code><\/pre>\n\n\n\n<p>Therefore, this results in a misalignment bug that must be fixed. &#x1f41b;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"flexible-array_members_and_implicit_unions\"><\/span>flexible-array members and implicit unions<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Before getting into the details of how to properly fix this issue, let me note that implicit unions between a FAM and a fixed-size array are not uncommon in kernel code. I&#8217;ve addressed several <code>-Wflex-array-member-not-at-end<\/code> warnings when this was the case before (however, those did not manifest any misalignment bug). This is actually one of the categories of <code>not-at-end<\/code> FAMs I often discuss at conferences:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"700\" height=\"397\" src=\"https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-From-2026-04-16-18-30-22-700x397.png\" alt=\"\" class=\"wp-image-2970\" srcset=\"https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-From-2026-04-16-18-30-22-700x397.png 700w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-From-2026-04-16-18-30-22-300x170.png 300w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-From-2026-04-16-18-30-22-768x435.png 768w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-From-2026-04-16-18-30-22-1536x870.png 1536w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-From-2026-04-16-18-30-22-800x453.png 800w, https:\/\/embeddedor.com\/blog\/wp-content\/uploads\/2026\/04\/Screenshot-From-2026-04-16-18-30-22.png 1772w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><figcaption class=\"wp-element-caption\">Upstream Kernel Hardening: Progress on enabling -Wflex-array-member-not-at-end (OSSJP2025)<sup data-fn=\"e78f3bf9-1d06-4eb2-b786-913bf3f126f4\" class=\"fn\"><a href=\"#e78f3bf9-1d06-4eb2-b786-913bf3f126f4\" id=\"e78f3bf9-1d06-4eb2-b786-913bf3f126f4-link\">4<\/a><\/sup><\/figcaption><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>What&#8217;s crucial for implicit unions of this kind is that the arrays are correctly aligned. That is, both arrays must share the same address in memory. We also need to ensure that this alignment is not inadvertently changed in the future.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"The_bugfix\"><\/span>The bugfix<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>So, going back to the bug in question, we need to address two issues:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>1) We need to find a way to make the FAM in <code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">struct virtio_net_rss_config_trailer<\/code> appear at the end of <code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">struct virtnet_info<\/code>. With this, we&#8217;ll be fixing the <code>-Wflex-array-member-not-at-end<\/code> warning.<\/li>\n\n\n\n<li>2) We need to fix the misalignment bug between the FAM and the fixed-size array.<\/li>\n<\/ul>\n\n\n\n<p>Over the past couple of years we, in the Linux Kernel Self-Protection Project<sup data-fn=\"bc3136b1-48cc-4cbb-adde-a7c267fd00b6\" class=\"fn\"><a href=\"#bc3136b1-48cc-4cbb-adde-a7c267fd00b6\" id=\"bc3136b1-48cc-4cbb-adde-a7c267fd00b6-link\">5<\/a><\/sup>, have implemented different methods and strategies to address these FAM <code>not-at-end<\/code> issues. The most recent innovation we&#8217;ve come up with for this is the <code>TRAILING_OVERLAP()<\/code><sup data-fn=\"ef93047d-4a9c-46c9-9059-c2c0aa9c4e36\" class=\"fn\"><a href=\"#ef93047d-4a9c-46c9-9059-c2c0aa9c4e36\" id=\"ef93047d-4a9c-46c9-9059-c2c0aa9c4e36-link\">6<\/a><\/sup> helper macro.<\/p>\n\n\n\n<p>The idea behind this helper is to address the common pattern of <strong><code>implicit unions<\/code> between a FAM and a number of following adjacent members of any type in a structure<\/strong> by creating an <code>explicit union<\/code> between them. I plan to talk more in detail about this macro, and show different scenarios where it can be used in a future post. For now, I&#8217;ll just show the bugfix<sup data-fn=\"f352415b-1be6-4009-aec4-ad418a6c6b7c\" class=\"fn\"><a href=\"#f352415b-1be6-4009-aec4-ad418a6c6b7c\" id=\"f352415b-1be6-4009-aec4-ad418a6c6b7c-link\">7<\/a><\/sup> below and describe the fixed up memory layout.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"diff\" class=\"EnlighterJSRAW\">diff --git a\/drivers\/net\/virtio_net.c b\/drivers\/net\/virtio_net.c\nindex ca92b4a1879ce..db88dcaefb20b 100644\n--- a\/drivers\/net\/virtio_net.c\n+++ b\/drivers\/net\/virtio_net.c\n@@ -425,9 +425,6 @@ struct virtnet_info {\n \tu16 rss_indir_table_size;\n \tu32 rss_hash_types_supported;\n \tu32 rss_hash_types_saved;\n-\tstruct virtio_net_rss_config_hdr *rss_hdr;\n-\tstruct virtio_net_rss_config_trailer rss_trailer;\n-\tu8 rss_hash_key_data&#91;VIRTIO_NET_RSS_MAX_KEY_SIZE];\n \n \t\/* Has control virtqueue *\/\n \tbool has_cvq;\n@@ -484,7 +481,16 @@ struct virtnet_info {\n \tstruct failover *failover;\n \n \tu64 device_stats_cap;\n+\n+\tstruct virtio_net_rss_config_hdr *rss_hdr;\n+\n+\t\/* Must be last as it ends in a flexible-array member. *\/\n+\tTRAILING_OVERLAP(struct virtio_net_rss_config_trailer, rss_trailer, hash_key_data,\n+\t\tu8 rss_hash_key_data&#91;VIRTIO_NET_RSS_MAX_KEY_SIZE];\n+\t);\n };\n+static_assert(offsetof(struct virtnet_info, rss_trailer.hash_key_data) ==\n+\t      offsetof(struct virtnet_info, rss_hash_key_data));\n \n struct padded_vnet_hdr {\n \tstruct virtio_net_hdr_v1_hash hdr;<\/code><\/code><\/pre>\n\n\n\n<p>After using <code>TRAILING_OVERLAP()<\/code>, and moving both <code>struct virtio_net_rss_config_trailer rss_trailer;<\/code> and <code>u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE];<\/code> at the end of <code>struct virtnet_info<\/code>, we end up with the following memory layout.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><code data-enlighter-language=\"c\" class=\"EnlighterJSRAW\">After changes, those members are correctly aligned at offset 795:\n\nstruct virtnet_info {\n...\n    union {\n        struct virtio_net_rss_config_trailer rss_trailer;   \/*   792     4 *\/\n        struct {\n                unsigned char __offset_to_hash_key_data&#91;3]; \/*   792     3 *\/\n                u8         rss_hash_key_data&#91;40];           \/*   795    40 *\/\n        };                                                  \/*   792    43 *\/\n    };                                                      \/*   792    44 *\/\n...\n};<\/code><\/code><\/pre>\n\n\n\n<p>As mentioned above, <code>rss_trailer.hash_key_data<\/code> and <code>rss_hash_key_data<\/code> are now correctly aligned at <code>offset 795<\/code> (the <code>1-byte<\/code> padding in between is gone), and FAM <code>rss_trailer.hash_key_data<\/code> is seen by the compiler as being at the end of <code>struct virtnet_info<\/code>. With this, both the warning and the bug are effectively resolved.<\/p>\n\n\n\n<p>Lastly, the <code>static_assert()<\/code> line ensures that the alignment does not inadvertently change.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span>Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>To conclude, let me just note that this is yet another subtle bug that <code>-Wflex-array-member-not-at-end<\/code> has helped us uncover in the Linux kernel. As I shared in a previous post<sup data-fn=\"8a742ec0-cb06-44b7-80d9-a8041d8f6f25\" class=\"fn\"><a href=\"#8a742ec0-cb06-44b7-80d9-a8041d8f6f25\" id=\"8a742ec0-cb06-44b7-80d9-a8041d8f6f25-link\">8<\/a><\/sup>, <strong>we&#8217;ve recently completed 85% of the work toward enabling this compiler option in mainline.<\/strong> Once it is globally enabled, it&#8217;s unlikely that these and other classes of memory corruption bugs<sup data-fn=\"a28e4cee-b4c0-4b01-953c-dde392017a1c\" class=\"fn\"><a href=\"#a28e4cee-b4c0-4b01-953c-dde392017a1c\" id=\"a28e4cee-b4c0-4b01-953c-dde392017a1c-link\">9<\/a><\/sup> <sup data-fn=\"5d5feb38-826f-4f9e-bfe2-323e9064d606\" class=\"fn\"><a href=\"#5d5feb38-826f-4f9e-bfe2-323e9064d606\" id=\"5d5feb38-826f-4f9e-bfe2-323e9064d606-link\">10<\/a><\/sup> <sup data-fn=\"3234eb92-70ad-4656-bfc9-cb2a3323f767\" class=\"fn\"><a href=\"#3234eb92-70ad-4656-bfc9-cb2a3323f767\" id=\"3234eb92-70ad-4656-bfc9-cb2a3323f767-link\">11<\/a><\/sup> <sup data-fn=\"074a789d-1cd0-4ceb-8264-fd5b0667358f\" class=\"fn\"><a href=\"#074a789d-1cd0-4ceb-8264-fd5b0667358f\" id=\"074a789d-1cd0-4ceb-8264-fd5b0667358f-link\">12<\/a><\/sup> will make their way into the upstream Linux kernel going forward.<\/p>\n\n\n\n<p>Thanks! &#x1f642;&#x1f427;&#x1f6e1;&#x2694;&#xfe0f;<\/p>\n\n\n<ol class=\"wp-block-footnotes\"><li id=\"8f534952-d1bb-4c3f-aef8-a02ea6895374\"><a href=\"https:\/\/embeddedor.com\/blog\/presentations\/#Upstream_Kernel_Hardening_Progress_on_enabling_-Wflex-array-member-not-at-end_OSSJP2025\" target=\"_blank\" rel=\"noreferrer noopener\">Upstream Kernel Hardening: Progress on enabling -Wflex-array-member-not-at-end<\/a> <a href=\"#8f534952-d1bb-4c3f-aef8-a02ea6895374-link\" aria-label=\"Jump to footnote reference 1\">\u21a9\ufe0e<\/a><\/li><li id=\"11de6685-74ba-4a88-bf1b-aaa1174f31a1\"><a href=\"https:\/\/gcc.gnu.org\/onlinedocs\/gcc\/Zero-Length.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/gcc.gnu.org\/onlinedocs\/gcc\/Zero-Length.html<\/a> <a href=\"#11de6685-74ba-4a88-bf1b-aaa1174f31a1-link\" aria-label=\"Jump to footnote reference 2\">\u21a9\ufe0e<\/a><\/li><li id=\"c6b105f2-c52b-4f7d-8e0f-1ec9500797f7\"><a href=\"https:\/\/lwn.net\/Articles\/908817\/\" target=\"_blank\" rel=\"noreferrer noopener\">Safer flexible arrays for the kernel<\/a> <a href=\"#c6b105f2-c52b-4f7d-8e0f-1ec9500797f7-link\" aria-label=\"Jump to footnote reference 3\">\u21a9\ufe0e<\/a><\/li><li id=\"e78f3bf9-1d06-4eb2-b786-913bf3f126f4\"><a href=\"https:\/\/embeddedor.com\/blog\/presentations\/#Upstream_Kernel_Hardening_Progress_on_enabling_-Wflex-array-member-not-at-end_OSSJP2025\" target=\"_blank\" rel=\"noreferrer noopener\">Upstream Kernel Hardening: Progress on enabling -Wflex-array-member-not-at-end (OSSJP2025)<\/a> <a href=\"#e78f3bf9-1d06-4eb2-b786-913bf3f126f4-link\" aria-label=\"Jump to footnote reference 4\">\u21a9\ufe0e<\/a><\/li><li id=\"bc3136b1-48cc-4cbb-adde-a7c267fd00b6\"><a href=\"https:\/\/kspp.github.io\/\"><\/a><a href=\"https:\/\/kspp.github.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">Linux Kernel Self-Protection Project<\/a> <a href=\"#bc3136b1-48cc-4cbb-adde-a7c267fd00b6-link\" aria-label=\"Jump to footnote reference 5\">\u21a9\ufe0e<\/a><\/li><li id=\"ef93047d-4a9c-46c9-9059-c2c0aa9c4e36\"><a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=29bb79e9dbf1ba100125e39deb7147acd490903f\" target=\"_blank\" rel=\"noreferrer noopener\">stddef: Introduce TRAILING_OVERLAP() helper macro<\/a> <a href=\"#ef93047d-4a9c-46c9-9059-c2c0aa9c4e36-link\" aria-label=\"Jump to footnote reference 6\">\u21a9\ufe0e<\/a><\/li><li id=\"f352415b-1be6-4009-aec4-ad418a6c6b7c\"><a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=4156c3745f06bc197094b9ee97a9584e69ed00bf\" target=\"_blank\" rel=\"noreferrer noopener\">virtio_net: Fix misalignment bug in struct virtnet_info<\/a> <a href=\"#f352415b-1be6-4009-aec4-ad418a6c6b7c-link\" aria-label=\"Jump to footnote reference 7\">\u21a9\ufe0e<\/a><\/li><li id=\"8a742ec0-cb06-44b7-80d9-a8041d8f6f25\"><a href=\"https:\/\/embeddedor.com\/blog\/2026\/04\/14\/100-wflex-array-member-not-at-end-issues-in-linux-next\/\" target=\"_blank\" rel=\"noreferrer noopener\">100 -Wflex-array-member-not-at-end issues in linux-next<\/a> <a href=\"#8a742ec0-cb06-44b7-80d9-a8041d8f6f25-link\" aria-label=\"Jump to footnote reference 8\">\u21a9\ufe0e<\/a><\/li><li id=\"a28e4cee-b4c0-4b01-953c-dde392017a1c\"><a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=eea03d18af9c4423\" target=\"_blank\" rel=\"noreferrer noopener\">qed\/red_ll2: Fix undefined behavior bug in struct qed_ll2_info<\/a> <a href=\"#a28e4cee-b4c0-4b01-953c-dde392017a1c-link\" aria-label=\"Jump to footnote reference 9\">\u21a9\ufe0e<\/a><\/li><li id=\"5d5feb38-826f-4f9e-bfe2-323e9064d606\"><a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=cf44e745048df2c935cb37de16e0ca476003a3b1\" target=\"_blank\" rel=\"noreferrer noopener\">wifi: mac80211: ieee80211_i: Fix memory corruption bug in struct ieee80211_chanctx<\/a> <a href=\"#5d5feb38-826f-4f9e-bfe2-323e9064d606-link\" aria-label=\"Jump to footnote reference 10\">\u21a9\ufe0e<\/a><\/li><li id=\"3234eb92-70ad-4656-bfc9-cb2a3323f767\"><a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=6e4bf018bb040955da53dae9f8628ef8fcec2dbe\" target=\"_blank\" rel=\"noreferrer noopener\">clk: clk-loongson2: Fix memory corruption bug in struct loongson2_clk_provider<\/a> <a href=\"#3234eb92-70ad-4656-bfc9-cb2a3323f767-link\" aria-label=\"Jump to footnote reference 11\">\u21a9\ufe0e<\/a><\/li><li id=\"074a789d-1cd0-4ceb-8264-fd5b0667358f\"><a href=\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=ef56578274d2b98423c8ef82bb450223f5811b59\" target=\"_blank\" rel=\"noreferrer noopener\">cgroup: Eliminate cgrp_ancestor_storage in cgroup_root<\/a> <a href=\"#074a789d-1cd0-4ceb-8264-fd5b0667358f-link\" aria-label=\"Jump to footnote reference 12\">\u21a9\ufe0e<\/a><\/li><\/ol>\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The warning During one of my presentations at Open Source Summit Japan &#x1f1ef;&#x1f1f5; the past year, I talked about a bug I found while addressing -Wflex-array-member-not-at-end issues in the Linux kernel. The warning reported by the compiler was the following. See the related code below. According to the compiler, struct virtio_net_rss_config_trailer at line 429 above&#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":"[{\"content\":\"<a href=\\\"https:\/\/embeddedor.com\/blog\/presentations\/#Upstream_Kernel_Hardening_Progress_on_enabling_-Wflex-array-member-not-at-end_OSSJP2025\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">Upstream Kernel Hardening: Progress on enabling -Wflex-array-member-not-at-end<\/a>\",\"id\":\"8f534952-d1bb-4c3f-aef8-a02ea6895374\"},{\"content\":\"<a href=\\\"https:\/\/gcc.gnu.org\/onlinedocs\/gcc\/Zero-Length.html\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">https:\/\/gcc.gnu.org\/onlinedocs\/gcc\/Zero-Length.html<\/a>\",\"id\":\"11de6685-74ba-4a88-bf1b-aaa1174f31a1\"},{\"content\":\"<a href=\\\"https:\/\/lwn.net\/Articles\/908817\/\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">Safer flexible arrays for the kernel<\/a>\",\"id\":\"c6b105f2-c52b-4f7d-8e0f-1ec9500797f7\"},{\"content\":\"<a href=\\\"https:\/\/embeddedor.com\/blog\/presentations\/#Upstream_Kernel_Hardening_Progress_on_enabling_-Wflex-array-member-not-at-end_OSSJP2025\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">Upstream Kernel Hardening: Progress on enabling -Wflex-array-member-not-at-end (OSSJP2025)<\/a>\",\"id\":\"e78f3bf9-1d06-4eb2-b786-913bf3f126f4\"},{\"content\":\"<a href=\\\"https:\/\/kspp.github.io\/\\\"><\/a><a href=\\\"https:\/\/kspp.github.io\/\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">Linux Kernel Self-Protection Project<\/a>\",\"id\":\"bc3136b1-48cc-4cbb-adde-a7c267fd00b6\"},{\"content\":\"<a href=\\\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=29bb79e9dbf1ba100125e39deb7147acd490903f\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">stddef: Introduce TRAILING_OVERLAP() helper macro<\/a>\",\"id\":\"ef93047d-4a9c-46c9-9059-c2c0aa9c4e36\"},{\"content\":\"<a href=\\\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=4156c3745f06bc197094b9ee97a9584e69ed00bf\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">virtio_net: Fix misalignment bug in struct virtnet_info<\/a>\",\"id\":\"f352415b-1be6-4009-aec4-ad418a6c6b7c\"},{\"content\":\"<a href=\\\"https:\/\/embeddedor.com\/blog\/2026\/04\/14\/100-wflex-array-member-not-at-end-issues-in-linux-next\/\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">100 -Wflex-array-member-not-at-end issues in linux-next<\/a>\",\"id\":\"8a742ec0-cb06-44b7-80d9-a8041d8f6f25\"},{\"content\":\"<a href=\\\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=eea03d18af9c4423\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">qed\/red_ll2: Fix undefined behavior bug in struct qed_ll2_info<\/a>\",\"id\":\"a28e4cee-b4c0-4b01-953c-dde392017a1c\"},{\"content\":\"<a href=\\\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=cf44e745048df2c935cb37de16e0ca476003a3b1\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">wifi: mac80211: ieee80211_i: Fix memory corruption bug in struct ieee80211_chanctx<\/a>\",\"id\":\"5d5feb38-826f-4f9e-bfe2-323e9064d606\"},{\"content\":\"<a href=\\\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=6e4bf018bb040955da53dae9f8628ef8fcec2dbe\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">clk: clk-loongson2: Fix memory corruption bug in struct loongson2_clk_provider<\/a>\",\"id\":\"3234eb92-70ad-4656-bfc9-cb2a3323f767\"},{\"content\":\"<a href=\\\"https:\/\/git.kernel.org\/pub\/scm\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=ef56578274d2b98423c8ef82bb450223f5811b59\\\" target=\\\"_blank\\\" rel=\\\"noreferrer noopener\\\">cgroup: Eliminate cgrp_ancestor_storage in cgroup_root<\/a>\",\"id\":\"074a789d-1cd0-4ceb-8264-fd5b0667358f\"}]"},"categories":[31,13,18,9],"tags":[],"class_list":["post-2636","post","type-post","status-publish","format-standard","hentry","category-wfamnae","category-kernel-self-protection-project","category-linux-kernel-bugs","category-linux-kernel-hardening"],"_links":{"self":[{"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/posts\/2636","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=2636"}],"version-history":[{"count":305,"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/posts\/2636\/revisions"}],"predecessor-version":[{"id":3296,"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/posts\/2636\/revisions\/3296"}],"wp:attachment":[{"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/media?parent=2636"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/categories?post=2636"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/embeddedor.com\/blog\/wp-json\/wp\/v2\/tags?post=2636"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}