Skip to content

Commit

Permalink
test: Fix memory leaks in cmark.py
Browse files Browse the repository at this point in the history
Free results of libcmark API function calls.
  • Loading branch information
nwellnhof authored and jgm committed Mar 17, 2024
1 parent fd23ae0 commit dfad5a9
Showing 1 changed file with 33 additions and 7 deletions.
40 changes: 33 additions & 7 deletions test/cmark.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,63 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from ctypes import CDLL, c_char_p, c_size_t, c_int, c_void_p
from ctypes import *
from subprocess import Popen, PIPE
import platform
import os

class cmark_mem(Structure):
_fields_ = [("calloc", c_void_p),
("realloc", c_void_p),
("free", CFUNCTYPE(None, c_void_p))]

def pipe_through_prog(prog, text):
p1 = Popen(prog.split(), stdout=PIPE, stdin=PIPE, stderr=PIPE)
[result, err] = p1.communicate(input=text.encode('utf-8'))
return [p1.returncode, result.decode('utf-8'), err]

def to_html(lib, text):
get_alloc = lib.cmark_get_default_mem_allocator
get_alloc.restype = POINTER(cmark_mem)
free_func = get_alloc().contents.free

markdown = lib.cmark_markdown_to_html
markdown.restype = c_char_p
markdown.restype = POINTER(c_char)
markdown.argtypes = [c_char_p, c_size_t, c_int]

textbytes = text.encode('utf-8')
textlen = len(textbytes)
# 1 << 17 == CMARK_OPT_UNSAFE
result = markdown(textbytes, textlen, 1 << 17).decode('utf-8')
cstring = markdown(textbytes, textlen, 1 << 17)
result = string_at(cstring).decode('utf-8')
free_func(cstring)

return [0, result, '']

def to_commonmark(lib, text):
textbytes = text.encode('utf-8')
textlen = len(textbytes)
get_alloc = lib.cmark_get_default_mem_allocator
get_alloc.restype = POINTER(cmark_mem)
free_func = get_alloc().contents.free

parse_document = lib.cmark_parse_document
parse_document.restype = c_void_p
parse_document.argtypes = [c_char_p, c_size_t, c_int]

render_commonmark = lib.cmark_render_commonmark
render_commonmark.restype = c_char_p
render_commonmark.restype = POINTER(c_char)
render_commonmark.argtypes = [c_void_p, c_int, c_int]

free_node = lib.cmark_node_free
free_node.argtypes = [c_void_p]

textbytes = text.encode('utf-8')
textlen = len(textbytes)
node = parse_document(textbytes, textlen, 0)
result = render_commonmark(node, 0, 0).decode('utf-8')
cstring = render_commonmark(node, 0, 0)
result = string_at(cstring).decode('utf-8')
free_func(cstring)
free_node(node)

return [0, result, '']

class CMark:
Expand Down

0 comments on commit dfad5a9

Please sign in to comment.