Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

pks-t
Copy link
Member

@pks-t pks-t commented Mar 2, 2018

In some parts of our code, we make rather heavy use of downcasting
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 2424e64 (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_DOWNCAST 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
parent 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. This is simply done by verifying that the offset of the
    member in the target structure is 0.

In case either of the above two conditions is not fulfilled, an assert
is triggered. Furthermore, these checks do not make use of any
information not known at compile type. As such, the macro should get
optimized away at compile time and have no overhead in case the cast can
be done.

Convert one instance of upcasting to use this new macro as a proof of
concept. This instance is the one that was fixed with 2424e64 --
reverting the change and upcasting to the wrong type does indeed trigger
an assert at runtime. This demonstrates that the error would've been
detected earlier if the new macro had existed back then and was used.

@pks-t
Copy link
Member Author

pks-t commented Mar 22, 2018

I've improved upon the implementation. As this PR is already using compiler-builtins in case __GNUC__ is defined, there really is no reason to not go for the complete thing and provide compile-time errors. The amended PR now makes use of __builtin_choose_expr, and either chooses the "correct" cast expression or chooses an expression which results in a compiler error. Like this, we have compile-time sanity checks for downcasting on GCC and Clang.

@tiennou
Copy link
Contributor

tiennou commented Jun 22, 2018

See 102c52d, which takes care of downcasts in transports and refdb_fs.

@pks-t pks-t force-pushed the pks/downcasting branch from 605b98a to 3744449 Compare July 6, 2018 08:44
@pks-t
Copy link
Member Author

pks-t commented Jul 6, 2018 via email

@tiennou
Copy link
Contributor

tiennou commented Apr 5, 2019

I just found another potential user, so here's a rebased branch: master...tiennou:pks/downcasting.

pks-t and others added 5 commits April 16, 2019 13:21
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 2424e64 (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.
@pks-t pks-t force-pushed the pks/downcasting branch from 3744449 to 431601f Compare April 16, 2019 11:22
@pks-t
Copy link
Member Author

pks-t commented Apr 16, 2019

Thanks, @tiennou, I've adopted your branch.

I did make one major change, though: instead of GIT_DOWNCAST, I've renamed the macro to GIT_CONTAINER_OF. I've realized that the macro does essentially the same thing as container_of in linux.git, and I think that container_of is a lot easier to grasp on first sight than downcast.

@pks-t
Copy link
Member Author

pks-t commented Apr 26, 2019

@tiennou: want to have another look so that we can get this merged?

@tiennou
Copy link
Contributor

tiennou commented Apr 26, 2019

I'm fine with the rename, so unless you need a real look, I should still fine with the rest of the changes 😉. That makes me commutative or something, right ? 🤣

@pks-t
Copy link
Member Author

pks-t commented Apr 26, 2019

You want to approve this PR, then, asOtherwise I'm not allowed to merge? So no, you're not commutative :P

@tiennou tiennou self-requested a review April 26, 2019 15:02
Copy link
Contributor

@tiennou tiennou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Damn, my reasoning was wrong ?? I'm fine with those changes, thanks for the cleanup @pks-t !

@ethomson ethomson self-requested a review April 26, 2019 15:25
@pks-t pks-t merged commit bc5b19e into libgit2:master Apr 29, 2019
@pks-t pks-t deleted the pks/downcasting branch April 29, 2019 07:01
@pks-t
Copy link
Member Author

pks-t commented Apr 29, 2019

Thanks to both of you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants