2022-12-01 19:59:05

by Greg Kroah-Hartman

[permalink] [raw]
Subject: [PATCH 1/4] container_of: add container_of_const() that preserves const-ness of the pointer

container_of does not preserve the const-ness of a pointer that is
passed into it, which can cause C code that passes in a const pointer to
get a pointer back that is not const and then scribble all over the data
in it. To prevent this, container_of_const() will preserve the const
status of the pointer passed into it using the newly available _Generic()
method.

Co-developed-by: Jason Gunthorpe <[email protected]>
Cc: Matthew Wilcox <[email protected]>
Cc: Sakari Ailus <[email protected]>
Cc: Andy Shevchenko <[email protected]>
Cc: "Rafael J. Wysocki" <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
include/linux/container_of.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/include/linux/container_of.h b/include/linux/container_of.h
index 2008e9f4058c..3c290e865151 100644
--- a/include/linux/container_of.h
+++ b/include/linux/container_of.h
@@ -22,4 +22,18 @@
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })

+/**
+ * container_of_const - cast a member of a structure out to the containing
+ * structure and preserve the const-ness of the pointer
+ * @ptr_type: the type of the pointer @ptr
+ * @ptr: the pointer to the member
+ * @member_type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ */
+#define container_of_const(ptr_type, ptr, member_type, member) \
+ _Generic(ptr, \
+ const ptr_type *: ((const member_type *)container_of(ptr, member_type, member)),\
+ ptr_type *: ((member_type *)container_of(ptr, member_type, member)) \
+ )
+
#endif /* _LINUX_CONTAINER_OF_H */
--
2.38.1


2022-12-01 23:10:04

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH 1/4] container_of: add container_of_const() that preserves const-ness of the pointer

On Thu, Dec 01, 2022 at 08:30:54PM +0100, Greg Kroah-Hartman wrote:
> container_of does not preserve the const-ness of a pointer that is
> passed into it, which can cause C code that passes in a const pointer to
> get a pointer back that is not const and then scribble all over the data
> in it. To prevent this, container_of_const() will preserve the const
> status of the pointer passed into it using the newly available _Generic()
> method.
>
> Co-developed-by: Jason Gunthorpe <[email protected]>

I believe this tag requires SoB of the co-develper.
The code looks good to me, thanks!
Reviewed-by: Andy Shevchenko <[email protected]>

> Cc: Matthew Wilcox <[email protected]>
> Cc: Sakari Ailus <[email protected]>
> Cc: Andy Shevchenko <[email protected]>
> Cc: "Rafael J. Wysocki" <[email protected]>
> Signed-off-by: Greg Kroah-Hartman <[email protected]>
> ---
> include/linux/container_of.h | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/include/linux/container_of.h b/include/linux/container_of.h
> index 2008e9f4058c..3c290e865151 100644
> --- a/include/linux/container_of.h
> +++ b/include/linux/container_of.h
> @@ -22,4 +22,18 @@
> "pointer type mismatch in container_of()"); \
> ((type *)(__mptr - offsetof(type, member))); })
>
> +/**
> + * container_of_const - cast a member of a structure out to the containing
> + * structure and preserve the const-ness of the pointer
> + * @ptr_type: the type of the pointer @ptr
> + * @ptr: the pointer to the member
> + * @member_type: the type of the container struct this is embedded in.
> + * @member: the name of the member within the struct.
> + */
> +#define container_of_const(ptr_type, ptr, member_type, member) \
> + _Generic(ptr, \
> + const ptr_type *: ((const member_type *)container_of(ptr, member_type, member)),\
> + ptr_type *: ((member_type *)container_of(ptr, member_type, member)) \
> + )
> +
> #endif /* _LINUX_CONTAINER_OF_H */
> --
> 2.38.1
>

--
With Best Regards,
Andy Shevchenko


2022-12-01 23:58:31

by Sakari Ailus

[permalink] [raw]
Subject: Re: [PATCH 1/4] container_of: add container_of_const() that preserves const-ness of the pointer

Hi Greg,

