Skip to content

Conversation

@ceolin
Copy link
Member

@ceolin ceolin commented Aug 29, 2025

Replace 0 length arrays declaration with proper C99 flexible arrays.

jhedberg
jhedberg previously approved these changes Aug 29, 2025
union {
uint8_t resv[0];
} __packed;
FLEXIBLE_ARRAY_DECLARE(uint8_t, resv);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have concern (not verified) that __packed has been removed by the introduction of FLEXIBLE_ARRAY_DECLARE. Is this truly equivalent?

I see prior PRs have already change some in subsys/bluetooth/controller/ll_sw/pdu.h file.

Can we have a __packed variant of this "workaround" define, like FLEXIBLE_ARRAY_DECLARE_PACKED?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, did __packed for an array of size 0 really do anything?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And even if it wasn't of size 0, since the elements are byte aligned, I don't think __packed would do anything at all.

Copy link
Contributor

@cvinayak cvinayak Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__packed struct or union when nested need __packed individually every time; besides themselves being packed, the parent struct or union which has __packed still need to include them without which the members are machine word aligned/sized (please run a sample on Cortex-M0 nRF51 and you will hit hardfaults based on how linking has been unlucky... i.e. increasing/decreasing buffer counts will misalign these structs).

This file is not the best example, as the union has only one zero length byte array.

But here :

struct pdu_data_vnd_octet3 {
union {
uint8_t resv[OCTET3_LEN]; /* nRF specific octet3 required for NRF_CCM use */
#if !defined(CONFIG_BT_CTLR_DATA_LENGTH_CLEAR)
struct pdu_cte_info cte_info; /* BT 5.1 Core spec. CTEInfo storage */
#endif /* !CONFIG_BT_CTLR_DATA_LENGTH_CLEAR */
} __packed;
} __packed;

The union needs __packed so that it take 1 byte and not 4 bytes in size.

It is best to have a FLEXIBLE_ARRAY_DECLARE_PACKED for code that had __packed for the union inside other __packed union/structs... and also where FLEXIBLE_ARRAY_DECLARE added new union/struct into __packed structs/unions. Hence to also correct the other PR that made changes to as here: 1a56b90

There is also zero length array alignment requirements for nRF51: 701d524

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this example is wrong. With/without packed you will get 4 bytes if CONFIG_BT_CTLR_DATA_LENGTH_CLEAR is not defined. And since this union is the only element of the structure pdu_data_vnd_octet3 that is packed you will get 1 byte size when CONFIG_BT_CTLR_DATA_LENGTH_CLEAR is defined.

If you noticed, I have just changed for this specific use case where the union.

I am wondering if I am missing something here though. Did you get any memory alignment issue ? Printing the struct sizes I get exactly the same thing and the alignment should be correct.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok... I did a quick diff of .lst file of a sample for BBC microbit board (adding CONFIG_OUTPUT_DISASSEMBLY=y), with and without 56e2b01, and I see no difference. I am ok for now.

Thalley
Thalley previously approved these changes Aug 29, 2025
union {
uint8_t resv[0];
} __packed;
FLEXIBLE_ARRAY_DECLARE(uint8_t, resv);
Copy link
Contributor

@cvinayak cvinayak Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__packed struct or union when nested need __packed individually every time; besides themselves being packed, the parent struct or union which has __packed still need to include them without which the members are machine word aligned/sized (please run a sample on Cortex-M0 nRF51 and you will hit hardfaults based on how linking has been unlucky... i.e. increasing/decreasing buffer counts will misalign these structs).

This file is not the best example, as the union has only one zero length byte array.

But here :

struct pdu_data_vnd_octet3 {
union {
uint8_t resv[OCTET3_LEN]; /* nRF specific octet3 required for NRF_CCM use */
#if !defined(CONFIG_BT_CTLR_DATA_LENGTH_CLEAR)
struct pdu_cte_info cte_info; /* BT 5.1 Core spec. CTEInfo storage */
#endif /* !CONFIG_BT_CTLR_DATA_LENGTH_CLEAR */
} __packed;
} __packed;

The union needs __packed so that it take 1 byte and not 4 bytes in size.

It is best to have a FLEXIBLE_ARRAY_DECLARE_PACKED for code that had __packed for the union inside other __packed union/structs... and also where FLEXIBLE_ARRAY_DECLARE added new union/struct into __packed structs/unions. Hence to also correct the other PR that made changes to as here: 1a56b90

