container_of注意事项

汤博
2023-12-01

已知一个变量的地址时,使用container_of获取此变量所在的结构体的首指针。其定义如下:

#define container_of(ptr, type, member) ({              \
    void *__mptr = (void *)(ptr);                   \
    BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&   \
             !__same_type(*(ptr), void),            \
             "pointer type mismatch in container_of()");    \
    ((type *)(__mptr - offsetof(type, member))); })


看一个例子,在中断下半部处理中,process_backlog函数根据napi指针地址,获取到其所在的softnet_data结构体的地址。一定要注意的是第三个参数(member)成员变量backlog,在结构体softnet_data中为变量,而不是指针,意思就是说backlog的地址一定是在为softnet_data分配空间的时候一起分配的,才能保证由backlog的地址(参数一:napi)推导出softnet_data的地址。

struct softnet_data {
    struct sk_buff_head process_queue;
    struct sk_buff_head input_pkt_queue;
    struct napi_struct  backlog;       //这里一定是变量,而非指针。
};
static int process_backlog(struct napi_struct *napi, int quota)
{   
    struct softnet_data *sd = container_of(napi, struct softnet_data, backlog);
}

如果backlog是一个指针,会出现什么情况?如下,假设成员backlog为指针,其初始化为全局变量ns_g的地址。此时的container_of拿ns_g的地址去做偏移,显然会得到一个非法的越界指针。

struct softnet_data {
    struct napi_struct  *backlog;       //错误情况
} sd_test;

struct napi_struct ns_g;
sd_test.backlog = &ns_g;

其实此种情况下,也是可以得到正确的softnet_data的地址的,只不过需要用backlog指针的地址去做偏移。

 

 

 类似资料: