I have code using container_of macros to get parent structure pointer from inner structure pointer. However, it triggers the clang-tidy security.ArrayBound warning.
For instance the following code
#include <stdio.h>
#include <stddef.h>
#include <assert.h>
#define container_of(ptr, type, member) ({ \
const void *__mptr = (void *)(ptr); \
(type *)((char *)__mptr - offsetof(type, member)); \
})
/* Simple inner structure */
struct inner_data {
int id;
float value;
};
/* Container structure that includes the inner structure */
struct container {
double extra_value;
char name[32];
int count;
struct inner_data data; /* Embedded inner structure */
};
/* Function that works with the inner structure */
void update_data(struct inner_data *data, float new_value) {
/* Get access to the container using container_of */
struct container *parent = container_of(data, struct container, data);
/* Now we can update container fields */
parent->extra_value = new_value * 2.0;
}
int main()
{
struct container my_container;
struct inner_data * mydata = &my_container.data;
update_data(mydata, 200.0);
}
Generates the following warning :
clang-tidy-21 -checks=clang-analyzer-* test.c -- -std=c11 -O2
1 warning generated.
/tmp/test.c:31:13: warning: Out of bound access to memory preceding 'my_container.data' [clang-analyzer-security.ArrayBound]
31 | parent->extra_value = new_value * 2.0;
| ^
/tmp/test.c:38:5: note: Calling 'update_data'
38 | update_data(mydata, 200.0);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
/tmp/test.c:31:13: note: Access of 'my_container.data' at negative byte offset -44
31 | parent->extra_value = new_value * 2.0;
| ~~~~~~~~^~~~~~~~~~~
I used the __clang_analyzer__
macro to trick the analyzer into not computing the pointer offset.
#ifdef __clang_analyzer__
#define container_of(ptr, type, member) ({ void *__consume(void *p); (type *)__consume(ptr); })
#else
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
To me, the decoupling possibility offered by container_of are worth the associated misuse risk.