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()”,
__mptrdoesn'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
__mptris 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
offsetofgets 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.cand will be detected by it.With the introduce of
void *__mptr = (void *)(ptr);, the compiler doesn't know the type of__mptranymore, soscripts/gcc-plugins/randomize_layout_plugin.cwill not complain when casting thevoid *__mptrto(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
__mptrwas used for type checking:Let's simplify the
container_ofand see this case:container_of_without_typecheckingdoesn't have__mptrbutcontainer_ofdoes.When compiling:
As you can see,
container_ofthrows anincompatible pointer typewarning whilecontainer_of_without_typecheckingdoes 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.