diff options
author | Patrick Steinhardt <ps@pks.im> | 2019-04-16 13:21:03 +0200 |
---|---|---|
committer | Patrick Steinhardt <ps@pks.im> | 2019-04-16 13:21:03 +0200 |
commit | b5f40441f51b091cf34e33153271fbaee133ddc2 (patch) | |
tree | 36589425416369e871a5e05cc2e486eb24056218 /src/commit.c | |
parent | ed959ca2f158862a59584cbfa0d39a845419f514 (diff) | |
download | libgit2-b5f40441f51b091cf34e33153271fbaee133ddc2.tar.gz |
util: introduce GIT_CONTAINER_OF macro
In some parts of our code, we make rather heavy use of casting
structures to their respective specialized implementation. One
example is the configuration code with the general
`git_config_backend` and the specialized `diskfile_header`
structures. At some occasions, it can get confusing though with
regards to the correct inheritance structure, which led to the
recent bug fixed in 2424e64c4 (config: harden our use of the
backend objects a bit, 2018-02-28).
Object-oriented programming in C is hard, but we can at least try
to have some checks when it comes to casting around stuff. Thus,
this commit introduces a `GIT_CONTAINER_OF` macro, which accepts
as parameters the pointer that is to be casted, the pointer it
should be cast to as well as the member inside of the target
structure that is the containing structure. This macro then tries
hard to detect mis-casts:
- It checks whether the source and target pointers are of the
same type. This requires support by the compiler, as it makes
use of the builtin `__builtin_types_compatible_p`.
- It checks whether the embedded member of the target structure
is the first member. In order to make this a compile-time
constant, the compiler-provided `__builtin_offsetof` is being
used for this.
- It ties these two checks together by the compiler-builtin
`__builtin_choose_expr`. Based on whether the previous two
checks evaluate to `true`, the compiler will either compile in
the correct cast, or it will output `(void)0`. The second case
results in a compiler error, resulting in a compile-time check
for wrong casts.
The only downside to this is that it relies heavily on
compiler-specific extensions. As both GCC and Clang support these
features, only define this macro like explained above in case
`__GNUC__` is set (Clang also defines `__GNUC__`). If the
compiler is not Clang or GCC, just go with a simple cast without
any additional checks.
Diffstat (limited to 'src/commit.c')
0 files changed, 0 insertions, 0 deletions