<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Gustavo A. R. Silva</title>
    <link>https://people.kernel.org/gustavoars/</link>
    <description>Labor et Sapientia Libertas</description>
    <pubDate>Wed, 08 Apr 2026 13:34:50 +0000</pubDate>
    <item>
      <title>How to use the new counted_by attribute in C (and Linux)</title>
      <link>https://people.kernel.org/gustavoars/how-to-use-the-new-counted_by-attribute-in-c-and-linux</link>
      <description>&lt;![CDATA[&#xA;&#xA;The counted\by attribute&#xA;&#xA;The countedby attribute was introduced in Clang-18 and will soon be available in GCC-15. Its purpose is to associate a flexible-array member with a struct member that will hold the number of elements in this array at some point at run-time. This association is critical for enabling runtime bounds checking via the array bounds sanitizer and the _builtindynamicobjectsize() built-in function. In user-space, this extra level of security is enabled by -DFORTIFYSOURCE=3. Therefore, using this attribute correctly enhances C codebases with runtime bounds-checking coverage on flexible-array members.&#xA;&#xA;Here is an example of a flexible array annotated with this attribute:&#xA;&#xA;struct boundedflexstruct {&#xA;    ...&#xA;    sizet count;&#xA;    struct foo flexarray[] attribute((_countedby_(count)));&#xA;};&#xA;&#xA;In the above example, count is the struct member that will hold the number of elements of the flexible array at run-time. We will call this struct member the counter.&#xA;&#xA;In the Linux kernel, this attribute facilitates bounds-checking coverage through fortified APIs such as the memcpy() family of functions, which internally use builtindynamicobjectsize() (CONFIG\FORTIFY\SOURCE). As well as through the array-bounds sanitizer (CONFIG\UBSAN\BOUNDS).&#xA;&#xA;The \\counted\by() macro&#xA;&#xA;In the kernel we wrap the countedby attribute in the _countedby() macro, as shown below.&#xA;&#xA;if _hasattribute(_countedby)&#xA;define countedby(member)  attribute((countedby(member)))&#xA;else&#xA;define countedby(member)&#xA;endif&#xA;c8248faf3ca27 (&#34;Compiler Attributes: counted\by: Adjust name...&#34;)&#xA;&#xA;And with this we have been annotating flexible-array members across the whole kernel tree over the last year.&#xA;&#xA;diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.h b/drivers/net/ethernet/chelsio/cxgb4/sched.h&#xA;index 5f8b871d79afac..6b3c778815f09e 100644&#xA;--- a/drivers/net/ethernet/chelsio/cxgb4/sched.h&#xA;+++ b/drivers/net/ethernet/chelsio/cxgb4/sched.h&#xA;@@ -82,7 +82,7 @@ struct schedclass {&#xA; &#xA; struct schedtable {      / per port scheduling table /&#xA; &#x9;u8 schedsize;&#xA;struct schedclass tab[];&#xA;struct schedclass tab[] countedby(schedsize);&#xA; };&#xA;ceba9725fb45 (&#34;cxgb4: Annotate struct sched\table with ...&#34;)&#xA;&#xA;However, as we are about to see, not all _countedby() annotations are always as straightforward as the one above.&#xA;&#xA;\\counted\by() annotations in the kernel&#xA;&#xA;There are a number of requirements to properly use the countedby attribute. One crucial requirement is that the counter must be initialized before the first reference to the flexible-array member. Another requirement is that the array must always contain at least as many elements as indicated by the counter. Below you can see an example of a kernel patch addressing these requirements.&#xA;&#xA;diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c&#xA;index dac7eb77799bd1..68960ae9898713 100644&#xA;--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c&#xA;+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c&#xA;@@ -33,7 +33,7 @@ struct brcmffwehqueueitem {&#xA; &#x9;u8 ifaddr[ETHALEN];&#xA; &#x9;struct brcmfeventmsgbe emsg;&#xA; &#x9;u32 datalen;&#xA;u8 data[];&#xA;u8 data[] countedby(datalen);&#xA; };&#xA; &#xA; /&#xA;@@ -418,17 +418,17 @@ void brcmffwehprocessevent(struct brcmfpub drvr,&#xA; &#x9;    datalen + sizeof(eventpacket)   packetlen)&#xA; &#x9;&#x9;return;&#xA; &#xA;event = kzalloc(sizeof(event) + datalen, gfp);&#xA;event = kzalloc(structsize(event, data, datalen), gfp);&#xA; &#x9;if (!event)&#xA; &#x9;&#x9;return;&#xA; &#xA;event-  datalen = datalen;&#xA; &#x9;event-  code = code;&#xA; &#x9;event-  ifidx = eventpacket-  msg.ifidx;&#xA; &#xA; &#x9;/ use memcpy to get aligned event message /&#xA; &#x9;memcpy(&amp;event-  emsg, &amp;eventpacket-  msg, sizeof(event-  emsg));&#xA; &#x9;memcpy(event-  data, data, datalen);&#xA;event-  datalen = datalen;&#xA; &#x9;memcpy(event-  ifaddr, eventpacket-  eth.hdest, ETHALEN);&#xA; &#xA; &#x9;brcmffwehqueueevent(fweh, event);&#xA;&#xA;62d19b358088 (&#34;wifi: brcmfmac: fweh: Add \\counted\by...&#34;)&#xA;&#xA;In the patch above, datalen is the counter for the flexible-array member data. Notice how the assignment to the counter event-  datalen = datalen had to be moved to before calling memcpy(event-  data, data, datalen), this ensures the counter is initialized before the first reference to the flexible array. Otherwise, the compiler would complain about trying to write into a flexible array of size zero, due to datalen being zeroed out by a previous call to kzalloc(). This assignment-after-memcpy has been quite common in the Linux kernel. However, when dealing with countedby annotations, this pattern should be changed. Therefore, we have to be careful when doing these annotations. We should audit all instances of code that reference both the counter and the flexible array and ensure they meet the proper requirements.&#xA;&#xA;In the kernel, we&#39;ve been learning from our mistakes and have fixed some buggy annotations we made in the beginning. Here are a couple of bugfixes to make you aware of these issues:&#xA;&#xA;6dc445c19050 (&#34;clk: bcm: rpi: Assign -  num before accessing...&#34;)&#xA;&#xA;9368cdf90f52 (&#34;clk: bcm: dvp: Assign -  num before accessing...&#34;)&#xA;&#xA;Another common issue is when the counter is updated inside a loop. See the patch below.&#xA;&#xA;diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c&#xA;index 8993028709ecfb..e8f1d30a8d73c5 100644&#xA;--- a/drivers/net/wireless/ath/wil6210/cfg80211.c&#xA;+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c&#xA;@@ -892,10 +892,8 @@ static int wilcfg80211scan(struct wiphy wiphy,&#xA; &#x9;struct wil6210priv wil = wiphytowil(wiphy);&#xA; &#x9;struct wirelessdev wdev = request-  wdev;&#xA; &#x9;struct wil6210vif vif = wdevtovif(wil, wdev);&#xA;struct {&#xA;struct wmistartscancmd cmd;&#xA;u16 chnl[4];&#xA;} packed cmd;&#xA;DEFINEFLEX(struct wmistartscancmd, cmd,&#xA;channellist, numchannels, 4);&#xA; &#x9;uint i, n;&#xA; &#x9;int rc;&#xA; &#xA;@@ -977,9 +975,8 @@ static int wilcfg80211scan(struct wiphy wiphy,&#xA; &#x9;vif-  scanrequest = request;&#xA; &#x9;modtimer(&amp;vif-  scantimer, jiffies + WIL6210SCANTO);&#xA; &#xA;memset(&amp;cmd, 0, sizeof(cmd));&#xA;cmd.cmd.scantype = WMIACTIVESCAN;&#xA;cmd.cmd.numchannels = 0;&#xA;cmd-  scantype = WMIACTIVESCAN;&#xA;cmd-  numchannels = 0;&#xA; &#x9;n = min(request-  nchannels, 4U);&#xA; &#x9;for (i = 0; i &lt; n; i++) {&#xA; &#x9;&#x9;int ch = request-  channels[i]-  hwvalue;&#xA;@@ -991,7 +988,8 @@ static int wilcfg80211scan(struct wiphy wiphy,&#xA; &#x9;&#x9;&#x9;continue;&#xA; &#x9;&#x9;}&#xA; &#x9;&#x9;/ 0-based channel indexes /&#xA;cmd.cmd.channellist[cmd.cmd.numchannels++].channel = ch - 1;&#xA;cmd-  numchannels++;&#xA;cmd-  channellist[cmd-  numchannels - 1].channel = ch - 1;&#xA; &#x9;&#x9;wildbgmisc(wil, &#34;Scan for ch %d  : %d MHz\n&#34;, ch,&#xA; &#x9;&#x9;&#x9;     request-  channels[i]-  centerfreq);&#xA; &#x9;}&#xA;@@ -1007,16 +1005,15 @@ static int wilcfg80211scan(struct wiphy wiphy,&#xA; &#x9;if (rc)&#xA; &#x9;&#x9;goto outrestore;&#xA; &#xA;if (wil-  discoverymode &amp;&amp; cmd.cmd.scantype == WMIACTIVESCAN) {&#xA;cmd.cmd.discoverymode = 1;&#xA;if (wil-  discoverymode &amp;&amp; cmd-  scantype == WMIACTIVESCAN) {&#xA;cmd-  discoverymode = 1;&#xA; &#x9;&#x9;wildbgmisc(wil, &#34;active scan with discoverymode=1\n&#34;);&#xA; &#x9;}&#xA; &#xA; &#x9;if (vif-  mid == 0)&#xA; &#x9;&#x9;wil-  radiowdev = wdev;&#xA; &#x9;rc = wmisend(wil, WMISTARTSCANCMDID, vif-  mid,&#xA;&amp;cmd, sizeof(cmd.cmd) +&#xA;cmd.cmd.numchannels  sizeof(cmd.cmd.channellist[0]));&#xA;cmd, structsize(cmd, channellist, cmd-  numchannels));&#xA; &#xA; outrestore:&#xA; &#x9;if (rc) {&#xA;diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h&#xA;index 71bf2ae27a984f..b47606d9068c8b 100644&#xA;--- a/drivers/net/wireless/ath/wil6210/wmi.h&#xA;+++ b/drivers/net/wireless/ath/wil6210/wmi.h&#xA;@@ -474,7 +474,7 @@ struct wmistartscancmd {&#xA; &#x9;struct {&#xA; &#x9;&#x9;u8 channel;&#xA; &#x9;&#x9;u8 reserved;&#xA;} channellist[];&#xA;} channellist[] _countedby(numchannels);&#xA; } packed;&#xA; &#xA; #define WMIMAXPNOSSIDNUM&#x9;(16)&#xA;&#xA;34c34c242a1b (&#34;wifi: wil6210: cfg80211: Use \\counted\by...&#34;)&#xA;&#xA;The patch above does a bit more than merely annotating the flexible array with the _countedby() macro, but that&#39;s material for a future post. For now, let&#39;s focus on the following excerpt.&#xA;&#xA;cmd.cmd.scantype = WMIACTIVESCAN;&#xA;cmd.cmd.numchannels = 0;&#xA;cmd-  scantype = WMIACTIVESCAN;&#xA;cmd-  numchannels = 0;&#xA; &#x9;n = min(request-  nchannels, 4U);&#xA; &#x9;for (i = 0; i &lt; n; i++) {&#xA; &#x9;&#x9;int ch = request-  channels[i]-  hwvalue;&#xA;@@ -991,7 +988,8 @@ static int wilcfg80211scan(struct wiphy wiphy,&#xA; &#x9;&#x9;&#x9;continue;&#xA; &#x9;&#x9;}&#xA; &#x9;&#x9;/ 0-based channel indexes /&#xA;cmd.cmd.channellist[cmd.cmd.numchannels++].channel = ch - 1;&#xA;cmd-  numchannels++;&#xA;cmd-  channellist[cmd-  numchannels - 1].channel = ch - 1;&#xA; &#x9;&#x9;wildbgmisc(wil, &#34;Scan for ch %d  : %d MHz\n&#34;, ch,&#xA; &#x9;&#x9;&#x9;     request-  channels[i]-  centerfreq);&#xA; &#x9;}&#xA; ...&#xA;--- a/drivers/net/wireless/ath/wil6210/wmi.h&#xA;+++ b/drivers/net/wireless/ath/wil6210/wmi.h&#xA;@@ -474,7 +474,7 @@ struct wmistartscancmd {&#xA; &#x9;struct {&#xA; &#x9;&#x9;u8 channel;&#xA; &#x9;&#x9;u8 reserved;&#xA;} channellist[];&#xA;} channellist[] countedby(numchannels);&#xA; } packed;&#xA;&#xA;Notice that in this case, numchannels is our counter, and it&#39;s set to zero before the for loop. Inside the for loop, the original code used this variable as an index to access the flexible array, then updated it via a post-increment, all in one line: cmd.cmd.channellist[cmd.cmd.numchannels++]. The issue is that once channellist was annotated with the countedby() macro, the compiler enforces dynamic array indexing of channellist to stay below numchannels. Since numchannels holds a value of zero at the moment of the array access, this leads to undefined behavior and may trigger a compiler warning.&#xA;&#xA;As shown in the patch, the solution is to increment numchannels before accessing the array, and then access the array through an index adjustment below numchannels.&#xA;&#xA;Another option is to avoid using the counter as an index for the flexible array altogether. This can be done by using an auxiliary variable instead. See an excerpt of a patch below.&#xA;&#xA;diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h&#xA;index 38eb7ec86a1a65..21ebd70f3dcc97 100644&#xA;--- a/include/net/bluetooth/hci.h&#xA;+++ b/include/net/bluetooth/hci.h&#xA;@@ -2143,7 +2143,7 @@ struct hcicplesetcigparams {&#xA; &#x9;_le16  clatency;&#xA; &#x9;_le16  platency;&#xA; &#x9;_u8    numcis;&#xA;struct hcicisparams cis[];&#xA;struct hcicisparams cis[] _countedby(numcis);&#xA; } packed;&#xA;&#xA;@@ -1722,34 +1717,33 @@ static int hcilecreatebig(struct hciconn conn, struct btisoqos qos)&#xA; &#xA; static int setcigparamssync(struct hcidev hdev, void data)&#xA; {&#xA; ...&#xA;&#xA;u8 auxnumcis = 0;&#xA; &#x9;u8 cisid;&#xA; ...&#xA;&#xA; &#x9;for (cisid = 0x00; cisid &lt; 0xf0 &amp;&amp;&#xA;pdu.cp.numcis &lt; ARRAYSIZE(pdu.cis); cisid++) {&#xA;auxnumcis  pdu-numcis; cisid++) {&#xA; &#x9;&#x9;struct hcicisparams cis;&#xA; &#xA; &#x9;&#x9;conn = hciconnhashlookupcis(hdev, NULL, 0, cigid, cisid);&#xA;@@ -1758,7 +1752,7 @@ static int setcigparamssync(struct hcidev hdev, void data)&#xA; &#xA; &#x9;&#x9;qos = &amp;conn-  isoqos;&#xA; &#xA;cis = &amp;pdu.cis[pdu.cp.numcis++];&#xA;cis = &amp;pdu-  cis[auxnumcis++];&#xA; &#x9;&#x9;cis-  cisid = cisid;&#xA; &#x9;&#x9;cis-  csdu  = cputole16(conn-  isoqos.ucast.out.sdu);&#xA; &#x9;&#x9;cis-  psdu  = cputole16(conn-  isoqos.ucast.in.sdu);&#xA;@@ -1769,14 +1763,14 @@ static int setcigparamssync(struct hcidev hdev, void data)&#xA; &#x9;&#x9;cis-  crtn  = qos-  ucast.out.rtn;&#xA; &#x9;&#x9;cis-  prtn  = qos-  ucast.in.rtn;&#xA; &#x9;}&#xA;pdu-  numcis = auxnumcis;&#xA; &#xA; ...&#xA;&#xA;ea9e148c803b (&#34;Bluetooth: hci\conn: Use \\counted\by() and...&#34;)&#xA;&#xA;Again, the entire patch does more than merely annotate the flexible-array member, but let&#39;s just focus on how auxnumcis is used to access flexible array pdu-  cis[].&#xA;&#xA;In this case, the counter is numcis. As in our previous example, originally, the counter is used to directly access the flexible array: &amp;pdu.cis[pdu.cp.numcis++]. However, the patch above introduces a new variable auxnumcis to be used instead of the counter: &amp;pdu-  cis[auxnumcis++]. The counter is then updated after the loop: pdu-  numcis = auxnumcis.&#xA;&#xA;Both solutions are acceptable, so use whichever is convenient for you. :)&#xA;&#xA;Here, you can see a recent bugfix for some buggy annotations that missed the details discussed above:&#xA;&#xA;\[PATCH\] wifi: iwlwifi: mvm: Fix \counted\by usage in cfg80211\wowlan\nd\*&#xA;&#xA;In a future post, I&#39;ll address the issue of annotating flexible arrays of flexible structures. Spoiler alert: don&#39;t do it!&#xA;&#xA;Latest version: How to use the new countedby attribute in C (and Linux)]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://embeddedor.com/blog/wp-content/uploads/2024/06/Screenshot-from-2024-06-19-09-18-59-700x234.png" alt=""></p>

<h2 id="the-counted-by-attribute">The counted_by attribute</h2>

<p>The <code>counted_by</code> attribute was introduced in Clang-18 and will soon be available in GCC-15. Its purpose is to associate a <code>flexible-array member</code> with a struct member that will hold the number of elements in this array at some point at run-time. This association is critical for enabling runtime bounds checking via the <code>array bounds sanitizer</code> and the <code>__builtin_dynamic_object_size()</code> built-in function. In user-space, this extra level of security is enabled by <a href="https://developers.redhat.com/articles/2022/09/17/gccs-new-fortification-level" rel="nofollow"><code>-D_FORTIFY_SOURCE=3</code></a>. Therefore, using this attribute correctly enhances C codebases with runtime bounds-checking coverage on flexible-array members.</p>

<p>Here is an example of a flexible array annotated with this attribute:</p>

<pre><code class="language-C">struct bounded_flex_struct {
    ...
    size_t count;
    struct foo flex_array[] __attribute__((__counted_by__(count)));
};
</code></pre>

<p>In the above example, <code>count</code> is the struct member that will hold the number of elements of the flexible array at run-time. We will call this struct member the <em>counter</em>.</p>

<p>In the Linux kernel, this attribute facilitates bounds-checking coverage through fortified APIs such as the <code>memcpy()</code> family of functions, which internally use <code>__builtin_dynamic_object_size()</code> (CONFIG_FORTIFY_SOURCE). As well as through the array-bounds sanitizer (CONFIG_UBSAN_BOUNDS).</p>

<h2 id="the-counted-by-macro">The __counted_by() macro</h2>

<p>In the kernel we wrap the <code>counted_by</code> attribute in the <code>__counted_by()</code> macro, as shown below.</p>

<pre><code class="language-C">#if __has_attribute(__counted_by__)
# define __counted_by(member)  __attribute__((__counted_by__(member)))
#else
# define __counted_by(member)
#endif
</code></pre>
<ul><li><a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c8248faf3ca276ebdf60f003b3e04bf764daba91" rel="nofollow">c8248faf3ca27</a> (“Compiler Attributes: counted_by: Adjust name...“)</li></ul>

<p>And with this we have been <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?qt=grep&amp;q=__counted_by" rel="nofollow">annotating flexible-array members</a> across the whole kernel tree over the last year.</p>

<pre><code class="language-diff">diff --git a/drivers/net/ethernet/chelsio/cxgb4/sched.h b/drivers/net/ethernet/chelsio/cxgb4/sched.h
index 5f8b871d79afac..6b3c778815f09e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sched.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/sched.h
@@ -82,7 +82,7 @@ struct sched_class {
 
 struct sched_table {      /* per port scheduling table */
 	u8 sched_size;
-	struct sched_class tab[];
+	struct sched_class tab[] __counted_by(sched_size);
 };
</code></pre>
<ul><li><a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ceba9725fb4554c3cd07d055332272208b8a052f" rel="nofollow">ceba9725fb45</a> (“cxgb4: Annotate struct sched_table with ...“)</li></ul>

<p>However, as we are about to see, not all <code>__counted_by()</code> annotations are always as straightforward as the one above.</p>

<h2 id="counted-by-annotations-in-the-kernel">__counted_by() annotations in the kernel</h2>

<p>There are <a href="https://gcc.gnu.org/pipermail/gcc-patches/2024-May/653123.html" rel="nofollow">a number of requirements</a> to properly use the <code>counted_by</code> attribute. One crucial requirement is that the <em>counter</em> must be initialized before the first reference to the flexible-array member. Another requirement is that the array must always contain at least as many elements as indicated by the <em>counter</em>. Below you can see an example of a kernel patch addressing these requirements.</p>

<pre><code class="language-diff">diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
index dac7eb77799bd1..68960ae9898713 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
@@ -33,7 +33,7 @@ struct brcmf_fweh_queue_item {
 	u8 ifaddr[ETH_ALEN];
 	struct brcmf_event_msg_be emsg;
 	u32 datalen;
-	u8 data[];
+	u8 data[] __counted_by(datalen);
 };
 
 /*
@@ -418,17 +418,17 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
 	    datalen + sizeof(*event_packet) &gt; packet_len)
 		return;
 
-	event = kzalloc(sizeof(*event) + datalen, gfp);
+	event = kzalloc(struct_size(event, data, datalen), gfp);
 	if (!event)
 		return;
 
+	event-&gt;datalen = datalen;
 	event-&gt;code = code;
 	event-&gt;ifidx = event_packet-&gt;msg.ifidx;
 
 	/* use memcpy to get aligned event message */
 	memcpy(&amp;event-&gt;emsg, &amp;event_packet-&gt;msg, sizeof(event-&gt;emsg));
 	memcpy(event-&gt;data, data, datalen);
-	event-&gt;datalen = datalen;
 	memcpy(event-&gt;ifaddr, event_packet-&gt;eth.h_dest, ETH_ALEN);
 
 	brcmf_fweh_queue_event(fweh, event);
</code></pre>
<ul><li><a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=62d19b35808816dc2bdf5031e5401230f6a915ba" rel="nofollow">62d19b358088</a> (“wifi: brcmfmac: fweh: Add __counted_by...“)</li></ul>

<p>In the patch above, <code>datalen</code> is the <em>counter</em> for the flexible-array member <code>data</code>. Notice how the assignment to the <em>counter</em> <code>event-&gt;datalen = datalen</code> had to be moved to before calling <code>memcpy(event-&gt;data, data, datalen)</code>, this ensures the <em>counter</em> is initialized before the first reference to the flexible array. Otherwise, the compiler would complain about trying to write into a flexible array of size zero, due to <code>datalen</code> being zeroed out by a previous call to <code>kzalloc()</code>. This assignment-after-memcpy has been quite common in the Linux kernel. However, when dealing with <code>counted_by</code> annotations, this pattern should be changed. Therefore, we have to be careful when doing these annotations. We should audit all instances of code that reference both the <em>counter</em> and the flexible array and ensure they meet the proper requirements.</p>

<p>In the kernel, we&#39;ve been learning from our mistakes and have fixed some buggy annotations we made in the beginning. Here are a couple of bugfixes to make you aware of these issues:</p>
<ul><li><p><a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=6dc445c1905096b2ed4db1a84570375b4e00cc0f" rel="nofollow">6dc445c19050</a> (“clk: bcm: rpi: Assign –&gt;num before accessing...“)</p></li>

<li><p><a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9368cdf90f52a68120d039887ccff74ff33b4444" rel="nofollow">9368cdf90f52</a> (“clk: bcm: dvp: Assign –&gt;num before accessing...“)</p></li></ul>

<p>Another common issue is when the <em>counter</em> is updated inside a loop. See the patch below.</p>

<pre><code class="language-diff">diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 8993028709ecfb..e8f1d30a8d73c5 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -892,10 +892,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
 	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
 	struct wireless_dev *wdev = request-&gt;wdev;
 	struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
-	struct {
-		struct wmi_start_scan_cmd cmd;
-		u16 chnl[4];
-	} __packed cmd;
+	DEFINE_FLEX(struct wmi_start_scan_cmd, cmd,
+		    channel_list, num_channels, 4);
 	uint i, n;
 	int rc;
 
@@ -977,9 +975,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
 	vif-&gt;scan_request = request;
 	mod_timer(&amp;vif-&gt;scan_timer, jiffies + WIL6210_SCAN_TO);
 
-	memset(&amp;cmd, 0, sizeof(cmd));
-	cmd.cmd.scan_type = WMI_ACTIVE_SCAN;
-	cmd.cmd.num_channels = 0;
+	cmd-&gt;scan_type = WMI_ACTIVE_SCAN;
+	cmd-&gt;num_channels = 0;
 	n = min(request-&gt;n_channels, 4U);
 	for (i = 0; i &lt; n; i++) {
 		int ch = request-&gt;channels[i]-&gt;hw_value;
@@ -991,7 +988,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
 			continue;
 		}
 		/* 0-based channel indexes */
-		cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1;
+		cmd-&gt;num_channels++;
+		cmd-&gt;channel_list[cmd-&gt;num_channels - 1].channel = ch - 1;
 		wil_dbg_misc(wil, &#34;Scan for ch %d  : %d MHz\n&#34;, ch,
 			     request-&gt;channels[i]-&gt;center_freq);
 	}
@@ -1007,16 +1005,15 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
 	if (rc)
 		goto out_restore;
 
-	if (wil-&gt;discovery_mode &amp;&amp; cmd.cmd.scan_type == WMI_ACTIVE_SCAN) {
-		cmd.cmd.discovery_mode = 1;
+	if (wil-&gt;discovery_mode &amp;&amp; cmd-&gt;scan_type == WMI_ACTIVE_SCAN) {
+		cmd-&gt;discovery_mode = 1;
 		wil_dbg_misc(wil, &#34;active scan with discovery_mode=1\n&#34;);
 	}
 
 	if (vif-&gt;mid == 0)
 		wil-&gt;radio_wdev = wdev;
 	rc = wmi_send(wil, WMI_START_SCAN_CMDID, vif-&gt;mid,
-		      &amp;cmd, sizeof(cmd.cmd) +
-		      cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
+		      cmd, struct_size(cmd, channel_list, cmd-&gt;num_channels));
 
 out_restore:
 	if (rc) {
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 71bf2ae27a984f..b47606d9068c8b 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -474,7 +474,7 @@ struct wmi_start_scan_cmd {
 	struct {
 		u8 channel;
 		u8 reserved;
-	} channel_list[];
+	} channel_list[] __counted_by(num_channels);
 } __packed;
 
 #define WMI_MAX_PNO_SSID_NUM	(16)
</code></pre>
<ul><li><a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=34c34c242a1be24cb5da17fe2954c8c71caf815a" rel="nofollow">34c34c242a1b</a> (“wifi: wil6210: cfg80211: Use __counted_by...“)</li></ul>

<p>The patch above does a bit more than merely annotating the flexible array with the <code>__counted_by()</code> macro, but that&#39;s material for a future post. For now, let&#39;s focus on the following excerpt.</p>

<pre><code class="language-diff">-	cmd.cmd.scan_type = WMI_ACTIVE_SCAN;
-	cmd.cmd.num_channels = 0;
+	cmd-&gt;scan_type = WMI_ACTIVE_SCAN;
+	cmd-&gt;num_channels = 0;
 	n = min(request-&gt;n_channels, 4U);
 	for (i = 0; i &lt; n; i++) {
 		int ch = request-&gt;channels[i]-&gt;hw_value;
@@ -991,7 +988,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
 			continue;
 		}
 		/* 0-based channel indexes */
-		cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1;
+		cmd-&gt;num_channels++;
+		cmd-&gt;channel_list[cmd-&gt;num_channels - 1].channel = ch - 1;
 		wil_dbg_misc(wil, &#34;Scan for ch %d  : %d MHz\n&#34;, ch,
 			     request-&gt;channels[i]-&gt;center_freq);
 	}
 ...
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -474,7 +474,7 @@ struct wmi_start_scan_cmd {
 	struct {
 		u8 channel;
 		u8 reserved;
-	} channel_list[];
+	} channel_list[] __counted_by(num_channels);
 } __packed;
</code></pre>

<p>Notice that in this case, <code>num_channels</code> is our <em>counter</em>, and it&#39;s set to zero before the for loop. Inside the for loop, the original code used this variable as an index to access the flexible array, then updated it via a post-increment, all in one line: <code>cmd.cmd.channel_list[cmd.cmd.num_channels++]</code>. The issue is that once <code>channel_list</code> was annotated with the <code>__counted_by()</code> macro, the compiler enforces dynamic array indexing of <code>channel_list</code> to stay below <code>num_channels</code>. Since <code>num_channels</code> holds a value of zero at the moment of the array access, this leads to undefined behavior and may trigger a compiler warning.</p>

<p>As shown in the patch, the solution is to increment <code>num_channels</code> before accessing the array, and then access the array through an index adjustment below <code>num_channels</code>.</p>

<p>Another option is to avoid using the <em>counter</em> as an index for the flexible array altogether. This can be done by using an auxiliary variable instead. See an excerpt of a patch below.</p>

<pre><code class="language-diff">diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 38eb7ec86a1a65..21ebd70f3dcc97 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -2143,7 +2143,7 @@ struct hci_cp_le_set_cig_params {
 	__le16  c_latency;
 	__le16  p_latency;
 	__u8    num_cis;
-	struct hci_cis_params cis[];
+	struct hci_cis_params cis[] __counted_by(num_cis);
 } __packed;

@@ -1722,34 +1717,33 @@ static int hci_le_create_big(struct hci_conn *conn, struct bt_iso_qos *qos)
 
 static int set_cig_params_sync(struct hci_dev *hdev, void *data)
 {
 ...

+	u8 aux_num_cis = 0;
 	u8 cis_id;
 ...

 	for (cis_id = 0x00; cis_id &lt; 0xf0 &amp;&amp;
-	     pdu.cp.num_cis &lt; ARRAY_SIZE(pdu.cis); cis_id++) {
+	     aux_num_cis &lt; pdu-&gt;num_cis; cis_id++) {
 		struct hci_cis_params *cis;
 
 		conn = hci_conn_hash_lookup_cis(hdev, NULL, 0, cig_id, cis_id);
@@ -1758,7 +1752,7 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data)
 
 		qos = &amp;conn-&gt;iso_qos;
 
-		cis = &amp;pdu.cis[pdu.cp.num_cis++];
+		cis = &amp;pdu-&gt;cis[aux_num_cis++];
 		cis-&gt;cis_id = cis_id;
 		cis-&gt;c_sdu  = cpu_to_le16(conn-&gt;iso_qos.ucast.out.sdu);
 		cis-&gt;p_sdu  = cpu_to_le16(conn-&gt;iso_qos.ucast.in.sdu);
@@ -1769,14 +1763,14 @@ static int set_cig_params_sync(struct hci_dev *hdev, void *data)
 		cis-&gt;c_rtn  = qos-&gt;ucast.out.rtn;
 		cis-&gt;p_rtn  = qos-&gt;ucast.in.rtn;
 	}
+	pdu-&gt;num_cis = aux_num_cis;
 
 ...
</code></pre>
<ul><li><a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ea9e148c803b24ebbc7a74171f22f42c8fd8d644" rel="nofollow">ea9e148c803b</a> (“Bluetooth: hci_conn: Use __counted_by() and...“)</li></ul>

<p>Again, the entire patch does more than merely annotate the flexible-array member, but let&#39;s just focus on how <code>aux_num_cis</code> is used to access flexible array <code>pdu-&gt;cis[]</code>.</p>

<p>In this case, the <em>counter</em> is <code>num_cis</code>. As in our previous example, originally, the <em>counter</em> is used to directly access the flexible array: <code>&amp;pdu.cis[pdu.cp.num_cis++]</code>. However, the patch above introduces a new variable <code>aux_num_cis</code> to be used instead of the <em>counter</em>: <code>&amp;pdu-&gt;cis[aux_num_cis++]</code>. The <em>counter</em> is then updated after the loop: <code>pdu-&gt;num_cis = aux_num_cis</code>.</p>

<p>Both solutions are acceptable, so use whichever is convenient for you. :)</p>

<p>Here, you can see a recent bugfix for some <a href="https://lore.kernel.org/linux-hardening/20240517153332.18271-1-dmantipov@yandex.ru/" rel="nofollow">buggy</a> annotations that missed the details discussed above:</p>
<ul><li>[<a href="https://lore.kernel.org/linux-hardening/20240619211233.work.355-kees@kernel.org/" rel="nofollow">PATCH</a>] wifi: iwlwifi: mvm: Fix <em>_counted_by usage in cfg80211_wowlan_nd</em>*</li></ul>

<p>In a future post, I&#39;ll address the issue of annotating flexible arrays of flexible structures. Spoiler alert: <strong>don&#39;t do it!</strong></p>

<p>Latest version: <a href="https://embeddedor.com/blog/2024/06/18/how-to-use-the-new-counted_by-attribute-in-c-and-linux/" rel="nofollow">How to use the new counted_by attribute in C (and Linux)</a></p>
]]></content:encoded>
      <guid>https://people.kernel.org/gustavoars/how-to-use-the-new-counted_by-attribute-in-c-and-linux</guid>
      <pubDate>Wed, 17 Jul 2024 00:43:46 +0000</pubDate>
    </item>
  </channel>
</rss>