Skip to content

Commit eb01c79

Browse files
committed
ConfigEntry: keep a reference to ConfigIterator
So git_config_iterator_free is only called when all the config entries are deleted. Because as stated in https://libgit2.org/libgit2/#HEAD/group/config/git_config_next "The pointers returned by this function are valid until the iterator is freed." Unfortunately this is not enough, through iteration the pointers in the git_config_entry struct become invalid. So the statement above in libgit2's documentation looks wrong, the pointers are invalid earlier.
1 parent 82e9c75 commit eb01c79

File tree

1 file changed

+29
-31
lines changed

1 file changed

+29
-31
lines changed

pygit2/config.py

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,13 @@ def _next_entry(self):
5151
err = C.git_config_next(centry, self._iter)
5252
check_error(err)
5353

54-
return ConfigEntry._from_c(centry[0], True)
54+
return ConfigEntry._from_c(centry[0], self)
5555

5656
def next(self):
5757
return self.__next__()
5858

5959
def __next__(self):
60-
entry = self._next_entry()
61-
return entry
60+
return self._next_entry()
6261

6362

6463
class ConfigMultivarIterator(ConfigIterator):
@@ -193,7 +192,7 @@ def get_bool(self, key):
193192

194193
entry = self._get_entry(key)
195194
res = ffi.new('int *')
196-
err = C.git_config_parse_bool(res, entry.raw_value)
195+
err = C.git_config_parse_bool(res, entry.c_value)
197196
check_error(err)
198197

199198
return res[0] != 0
@@ -208,7 +207,7 @@ def get_int(self, key):
208207

209208
entry = self._get_entry(key)
210209
res = ffi.new('int64_t *')
211-
err = C.git_config_parse_int64(res, entry.raw_value)
210+
err = C.git_config_parse_int64(res, entry.c_value)
212211
check_error(err)
213212

214213
return res[0]
@@ -289,46 +288,45 @@ class ConfigEntry(object):
289288
"""
290289

291290
@classmethod
292-
def _from_c(cls, ptr, from_iterator=False):
293-
"""Builds the entry from a ``git_config_entry`` pointer. ``from_iterator``
294-
should be ``True`` when the entry was created during ``git_config_iterator``
295-
actions
291+
def _from_c(cls, ptr, iterator=None):
292+
"""Builds the entry from a ``git_config_entry`` pointer.
293+
294+
``iterator`` must be a ``ConfigIterator`` instance if the entry was
295+
created during ``git_config_iterator`` actions.
296296
"""
297297
entry = cls.__new__(cls)
298298
entry._entry = ptr
299-
entry.from_iterator = from_iterator
299+
entry.iterator = iterator
300300
return entry
301301

302302
def __del__(self):
303-
if not self.from_iterator:
303+
if self.iterator is None:
304304
C.git_config_entry_free(self._entry)
305305

306+
@property
307+
def c_value(self):
308+
"""The raw ``cData`` entry value."""
309+
return self._entry.value
310+
311+
@property
312+
def raw_value(self):
313+
return ffi.string(self.c_value)
314+
306315
@property
307316
def value(self):
308-
"""The entry's value as a string
309-
"""
310-
return self.decode_as_string(self._entry.value)
317+
"""The entry's value as a string."""
318+
return self.raw_value.decode('utf-8')
311319

312320
@property
313-
def level(self):
314-
"""The entry's ``git_config_level_t`` value
315-
"""
316-
return self._entry.level
321+
def raw_name(self):
322+
return ffi.string(self._entry.name)
317323

318324
@property
319325
def name(self):
320-
"""The entry's name
321-
"""
322-
return self.decode_as_string(self._entry.name)
326+
"""The entry's name."""
327+
return self.raw_name.decode('utf-8')
323328

324329
@property
325-
def raw_value(self):
326-
"""The raw ``cData`` entry value
327-
"""
328-
return self._entry.value
329-
330-
@staticmethod
331-
def decode_as_string(value):
332-
"""Returns ``value`` as a decoded ``utf-8`` string.
333-
"""
334-
return ffi.string(value).decode('utf-8')
330+
def level(self):
331+
"""The entry's ``git_config_level_t`` value."""
332+
return self._entry.level

0 commit comments

Comments
 (0)