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
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
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
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
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
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
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
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
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
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