I am reading linux kernel 5.17.5 and now looking at container_of() macro.
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })
My question is really simple: What is the purpose of the __mptr
, can i just replace __mptr
by (void *)ptr
like this?
#define container_of(ptr, type, member) ({ \
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)((void*)ptr - offsetof(type, member))); })
Since “kernel.h: handle pointers to arrays better in container_of()”,
__mptr
doesn't serve for type checking anymore. It is used to eliminatescripts/gcc-plugins/randomize_layout_plugin.c
's informative message likeinform(gimple_location(stmt), "found mismatched ssa struct pointer types: %qT and %qT\n", ptr_lhs_type, ptr_rhs_type);
. One of this file's job is:If
__mptr
is missing, the macro will include code as you said:(type *)((void*)ptr - offsetof(type, member)))
(PS:
char *
is better here, because it is guaranteed by iso c standard to be 1 byte foroffsetof
,void *
is guaranteed by gnu c only)If
offsetof
gets zero, and ptr will contain the start address of struct typemember
, then this will be cast to be a totally different type:struct type *
. This form malfunctions perscripts/gcc-plugins/randomize_layout_plugin.c
and will be detected by it.With the introduce of
void *__mptr = (void *)(ptr);
, the compiler doesn't know the type of__mptr
anymore, soscripts/gcc-plugins/randomize_layout_plugin.c
will not complain when casting thevoid *
__mptr
to(type *)
You can see the real case and related fixed patch from https://lkml.org/lkml/2017/6/20/873Below is original answer for kernel prior to 4.13 when
__mptr
was used for type checking:Let's simplify the
container_of
and see this case:container_of_without_typechecking
doesn't have__mptr
butcontainer_of
does.When compiling:
As you can see,
container_of
throws anincompatible pointer type
warning whilecontainer_of_without_typechecking
does not, so it just for type checking.Also, note that the Linux kernel regards this warning as an error:
So, you will get an error instead of a warning if you pass through the wrong type to
container_of
.