[Mesa-dev] [PATCH 1/9] util: fix undefined behavior
Tolga Dalman
tolga.dalman at googlemail.com
Sun Apr 8 01:28:45 PDT 2012
On 06.04.2012 17:38, nobled wrote:
> On Mon, Apr 2, 2012 at 7:40 AM, Tolga Dalman
> <tolga.dalman at googlemail.com> wrote:
> Hi,
>
>
> On 02.04.2012 00:24, nobled wrote:
>>>> #define LIST_FOR_EACH_ENTRY(pos, head, member) \
>>>> - for (pos = container_of((head)->next, pos, member); \
>>>> + for (pos = NULL, pos = container_of((head)->next, pos, member); \
>>>> &pos->member != (head); \
>>>> pos = container_of(pos->member.next, pos, member))
>
> The container_of macro is obviously error-prone and leads to future
> problems. Your patch works around that buggy API instead of
> really fixing it.
>
> container_of could be defined using the offsetof macro, i.e.,
>
> #define container_of(ptr, type, member) \
> (void *)((char *)(ptr) - offsetof(type, member))
>
> As far as I can see, container_of is only used sparsely in
> mesa, so applying my proposal should be possible quite easily.
>> Not really. container_of() is only used *directly* in this one header;
>> but changing it to require a type parameter requires also changing all
>> the macros that use it in turn, which actually are used widely in
>> mesa.
Widely is a bit exaggerated. Basically, it is only used in the
LIST_FOR_EACH macros. A quick grep results:
grep "[[:space:]]LIST_FOR_EACH" * -R|grep -v u_double_list.h|wc -l
35
I also noticed, that LIST_FOR_EACH_ENTRY_FROM and LIST_FOR_EACH_ENTRY_FROM_REV
are not used anywhere in the mesa source.
>> Adding the type name to every use of the LIST_FOR_EACH_* macros
>> also introduces redundancy and the possibility of error, e.g. if the
>> containing ever changes but not every use of the macro is updated,
>> there's no compile error but it'll go wrong at runtime. That can't
>> happen with the current version of it.
Easy: use typeof(), i.e., the LIST_FOR_EACH_* macros are updated as follows:
#define LIST_FOR_EACH_ENTRY(pos, head, member) \
for (pos = container_of((head)->next, typeof(pos), member); \
&pos->member != (head); \
pos = container_of(pos->member.next, typeof(pos), member))
In the long term, the container_of/LIST_FOR_EACH mess should go away.
Instead, just implement the clean linux kernel list_for_each
implementation (whence, I presume, the Mesa list is borrowed from).
>> container_of() just has one basic caveat that we can easily satisfy,
>> since like you said, it isn't directly used in many places, and I
>> don't think future problems are actually likely--any misuse will
>> trigger uninitialized warnings like the above so they're easily
>> caught, unlike possible typename mistakes.
Agreed.
Thanks and best regards
Tolga Dalman
More information about the mesa-dev
mailing list