LibXML 2封装在Python/ctypes中时无法释放内存

pzfprimi  于 2023-05-05  发布在  Python
关注(0)|答案(1)|浏览(134)

我的Python脚本是:

def xmlEncodeSpecialChars(doc: xmlDoc, input: str) -> str:
    '''
    Do a global encoding of a string, replacing the predefined entities this routine is reentrant, and result must be deallocated.

        doc:        the document containing the string
        input:      A string to convert to XML.
        Returns:    A newly allocated string with the substitution done.'''
        
    libXML = LibXML2() # DSO/DLL 

    libXML.xmlEncodeSpecialChars.restype = ctypes.c_char_p
    libXML.xmlEncodeSpecialChars.argtypes = ctypes.c_void_p, ctypes.c_char_p, 

    output: ctypes.c_char_p = libXML.xmlEncodeSpecialChars(doc, input.encode()); 
    Err = xmlGetLastError()
    if Err: raise LibErr(Err)
    ans = output.decode()
# free memory
    libXML.xmlMemFree.argtypes = ctypes.c_char_p, ;
    libXML.xmlMemFree(output)
    
    return ans

它正确地返回了一个转义字符串,但是xmlMemFree()在Python中生成了一个Memory tag error,尽管对同一DLL的等效C调用也可以正常工作。
如何设置ctypes内存释放操作?
---编辑---
最低可复制(Linux)设置为:

def xmlEncodeSpecialChars(doc: xmlDoc, input: str) -> str:
    '''
    Do a global encoding of a string, replacing the predefined entities this routine is reentrant, and result must be deallocated.

        doc:        the document containing the string
        input:      A string to convert to XML.
        Returns:    A newly allocated string with the substitution done.'''
    
    libXML = ctypes.CDLL ("libxml2.so.2") # DSO/DLL 

    libXML.xmlEncodeSpecialChars.restype = ctypes.c_void_p
    libXML.xmlEncodeSpecialChars.argtypes = ctypes.c_void_p, ctypes.c_char_p, 

    output: ctypes.c_void_p = libXML.xmlEncodeSpecialChars(doc, input.encode()); 

    Err = xmlGetLastError() #   check for library error
    if Err: raise LibErr(Err)

    ans = ctypes.cast(output, ctypes.c_char_p).value.decode()                   #   convert to Python str

    libXML.xmlMemFree.argtypes = ctypes.c_void_p, ;libXML.xmlMemFree(output);   #   free memory, FIXME

    return ans

print(xmlEncodeSpecialChars(None, "<root>Some text with < and > characters</root>"))
kr98yfug

kr98yfug1#

ctypes中,c_char_p转换以null结尾的C char*并返回Python bytes对象。指针丢失。
使用c_void_pPOINTER(c_char)来维护指针。string_at可用于读取返回地址处的空终止字符串。
未测试:

def xmlEncodeSpecialChars(doc: xmlDoc, input: str) -> str:
    '''
    Do a global encoding of a string, replacing the predefined entities this routine is reentrant, and result must be deallocated.

        doc:        the document containing the string
        input:      A string to convert to XML.
        Returns:    A newly allocated string with the substitution done.'''
    libXML = LibXML2() # DSO/DLL 

    libXML.xmlEncodeSpecialChars.restype = ctypes.c_void_p
    libXML.xmlEncodeSpecialChars.argtypes = ctypes.c_void_p, ctypes.c_char_p

    output: ctypes.c_void_p = libXML.xmlEncodeSpecialChars(doc, input.encode())
    Err = xmlGetLastError()
    if Err: raise LibErr(Err)
    ans = ctypes.string_at(output).decode()
# free memory
    libXML.xmlMemFree.argtypes = ctypes.c_void_p,
    libXML.xmlMemFree.restype = None
    libXML.xmlMemFree(output)
    return ans

相关问题