On Thu, Dec 01, 2022 at 08:30:54PM +0100, Greg Kroah-Hartman wrote:
> container_of does not preserve the const-ness of a pointer that is
> passed into it, which can cause C code that passes in a const pointer to
> get a pointer back that is not const and then scribble all over the data
> in it. To prevent this, container_of_const() will preserve the const
> status of the pointer passed into it using the newly available _Generic()
> method.

"_const" in the name suggests that the macro would always take a const
argument. Could this be called e.g. container_of_safe() (for type-safe, but
full type_safe would be a bit long)?

--
Kind regards,

Sakari Ailus

2022-12-02 01:05:08

by Jason Gunthorpe

[permalink] [raw]
Subject: Re: [PATCH 1/4] container_of: add container_of_const() that preserves const-ness of the pointer

On Fri, Dec 02, 2022 at 12:50:05AM +0200, Andy Shevchenko wrote:
> On Thu, Dec 01, 2022 at 08:30:54PM +0100, Greg Kroah-Hartman wrote:
> > container_of does not preserve the const-ness of a pointer that is
> > passed into it, which can cause C code that passes in a const pointer to
> > get a pointer back that is not const and then scribble all over the data
> > in it. To prevent this, container_of_const() will preserve the const
> > status of the pointer passed into it using the newly available _Generic()
> > method.
> >
> > Co-developed-by: Jason Gunthorpe <[email protected]>
>
> I believe this tag requires SoB of the co-develper.

Sure, Greg you can add whatever tags are required

Did you look at possibly just calling this "container_of" ?

Thanks,
Jason

2022-12-02 01:42:07

by Jason Gunthorpe

[permalink] [raw]
Subject: Re: [PATCH 1/4] container_of: add container_of_const() that preserves const-ness of the pointer

On Thu, Dec 01, 2022 at 08:30:54PM +0100, Greg Kroah-Hartman wrote:
> container_of does not preserve the const-ness of a pointer that is
> passed into it, which can cause C code that passes in a const pointer to
> get a pointer back that is not const and then scribble all over the data
> in it. To prevent this, container_of_const() will preserve the const
> status of the pointer passed into it using the newly available _Generic()
> method.
>
> Co-developed-by: Jason Gunthorpe <[email protected]>
> Cc: Matthew Wilcox <[email protected]>
> Cc: Sakari Ailus <[email protected]>
> Cc: Andy Shevchenko <[email protected]>
> Cc: "Rafael J. Wysocki" <[email protected]>
> Signed-off-by: Greg Kroah-Hartman <[email protected]>
> ---
> include/linux/container_of.h | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)

For the whole series

Reviewed-by: Jason Gunthorpe <[email protected]>

Jason

2022-12-02 07:08:18

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 1/4] container_of: add container_of_const() that preserves const-ness of the pointer

On Thu, Dec 01, 2022 at 08:46:12PM -0400, Jason Gunthorpe wrote:
> On Fri, Dec 02, 2022 at 12:50:05AM +0200, Andy Shevchenko wrote:
> > On Thu, Dec 01, 2022 at 08:30:54PM +0100, Greg Kroah-Hartman wrote:
> > > container_of does not preserve the const-ness of a pointer that is
> > > passed into it, which can cause C code that passes in a const pointer to
> > > get a pointer back that is not const and then scribble all over the data
> > > in it. To prevent this, container_of_const() will preserve the const
> > > status of the pointer passed into it using the newly available _Generic()
> > > method.
> > >
> > > Co-developed-by: Jason Gunthorpe <[email protected]>
> >
> > I believe this tag requires SoB of the co-develper.
>
> Sure, Greg you can add whatever tags are required

I need you to send me a signed-off-by line, I can't add that on my own
for obvious reasons.

> Did you look at possibly just calling this "container_of" ?

Yes, but to do that would require all instances to be touched as this
call takes 4 parameters, while container_of() takes 3, so that can't be
done simply, AND there would be a lot of build errors all at once.

I'll work on moving code over to the new call as needed.

thanks,

greg k-h

2022-12-02 11:27:59

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 1/4] container_of: add container_of_const() that preserves const-ness of the pointer

