2

On trying to understand the functionality of container_of() from the source code linux kernel Definition of container_of, I found out that the below line in the definition of the macro looks like doing nothing.

const typeof( ((type *)0)->member ) *__mptr = (ptr); \

So, I wrote a simple C program without the said line and tried to the compare the obtained results. Basically, I am trying to Understand how is the new implementation my_contianer_of() different from container_of() ? when both the implementation give same results.

#include <stdio.h>
#include <stddef.h>

#define container_of(ptr, type, member) ({                      \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );})

#define my_container_of(ptr, type, member) ({ \
        (char *)ptr - offsetof(type, member);})

struct container {
    int *i;
    char c;
    float f;
};

void foo(char *cptr)
{
    printf("foo  : %p\n", my_container_of(cptr, struct container, c));
}

int main(int argc, char *argv[])
{
    struct container tc;

    printf("&tc  : %p\n", &tc);
    printf("cof  : %p\n", container_of(&tc.c, struct container, c));
    printf("mycof: %p\n", my_container_of(&tc.c, struct container, c));

    foo(&tc.c);

    return 0;
}

The below is the sample output for the above c program.

&tc  : 0x7ffca543e0c0
cof  : 0x7ffca543e0c0
mycof: 0x7ffca543e0c0
foo  : 0x7ffca543e0c0

Please don't mark this question as the duplicate of any other question or this Understanding container_of macro in the linux kernel as those questions did not provide the required answer for my query.

Santosh A
  • 5,173
  • 27
  • 37
  • There could be edge cases that the simplified version does not handle. Or it's just a matter of eliminating compiler implicit typecasting warnings. – fredrik Sep 06 '18 at 06:08

1 Answers1

3

Your implementation isn't type safe. It doesn't make sure that the pointer you pass is to the same type as the member, which could lead to bugs. So, for instance:

my_container_of(&tc.f, struct container, c)

Will compile just fine. The kernel version will at least issue a warning about incompatible pointer types. Or flat out cause compilation to halt, depending on your GCC flags.

Naturally, the kernel version doesn't prevent all bugs (if f and c were of the same type, for instance). But this is one it can catch, and should.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458