From 27585e534434896a404eda728e4ae2cc558c6620 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=2E=20David=20Ib=C3=A1=C3=B1ez?= <jdavid.ibp@gmail.com>
Date: Sat, 17 Mar 2012 17:55:41 +0100
Subject: [PATCH] Fixing TreeEntry lifetime issues

Now a TreeEntry can be owned by a Tree or a TreeBuilder, this should
handle the lifetime issues reported by Han-Wen Nienhuys.

Discussion in issue #56
---
 pygit2.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/pygit2.c b/pygit2.c
index 1b25851..d0b8877 100644
--- a/pygit2.c
+++ b/pygit2.c
@@ -110,7 +110,12 @@ OBJECT_STRUCT(Blob, git_blob, blob)
 OBJECT_STRUCT(Tag, git_tag, tag)
 OBJECT_STRUCT(Index, git_index, index)
 OBJECT_STRUCT(Walker, git_revwalk, walk)
-OBJECT_STRUCT(TreeEntry, git_tree_entry, entry)
+
+typedef struct {
+    PyObject_HEAD
+    PyObject *owner; /* Tree or TreeBuilder */
+    const git_tree_entry *entry;
+} TreeEntry;
 
 typedef struct {
     PyObject_HEAD
@@ -1418,7 +1423,7 @@ static PyTypeObject CommitType = {
 static void
 TreeEntry_dealloc(TreeEntry *self)
 {
-    Py_XDECREF(self->repo);
+    Py_XDECREF(self->owner);
     PyObject_Del(self);
 }
 
@@ -1453,9 +1458,11 @@ static PyObject *
 TreeEntry_to_object(TreeEntry *self)
 {
     const git_oid *entry_oid;
+    Repository *repo;
 
+    repo = ((Object*)(self->owner))->repo;
     entry_oid = git_tree_entry_id(self->entry);
-    return lookup_object(self->repo, entry_oid, GIT_OBJ_ANY);
+    return lookup_object(repo, entry_oid, GIT_OBJ_ANY);
 }
 
 static PyGetSetDef TreeEntry_getseters[] = {
@@ -1533,15 +1540,15 @@ Tree_contains(Tree *self, PyObject *py_name)
 }
 
 static TreeEntry *
-wrap_tree_entry(const git_tree_entry *entry, Repository *repo)
+wrap_tree_entry(const git_tree_entry *entry, Tree *tree)
 {
     TreeEntry *py_entry;
 
     py_entry = PyObject_New(TreeEntry, &TreeEntryType);
     if (py_entry) {
         py_entry->entry = entry;
-        py_entry->repo = repo;
-        Py_INCREF(repo);
+        py_entry->owner = (PyObject*)tree;
+        Py_INCREF(tree);
     }
     return py_entry;
 }
@@ -1604,7 +1611,7 @@ Tree_getitem_by_index(Tree *self, PyObject *py_index)
         PyErr_SetObject(PyExc_IndexError, py_index);
         return NULL;
     }
-    return wrap_tree_entry(entry, self->repo);
+    return wrap_tree_entry(entry, self);
 }
 
 static TreeEntry *
@@ -1626,7 +1633,7 @@ Tree_getitem(Tree *self, PyObject *value)
         PyErr_SetObject(PyExc_KeyError, value);
         return NULL;
     }
-    return wrap_tree_entry(entry, self->repo);
+    return wrap_tree_entry(entry, self);
 }
 
 static PySequenceMethods Tree_as_sequence = {
@@ -1822,7 +1829,7 @@ TreeIter_iternext(TreeIter *self)
         return NULL;
 
     self->i += 1;
-    return (TreeEntry*)wrap_tree_entry(tree_entry, self->owner->repo);
+    return (TreeEntry*)wrap_tree_entry(tree_entry, self->owner);
 }
 
 static PyTypeObject TreeIterType = {