There is also zero length array alignment requirements for nRF51: 701d524

#define BTP_OTS_READ_SUPPORTED_COMMANDS 0x01
struct btp_ots_read_supported_commands_rp {
uint8_t data[0];
FLEXIBLE_ARRAY_DECLARE(uint8_t, data);
Copy link
Contributor

@cvinayak cvinayak Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you use a script to do data[0] changes?

Below name[0] is not using FLEXIBLE_ARRAY_DECLARE :-)

Please revert to using uint8_t data[]; instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC C++ does not allow empty structs (i.e. struct with only uint8_t data[];, so that's why we need to use FLEXIBLE_ARRAY_DECLARE if a struct only contains a flexible array

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cvinayak it is exactly what @Thalley mentioned. I don't bother to change it if that is not a problem.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC C++ does not allow empty structs

@Thalley this is not documented in FLEXIBLE_ARRAY_DECLARE as a workaround for.

 * Since C99, flexible arrays are part of the C standard, but for historical
 * reasons many places still use an older GNU extension that is declare
 * zero length arrays.
 *
 * Although zero length arrays are flexible arrays, we can't blindly
 * replace [0] with [] because of some syntax limitations. This macro
 * workaround these limitations.

@ceolin I am not happy polluting the source with workarounds (more of Zephyr macro magics to make code convoluted, and "steep learning curve" when it comes to Zephyr code base), as clearly the documentation conveys that the macro is a workaround.

Well, for many reasons, redesigns/refactoring increasing CPU usages, compiler instruction re-ordering, bugs included, nRF51 support is broken over the times now (#74345).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cvinayak I see your point, unfortunately I don't see a better way to do it, at least not while we are supporting C++. Also, this macro is needed when using flexible arrays in unions.

There is always a risk of introducing issues for sure, but there are many benefits as well. Doing these changes I found some places where flexible arrays were not in the end of the structure and more importantly it will allow us to enable new compilation options to check some type out-of-bound accesses that is the majority cause of security issues.

@cvinayak
Copy link
Contributor

cvinayak commented Aug 30, 2025

Convinced for now, that the changes (did not check this particular PR changes, but only with 56e2b01) do not show any difference in generated code for a bbc microbit board sample with the Bluetooth Controller.

@thedjnK Cool experiment as part of this PR: #95191

My request changes can be dismissed (when conflicts are resolved in this PR).

0 length array is a GNU extension. Use proper C99 flexible
array.

Signed-off-by: Flavio Ceolin <[email protected]>
0 length array is a GNU extension. Use proper C99 flexible
array.

Signed-off-by: Flavio Ceolin <[email protected]>
0 length array is a GNU extension. Use proper C99 flexible
array.

Signed-off-by: Flavio Ceolin <[email protected]>
0 length array is a GNU extension. Use proper C99 flexible
array.

Signed-off-by: Flavio Ceolin <[email protected]>
0 length array is a GNU extension. Use proper C99 flexible
array.

Signed-off-by: Flavio Ceolin <[email protected]>
0 length array is a GNU extension. Use proper C99 flexible
array.

Signed-off-by: Flavio Ceolin <[email protected]>
0 length array is a GNU extension. Use proper C99 flexible
array.

Signed-off-by: Flavio Ceolin <[email protected]>
@ceolin ceolin dismissed stale reviews from Thalley and jhedberg via 0df79cf September 3, 2025 04:47
@ceolin ceolin force-pushed the security/flex-array branch from e028ecf to 0df79cf Compare September 3, 2025 04:47
@sonarqubecloud
Copy link

sonarqubecloud bot commented Sep 3, 2025

@ceolin
Copy link
Member Author

ceolin commented Sep 3, 2025

@jhedberg @cvinayak @Thalley would you mind take another look ?

@Thalley
Copy link
Contributor

Thalley commented Sep 3, 2025

@jhedberg @cvinayak @Thalley would you mind take another look ?

At least for me, it's easier if you just press the "Re-request review" button, so that it will show up in "Review requests" tab on Github :)

@cvinayak cvinayak dismissed their stale review September 3, 2025 07:27

No concerns from my side.

@jhedberg jhedberg merged commit 9fdbe5f into zephyrproject-rtos:main Sep 3, 2025
36 of 39 checks passed
@github-project-automation github-project-automation bot moved this from In Review to Done in Bluetooth LE Audio Sep 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

7 participants