Skip to content

Safer handling of string arrays #487

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 6, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions pygit2/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from _pygit2 import Oid, Tree, Diff
from .errors import check_error
from .ffi import ffi, C
from .utils import is_string, strings_to_strarray, to_bytes, to_str
from .utils import is_string, to_bytes, to_str, StrArray


class Index(object):
Expand Down Expand Up @@ -175,9 +175,9 @@ def add_all(self, pathspecs=[]):
If pathspecs are specified, only files matching those pathspecs will
be added.
"""
arr, refs = strings_to_strarray(pathspecs)
err = C.git_index_add_all(self._index, arr, 0, ffi.NULL, ffi.NULL)
check_error(err, True)
with StrArray(pathspecs) as arr:
err = C.git_index_add_all(self._index, arr, 0, ffi.NULL, ffi.NULL)
check_error(err, True)

def add(self, path_or_entry):
"""add([path|entry])
Expand Down
20 changes: 10 additions & 10 deletions pygit2/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from .ffi import ffi, C
from .credentials import KeypairFromAgent
from .refspec import Refspec
from .utils import to_bytes, strarray_to_strings, strings_to_strarray
from .utils import to_bytes, strarray_to_strings, StrArray


def maybe_string(ptr):
Expand Down Expand Up @@ -253,9 +253,9 @@ def fetch_refspecs(self):

@fetch_refspecs.setter
def fetch_refspecs(self, l):
arr, refs = strings_to_strarray(l)
err = C.git_remote_set_fetch_refspecs(self._remote, arr)
check_error(err)
with StrArray(l) as arr:
err = C.git_remote_set_fetch_refspecs(self._remote, arr)
check_error(err)

@property
def push_refspecs(self):
Expand All @@ -269,9 +269,9 @@ def push_refspecs(self):

@push_refspecs.setter
def push_refspecs(self, l):
arr, refs = strings_to_strarray(l)
err = C.git_remote_set_push_refspecs(self._remote, arr)
check_error(err)
with StrArray(l) as arr:
err = C.git_remote_set_push_refspecs(self._remote, arr)
check_error(err)

def add_fetch(self, spec):
"""add_fetch(refspec)
Expand Down Expand Up @@ -305,7 +305,6 @@ def push(self, specs, signature=None, message=None):
err = C.git_remote_init_callbacks(defaultcallbacks, 1)
check_error(err)

refspecs, refspecs_refs = strings_to_strarray(specs)
if signature:
sig_cptr = ffi.new('git_signature **')
ffi.buffer(sig_cptr)[:] = signature._pointer[:]
Expand Down Expand Up @@ -333,8 +332,9 @@ def push(self, specs, signature=None, message=None):
raise

try:
err = C.git_remote_push(self._remote, refspecs, ffi.NULL, sig_ptr, to_bytes(message))
check_error(err)
with StrArray(specs) as refspecs:
err = C.git_remote_push(self._remote, refspecs, ffi.NULL, sig_ptr, to_bytes(message))
check_error(err)
finally:
self._self_handle = None

Expand Down
46 changes: 23 additions & 23 deletions pygit2/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,34 +50,34 @@ def strarray_to_strings(arr):
return l


def strings_to_strarray(l):
"""Convert a list of strings to a git_strarray
class StrArray(object):
"""A git_strarray wrapper

We return first the git_strarray* you can pass to libgit2 and a
list of references to the memory, which we must keep around for as
long as the git_strarray must live.
"""
Use this in order to get a git_strarray* to pass to libgit2 out of a
list of strings. This has a context manager, which you should use, e.g.

if not isinstance(l, list):
raise TypeError("Value must be a list")
with StrArray(list_of_strings) as arr:
C.git_function_that_takes_strarray(arr)
"""

arr = ffi.new('git_strarray *')
strings = ffi.new('char *[]', len(l))
def __init__(self, l):
if not isinstance(l, list):
raise TypeError("Value must be a list")

# We need refs in order to keep a reference to the value returned
# by the ffi.new(). Otherwise, they will be freed and the memory
# re-used, with less than great consequences.
refs = [None] * len(l)
arr = ffi.new('git_strarray *')
strings = [None] * len(l)
for i in range(len(l)):
if not is_string(l[i]):
raise TypeError("Value must be a string")

for i in range(len(l)):
if not is_string(l[i]):
raise TypeError("Value must be a string")
strings[i] = ffi.new('char []', to_bytes(l[i]))

s = ffi.new('char []', to_bytes(l[i]))
refs[i] = s
strings[i] = s
self._arr = ffi.new('char *[]', strings)
self._strings = strings
self.array = ffi.new('git_strarray *', [self._arr, len(strings)])

arr.strings = strings
arr.count = len(l)
def __enter__(self):
return self.array

return arr, refs
def __exit__(self, type, value, traceback):
pass