summaryrefslogtreecommitdiff
path: root/jq.pyx
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2020-04-18 07:31:03 +0100
committerMichael Williamson <mike@zwobble.org>2020-04-18 07:31:03 +0100
commit63e23c1559066d46a45d05c6e258578274bc522d (patch)
tree5ba1a5b20473ee8752fe95500000ece038b4d5b8 /jq.pyx
parentbf0a7d295812b50ad260f170b1d9521b09022c8c (diff)
Fix memory leaks
Diffstat (limited to 'jq.pyx')
-rw-r--r--jq.pyx80
1 files changed, 45 insertions, 35 deletions
diff --git a/jq.pyx b/jq.pyx
index 2da5f41..1bd443e 100644
--- a/jq.pyx
+++ b/jq.pyx
@@ -14,7 +14,7 @@ cdef extern from "jv.h":
ctypedef struct jv:
pass
-
+
jv_kind jv_get_kind(jv)
int jv_is_valid(jv)
jv jv_copy(jv)
@@ -23,10 +23,10 @@ cdef extern from "jv.h":
int jv_invalid_has_msg(jv)
char* jv_string_value(jv)
jv jv_dump_string(jv, int flags)
-
+
cdef struct jv_parser:
pass
-
+
jv_parser* jv_parser_new(int)
void jv_parser_free(jv_parser*)
void jv_parser_set_buf(jv_parser*, const char*, int, int)
@@ -36,9 +36,9 @@ cdef extern from "jv.h":
cdef extern from "jq.h":
ctypedef struct jq_state:
pass
-
+
ctypedef void (*jq_err_cb)(void *, jv)
-
+
jq_state *jq_init()
void jq_teardown(jq_state **)
int jq_compile(jq_state *, const char* str)
@@ -46,7 +46,7 @@ cdef extern from "jq.h":
jv jq_next(jq_state *)
void jq_set_error_cb(jq_state *, jq_err_cb, void *)
void jq_get_error_cb(jq_state *, jq_err_cb *, void **)
-
+
def jq(object program):
cdef object program_bytes_obj = program.encode("utf8")
@@ -54,20 +54,28 @@ def jq(object program):
cdef jq_state *jq = jq_init()
if not jq:
raise Exception("jq_init failed")
-
- cdef _ErrorStore error_store = _ErrorStore.__new__(_ErrorStore)
- error_store.clear()
-
- jq_set_error_cb(jq, store_error, <void*>error_store)
-
- cdef int compiled = jq_compile(jq, program_bytes)
-
- if error_store.has_errors():
- raise ValueError(error_store.error_string())
-
- if not compiled:
- raise ValueError("program was not valid")
-
+
+ cdef _ErrorStore error_store
+ cdef int compiled
+
+ try:
+ error_store = _ErrorStore.__new__(_ErrorStore)
+ error_store.clear()
+
+ jq_set_error_cb(jq, store_error, <void*>error_store)
+
+ compiled = jq_compile(jq, program_bytes)
+
+ if error_store.has_errors():
+ raise ValueError(error_store.error_string())
+
+ if not compiled:
+ raise ValueError("program was not valid")
+
+ except:
+ jq_teardown(&jq)
+ raise
+
cdef _Program wrapped_program = _Program.__new__(_Program)
wrapped_program._jq = jq
wrapped_program._error_store = error_store
@@ -80,19 +88,21 @@ cdef void store_error(void* store_ptr, jv error):
if jv_get_kind(error) == JV_KIND_STRING:
store.store_error(jv_string_value(error))
+ jv_free(error)
+
cdef class _ErrorStore(object):
cdef object _errors
-
+
cdef int has_errors(self):
return len(self._errors)
-
+
cdef object error_string(self):
return "\n".join(self._errors)
-
+
cdef void store_error(self, char* error):
self._errors.append(error.decode("utf8"))
-
+
cdef void clear(self):
self._errors = []
@@ -108,20 +118,20 @@ cdef class _Program(object):
def __dealloc__(self):
jq_teardown(&self._jq)
-
+
def transform(self, value=_NO_VALUE, text=_NO_VALUE, text_output=False, multiple_output=False):
if (value is _NO_VALUE) == (text is _NO_VALUE):
raise ValueError("Either the value or text argument should be set")
string_input = text if text is not _NO_VALUE else json.dumps(value)
bytes_input = string_input.encode("utf8")
-
+
self._error_store.clear()
-
+
result_bytes = self._string_to_strings(bytes_input)
-
+
if self._error_store.has_errors():
raise ValueError(self._error_store.error_string())
-
+
result_strings = map(lambda s: s.decode("utf8"), result_bytes)
if text_output:
return "\n".join(result_strings)
@@ -143,11 +153,11 @@ cdef class _Program(object):
else:
self._handle_invalid_jv(value, b"parse error: ")
break
-
+
jv_parser_free(parser)
-
+
return results
-
+
cdef void _handle_invalid_jv(self, jv value, char* prefix):
if jv_invalid_has_msg(jv_copy(value)):
error_message = jv_invalid_get_msg(value)
@@ -156,17 +166,17 @@ cdef class _Program(object):
jv_free(error_message)
else:
jv_free(value)
-
+
cdef void _process(self, jv value, object output):
cdef int jq_flags = 0
-
+
jq_start(self._jq, value, jq_flags);
cdef jv result
cdef int dumpopts = 0
cdef jv dumped
-
+
while True:
result = jq_next(self._jq)
if not jv_is_valid(result):