Commit 585b5dac by Patrick Steinhardt

refcount: make refcounting conform to aliasing rules

Strict aliasing rules dictate that for most data types, you are not
allowed to cast them to another data type and then access the casted
pointers. While this works just fine for most compilers, technically we
end up in undefined behaviour when we hurt that rule.

Our current refcounting code makes heavy use of casting and thus
violates that rule. While we didn't have any problems with that code,
Travis started spitting out a lot of warnings due to a change in their
toolchain. In the refcounting case, the code is also easy to fix:
as all refcounting-statements are actually macros, we can just access
the `rc` field directly instead of casting.

There are two outliers in our code where that doesn't work. Both the
`git_diff` and `git_patch` structures have specializations for generated
and parsed diffs/patches, which directly inherit from them. Because of
that, the refcounting code is only part of the base structure and not of
the children themselves. We can help that by instead passing their base
into `GIT_REFCOUNT_INC`, though.
parent fd1492e8
......@@ -411,7 +411,7 @@ static git_diff_generated *diff_generated_alloc(
if ((diff = git__calloc(1, sizeof(git_diff_generated))) == NULL)
return NULL;
GIT_REFCOUNT_INC(diff);
GIT_REFCOUNT_INC(&diff->base);
diff->base.type = GIT_DIFF_TYPE_GENERATED;
diff->base.repo = repo;
diff->base.old_src = old_iter->type;
......
......@@ -36,7 +36,7 @@ static git_diff_parsed *diff_parsed_alloc(void)
if ((diff = git__calloc(1, sizeof(git_diff_parsed))) == NULL)
return NULL;
GIT_REFCOUNT_INC(diff);
GIT_REFCOUNT_INC(&diff->base);
diff->base.type = GIT_DIFF_TYPE_PARSED;
diff->base.strcomp = git__strcmp;
diff->base.strncomp = git__strncmp;
......
......@@ -139,7 +139,7 @@ static int patch_generated_alloc_from_diff(
if (!(error = patch_generated_init(patch, diff, delta_index))) {
patch->flags |= GIT_PATCH_GENERATED_ALLOCATED;
GIT_REFCOUNT_INC(patch);
GIT_REFCOUNT_INC(&patch->base);
} else {
git__free(patch);
patch = NULL;
......
......@@ -1084,7 +1084,7 @@ int git_patch_parse(
patch->base.diff_opts.new_prefix = patch->new_prefix;
patch->base.diff_opts.flags |= GIT_DIFF_SHOW_BINARY;
GIT_REFCOUNT_INC(patch);
GIT_REFCOUNT_INC(&patch->base);
*out = &patch->base;
done:
......
......@@ -10,7 +10,6 @@
#include <ctype.h>
#include "git2/object.h"
#include "git2/refdb.h"
#include "git2/sys/repository.h"
#include "common.h"
......@@ -25,6 +24,7 @@
#include "refs.h"
#include "filter.h"
#include "odb.h"
#include "refdb.h"
#include "remote.h"
#include "merge.h"
#include "diff_driver.h"
......
......@@ -297,22 +297,22 @@ typedef struct {
typedef void (*git_refcount_freeptr)(void *r);
#define GIT_REFCOUNT_INC(r) { \
git_atomic_inc(&((git_refcount *)(r))->refcount); \
git_atomic_inc(&(r)->rc.refcount); \
}
#define GIT_REFCOUNT_DEC(_r, do_free) { \
git_refcount *r = (git_refcount *)(_r); \
git_refcount *r = &(_r)->rc; \
int val = git_atomic_dec(&r->refcount); \
if (val <= 0 && r->owner == NULL) { do_free(_r); } \
}
#define GIT_REFCOUNT_OWN(r, o) { \
((git_refcount *)(r))->owner = o; \
(r)->rc.owner = o; \
}
#define GIT_REFCOUNT_OWNER(r) (((git_refcount *)(r))->owner)
#define GIT_REFCOUNT_OWNER(r) ((r)->rc.owner)
#define GIT_REFCOUNT_VAL(r) git_atomic_get(&((git_refcount *)(r))->refcount)
#define GIT_REFCOUNT_VAL(r) git_atomic_get((r)->rc.refcount)
static signed char from_hex[] = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment