[v3,1/2] uapi: fix __DECLARE_FLEX_ARRAY for C++

Message ID 97242381-f1ec-4a4a-9472-1a464f575657@p183
State New
Headers
Series [v3,1/2] uapi: fix __DECLARE_FLEX_ARRAY for C++ |

Commit Message

Alexey Dobriyan Sept. 12, 2023, 4:22 p.m. UTC
  __DECLARE_FLEX_ARRAY(T, member) macro expands to

	struct {
		struct {} __empty_member;
		T member[];
	};

which is subtly wrong in C++ because sizeof(struct{}) is 1 not 0,
changing UAPI structures layouts.

This can be fixed by expanding to

	T member[];

Now g++ doesn't like "T member[]" either, throwing errors on
the following code:

	struct S {
		union {
			T1 member1[];
			T2 member2[];
		};
	};

or

	struct S {
		T member[];
	};

Use "T member[0];" which seems to work and does the right thing wrt
structure layout.

Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Fixes: 3080ea5553cc ("stddef: Introduce DECLARE_FLEX_ARRAY() helper")
---

 include/uapi/linux/stddef.h |    6 ++++++
 1 file changed, 6 insertions(+)
  

Comments

Kees Cook Sept. 15, 2023, 7:14 p.m. UTC | #1
On Tue, Sep 12, 2023 at 07:22:24PM +0300, Alexey Dobriyan wrote:
> __DECLARE_FLEX_ARRAY(T, member) macro expands to
> 
> 	struct {
> 		struct {} __empty_member;
> 		T member[];
> 	};
> 
> which is subtly wrong in C++ because sizeof(struct{}) is 1 not 0,
> changing UAPI structures layouts.

Looking at this again just now, what about using a 0-length array
instead of an anonymous struct?

https://godbolt.org/z/rGaxPWjef

Then we don't need an #ifdef at all...

 	struct {
 		int __empty_member[0];
 		T member[];
 	};

-Kees
  

Patch

--- a/include/uapi/linux/stddef.h
+++ b/include/uapi/linux/stddef.h
@@ -29,6 +29,11 @@ 
 		struct TAG { MEMBERS } ATTRS NAME; \
 	}
 
+#ifdef __cplusplus
+/* sizeof(struct{}) is 1 in C++, not 0, can't use C version of the macro. */
+#define __DECLARE_FLEX_ARRAY(T, member)	\
+	T member[0]
+#else
 /**
  * __DECLARE_FLEX_ARRAY() - Declare a flexible array usable in a union
  *
@@ -45,6 +50,7 @@ 
 		TYPE NAME[]; \
 	}
 #endif
+#endif
 
 #ifndef __counted_by
 #define __counted_by(m)