Skip to content

Commit

Permalink
19317: Fixes memory leaks when returning strings from C interface, MI…
Browse files Browse the repository at this point in the history
…NOR (#57)
  • Loading branch information
calebwherry authored Feb 20, 2024
1 parent 5567bcd commit 1d501d7
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 9 deletions.
26 changes: 18 additions & 8 deletions amalgam/api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from ctypes import (
byref, c_bool, c_char, c_char_p, c_double, c_size_t, c_uint64, c_void_p,
byref, cast, c_bool, c_char, c_char_p, c_double, c_size_t, c_uint64, c_void_p,
cdll, POINTER
)
from datetime import datetime
Expand Down Expand Up @@ -479,6 +479,16 @@ def _log_execution(self, execution_string: str) -> None:
self.trace.write(execution_string + "\n")
self.trace.flush()

def _copy_to_bytes(self, p) -> bytes:
"""Copies a native C char* to bytes, cleaning up native memory correctly."""
bytes = cast(p, c_char_p).value

self.amlg.DeleteString.argtypes = c_char_p,
self.amlg.DeleteString.restype = None
self.amlg.DeleteString(p)

return bytes

def gc(self) -> None:
"""Force garbage collection when called if self.force_gc is set."""
if (
Expand Down Expand Up @@ -676,16 +686,16 @@ def execute_entity_json(
bytes
A byte-encoded json representation of the response.
"""
self.amlg.ExecuteEntityJsonPtr.restype = c_char_p
self.amlg.ExecuteEntityJsonPtr.restype = POINTER(c_char)
self.amlg.ExecuteEntityJsonPtr.argtype = [
c_char_p, c_char_p, c_char_p]
handle_buf = self.str_to_char_p(handle)
label_buf = self.str_to_char_p(label)
json_buf = self.str_to_char_p(json)
self._log_time("EXECUTION START")
self._log_execution(f"EXECUTE_ENTITY_JSON {handle} {label} {json}")
result = self.amlg.ExecuteEntityJsonPtr(
handle_buf, label_buf, json_buf)
result = self._copy_to_bytes(self.amlg.ExecuteEntityJsonPtr(
handle_buf, label_buf, json_buf))
self._log_time("EXECUTION STOP")
self._log_reply(result)
del handle_buf
Expand Down Expand Up @@ -881,8 +891,8 @@ def get_version_string(self) -> bytes:
bytes
A version byte-encoded string with semver.
"""
self.amlg.GetVersionString.restype = c_char_p
amlg_version = self.amlg.GetVersionString()
self.amlg.GetVersionString.restype = POINTER(c_char)
amlg_version = self._copy_to_bytes(self.amlg.GetVersionString())
self._log_comment(f"call to amlg.GetVersionString() - returned: "
f"{amlg_version}\n")
return amlg_version
Expand All @@ -897,8 +907,8 @@ def get_concurrency_type_string(self) -> bytes:
A byte-encoded string with library concurrency type.
Ex. b'MultiThreaded'
"""
self.amlg.GetConcurrencyTypeString.restype = c_char_p
amlg_concurrency_type = self.amlg.GetConcurrencyTypeString()
self.amlg.GetConcurrencyTypeString.restype = POINTER(c_char)
amlg_concurrency_type = self._copy_to_bytes(self.amlg.GetConcurrencyTypeString())
self._log_comment(
f"call to amlg.GetConcurrencyTypeString() - returned: "
f"{amlg_concurrency_type}\n")
Expand Down
2 changes: 1 addition & 1 deletion version.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"dependencies": {
"amalgam": "47.1.6"
"amalgam": "47.2.0"
}
}

0 comments on commit 1d501d7

Please sign in to comment.