diff options
| author | Michael Williamson <mike@zwobble.org> | 2020-04-18 07:31:03 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2020-04-18 07:31:03 +0100 |
| commit | 63e23c1559066d46a45d05c6e258578274bc522d (patch) | |
| tree | 5ba1a5b20473ee8752fe95500000ece038b4d5b8 | |
| parent | bf0a7d295812b50ad260f170b1d9521b09022c8c (diff) | |
Fix memory leaks
| -rw-r--r-- | jq.pyx | 80 |
1 files changed, 45 insertions, 35 deletions
@@ -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): |
