mirror of
https://github.com/git/git
synced 2024-08-25 10:45:59 +00:00
![Jeff King](/assets/img/avatar_default.png)
There's not currently any way to free the resources associated with a decoration struct. As a result, we have several memory leaks which cannot easily be plugged. Let's add a "clear" function and make use of it in the example code of t9004. This removes the only leak from that script, so we can mark it as passing the leak sanitizer. Curiously this leak is found only when running SANITIZE=leak with clang, but not with gcc. But it is a bog-standard leak: we allocate some memory in a local variable struct, and then exit main() without releasing it. I'm not sure why gcc doesn't find it. After this patch, both compilers report it as leak-free. Note that the clear function takes a callback to free the individual entries. That's not needed for our example (which is just decorating with ints), but will be for real callers. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
99 lines
2 KiB
C
99 lines
2 KiB
C
/*
|
|
* decorate.c - decorate a git object with some arbitrary
|
|
* data.
|
|
*/
|
|
#include "git-compat-util.h"
|
|
#include "object.h"
|
|
#include "decorate.h"
|
|
|
|
static unsigned int hash_obj(const struct object *obj, unsigned int n)
|
|
{
|
|
return oidhash(&obj->oid) % n;
|
|
}
|
|
|
|
static void *insert_decoration(struct decoration *n, const struct object *base, void *decoration)
|
|
{
|
|
int size = n->size;
|
|
struct decoration_entry *entries = n->entries;
|
|
unsigned int j = hash_obj(base, size);
|
|
|
|
while (entries[j].base) {
|
|
if (entries[j].base == base) {
|
|
void *old = entries[j].decoration;
|
|
entries[j].decoration = decoration;
|
|
return old;
|
|
}
|
|
if (++j >= size)
|
|
j = 0;
|
|
}
|
|
entries[j].base = base;
|
|
entries[j].decoration = decoration;
|
|
n->nr++;
|
|
return NULL;
|
|
}
|
|
|
|
static void grow_decoration(struct decoration *n)
|
|
{
|
|
int i;
|
|
int old_size = n->size;
|
|
struct decoration_entry *old_entries = n->entries;
|
|
|
|
n->size = (old_size + 1000) * 3 / 2;
|
|
CALLOC_ARRAY(n->entries, n->size);
|
|
n->nr = 0;
|
|
|
|
for (i = 0; i < old_size; i++) {
|
|
const struct object *base = old_entries[i].base;
|
|
void *decoration = old_entries[i].decoration;
|
|
|
|
if (!decoration)
|
|
continue;
|
|
insert_decoration(n, base, decoration);
|
|
}
|
|
free(old_entries);
|
|
}
|
|
|
|
void *add_decoration(struct decoration *n, const struct object *obj,
|
|
void *decoration)
|
|
{
|
|
int nr = n->nr + 1;
|
|
|
|
if (nr > n->size * 2 / 3)
|
|
grow_decoration(n);
|
|
return insert_decoration(n, obj, decoration);
|
|
}
|
|
|
|
void *lookup_decoration(struct decoration *n, const struct object *obj)
|
|
{
|
|
unsigned int j;
|
|
|
|
/* nothing to lookup */
|
|
if (!n->size)
|
|
return NULL;
|
|
j = hash_obj(obj, n->size);
|
|
for (;;) {
|
|
struct decoration_entry *ref = n->entries + j;
|
|
if (ref->base == obj)
|
|
return ref->decoration;
|
|
if (!ref->base)
|
|
return NULL;
|
|
if (++j == n->size)
|
|
j = 0;
|
|
}
|
|
}
|
|
|
|
void clear_decoration(struct decoration *n, void (*free_cb)(void *))
|
|
{
|
|
if (free_cb) {
|
|
unsigned int i;
|
|
for (i = 0; i < n->size; i++) {
|
|
void *d = n->entries[i].decoration;
|
|
if (d)
|
|
free_cb(d);
|
|
}
|
|
}
|
|
|
|
FREE_AND_NULL(n->entries);
|
|
n->size = n->nr = 0;
|
|
}
|