mirror of
https://github.com/git/git
synced 2024-08-28 20:20:07 +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>
79 lines
2 KiB
C
79 lines
2 KiB
C
#include "test-tool.h"
|
|
#include "git-compat-util.h"
|
|
#include "object.h"
|
|
#include "decorate.h"
|
|
#include "repository.h"
|
|
|
|
int cmd__example_decorate(int argc UNUSED, const char **argv UNUSED)
|
|
{
|
|
struct decoration n;
|
|
struct object_id one_oid = { {1} };
|
|
struct object_id two_oid = { {2} };
|
|
struct object_id three_oid = { {3} };
|
|
struct object *one, *two, *three;
|
|
|
|
int decoration_a, decoration_b;
|
|
|
|
void *ret;
|
|
|
|
int i, objects_noticed = 0;
|
|
|
|
/*
|
|
* The struct must be zero-initialized.
|
|
*/
|
|
memset(&n, 0, sizeof(n));
|
|
|
|
/*
|
|
* Add 2 objects, one with a non-NULL decoration and one with a NULL
|
|
* decoration.
|
|
*/
|
|
one = lookup_unknown_object(the_repository, &one_oid);
|
|
two = lookup_unknown_object(the_repository, &two_oid);
|
|
ret = add_decoration(&n, one, &decoration_a);
|
|
if (ret)
|
|
BUG("when adding a brand-new object, NULL should be returned");
|
|
ret = add_decoration(&n, two, NULL);
|
|
if (ret)
|
|
BUG("when adding a brand-new object, NULL should be returned");
|
|
|
|
/*
|
|
* When re-adding an already existing object, the old decoration is
|
|
* returned.
|
|
*/
|
|
ret = add_decoration(&n, one, NULL);
|
|
if (ret != &decoration_a)
|
|
BUG("when readding an already existing object, existing decoration should be returned");
|
|
ret = add_decoration(&n, two, &decoration_b);
|
|
if (ret)
|
|
BUG("when readding an already existing object, existing decoration should be returned");
|
|
|
|
/*
|
|
* Lookup returns the added declarations, or NULL if the object was
|
|
* never added.
|
|
*/
|
|
ret = lookup_decoration(&n, one);
|
|
if (ret)
|
|
BUG("lookup should return added declaration");
|
|
ret = lookup_decoration(&n, two);
|
|
if (ret != &decoration_b)
|
|
BUG("lookup should return added declaration");
|
|
three = lookup_unknown_object(the_repository, &three_oid);
|
|
ret = lookup_decoration(&n, three);
|
|
if (ret)
|
|
BUG("lookup for unknown object should return NULL");
|
|
|
|
/*
|
|
* The user can also loop through all entries.
|
|
*/
|
|
for (i = 0; i < n.size; i++) {
|
|
if (n.entries[i].base)
|
|
objects_noticed++;
|
|
}
|
|
if (objects_noticed != 2)
|
|
BUG("should have 2 objects");
|
|
|
|
clear_decoration(&n, NULL);
|
|
|
|
return 0;
|
|
}
|