On Thu, Dec 01, 2022 at 11:21:50PM +0000, Sakari Ailus wrote:
> Hi Greg,
>
> On Thu, Dec 01, 2022 at 08:30:54PM +0100, Greg Kroah-Hartman wrote:
> > container_of does not preserve the const-ness of a pointer that is
> > passed into it, which can cause C code that passes in a const pointer to
> > get a pointer back that is not const and then scribble all over the data
> > in it. To prevent this, container_of_const() will preserve the const
> > status of the pointer passed into it using the newly available _Generic()
> > method.
>
> "_const" in the name suggests that the macro would always take a const
> argument.

I mean it here to be "this will preserve const" as yes, it can take a
const. Or not.

> Could this be called e.g. container_of_safe() (for type-safe, but
> full type_safe would be a bit long)?

const is an attribute of type safety, container_of is also type-safe
as-is, it's just the const portion here that is the difference between
the two.

Naming is hard :(

>
> --
> Kind regards,
>
> Sakari Ailus

2022-12-02 12:27:25

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH 1/4] container_of: add container_of_const() that preserves const-ness of the pointer

On Fri, Dec 02, 2022 at 11:45:55AM +0100, Greg Kroah-Hartman wrote:
> On Thu, Dec 01, 2022 at 11:21:50PM +0000, Sakari Ailus wrote:
> > On Thu, Dec 01, 2022 at 08:30:54PM +0100, Greg Kroah-Hartman wrote:
> > > container_of does not preserve the const-ness of a pointer that is
> > > passed into it, which can cause C code that passes in a const pointer to
> > > get a pointer back that is not const and then scribble all over the data
> > > in it. To prevent this, container_of_const() will preserve the const
> > > status of the pointer passed into it using the newly available _Generic()
> > > method.
> >
> > "_const" in the name suggests that the macro would always take a const
> > argument.
>
> I mean it here to be "this will preserve const" as yes, it can take a
> const. Or not.
>
> > Could this be called e.g. container_of_safe() (for type-safe, but
> > full type_safe would be a bit long)?
>
> const is an attribute of type safety, container_of is also type-safe
> as-is, it's just the const portion here that is the difference between
> the two.

container_of_const_safe() :-)

> Naming is hard :(

True.

--
With Best Regards,
Andy Shevchenko


2022-12-02 13:16:53

by Sakari Ailus

[permalink] [raw]
Subject: Re: [PATCH 1/4] container_of: add container_of_const() that preserves const-ness of the pointer

Hi Greg,

On Thu, Dec 01, 2022 at 08:30:54PM +0100, Greg Kroah-Hartman wrote:
> container_of does not preserve the const-ness of a pointer that is
> passed into it, which can cause C code that passes in a const pointer to
> get a pointer back that is not const and then scribble all over the data
> in it. To prevent this, container_of_const() will preserve the const
> status of the pointer passed into it using the newly available _Generic()
> method.
>
> Co-developed-by: Jason Gunthorpe <[email protected]>
> Cc: Matthew Wilcox <[email protected]>
> Cc: Sakari Ailus <[email protected]>
> Cc: Andy Shevchenko <[email protected]>
> Cc: "Rafael J. Wysocki" <[email protected]>
> Signed-off-by: Greg Kroah-Hartman <[email protected]>
> ---
> include/linux/container_of.h | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
>
> diff --git a/include/linux/container_of.h b/include/linux/container_of.h
> index 2008e9f4058c..3c290e865151 100644
> --- a/include/linux/container_of.h
> +++ b/include/linux/container_of.h
> @@ -22,4 +22,18 @@
> "pointer type mismatch in container_of()"); \
> ((type *)(__mptr - offsetof(type, member))); })
>
> +/**
> + * container_of_const - cast a member of a structure out to the containing
> + * structure and preserve the const-ness of the pointer
> + * @ptr_type: the type of the pointer @ptr
> + * @ptr: the pointer to the member
> + * @member_type: the type of the container struct this is embedded in.
> + * @member: the name of the member within the struct.
> + */
> +#define container_of_const(ptr_type, ptr, member_type, member) \

I missed earlier you had four arguments for the macro instead of three.

With default: this can be done with just three:

#define container_of_const(ptr, member_type, member) \
_Generic(ptr, \
const typeof(*(ptr)) *: ((const member_type *)container_of(ptr, member_type, member)),\
default: ((member_type *)container_of(ptr, member_type, member)) \
)

The const typeof(*(ptr)) * will match if ptr is const, otherwise default
matches. But you can't have typeof(*(ptr)) * instead of default as the two
types are still the same, hence default.

I've tested this on GCC 10.2.1 and clang 11.0.1.

This should also make it a bit easier for existing users to switch to the
new macro and hopefully eventual rename back to container_of() once all
users have been converted.

> + _Generic(ptr, \
> + const ptr_type *: ((const member_type *)container_of(ptr, member_type, member)),\
> + ptr_type *: ((member_type *)container_of(ptr, member_type, member)) \
> + )
> +
> #endif /* _LINUX_CONTAINER_OF_H */

--
Kind regards,

Sakari Ailus

2022-12-02 17:06:05

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 1/4] container_of: add container_of_const() that preserves const-ness of the pointer

On Fri, Dec 02, 2022 at 12:48:57PM +0000, Sakari Ailus wrote:
> Hi Greg,
>
> On Thu, Dec 01, 2022 at 08:30:54PM +0100, Greg Kroah-Hartman wrote:
> > container_of does not preserve the const-ness of a pointer that is
> > passed into it, which can cause C code that passes in a const pointer to
> > get a pointer back that is not const and then scribble all over the data
> > in it. To prevent this, container_of_const() will preserve the const
> > status of the pointer passed into it using the newly available _Generic()
> > method.
> >
> > Co-developed-by: Jason Gunthorpe <[email protected]>
> > Cc: Matthew Wilcox <[email protected]>
> > Cc: Sakari Ailus <[email protected]>
> > Cc: Andy Shevchenko <[email protected]>
> > Cc: "Rafael J. Wysocki" <[email protected]>
> > Signed-off-by: Greg Kroah-Hartman <[email protected]>
> > ---
> > include/linux/container_of.h | 14 ++++++++++++++
> > 1 file changed, 14 insertions(+)
> >
> > diff --git a/include/linux/container_of.h b/include/linux/container_of.h
> > index 2008e9f4058c..3c290e865151 100644
> > --- a/include/linux/container_of.h
> > +++ b/include/linux/container_of.h
> > @@ -22,4 +22,18 @@
> > "pointer type mismatch in container_of()"); \
> > ((type *)(__mptr - offsetof(type, member))); })
> >
> > +/**
> > + * container_of_const - cast a member of a structure out to the containing
> > + * structure and preserve the const-ness of the pointer
> > + * @ptr_type: the type of the pointer @ptr
> > + * @ptr: the pointer to the member
> > + * @member_type: the type of the container struct this is embedded in.
> > + * @member: the name of the member within the struct.
> > + */
> > +#define container_of_const(ptr_type, ptr, member_type, member) \
>
> I missed earlier you had four arguments for the macro instead of three.
>
> With default: this can be done with just three:
>
> #define container_of_const(ptr, member_type, member) \
> _Generic(ptr, \
> const typeof(*(ptr)) *: ((const member_type *)container_of(ptr, member_type, member)),\
> default: ((member_type *)container_of(ptr, member_type, member)) \
> )
>
> The const typeof(*(ptr)) * will match if ptr is const, otherwise default
> matches.

I had tried to use typeof before, your way is easier, thanks, I couldn't
get it to work myself...

> But you can't have typeof(*(ptr)) * instead of default as the two
> types are still the same, hence default.

Ah. Ok, I really didn't want to use default, and that's probably why it
wasn't working for me.

> I've tested this on GCC 10.2.1 and clang 11.0.1.
>
> This should also make it a bit easier for existing users to switch to the
> new macro and hopefully eventual rename back to container_of() once all
> users have been converted.

True. Ok, I'll try this later tomorrow and send out a new version if
all goes well, thanks!

greg k-h