使用SWIG包装包含const char *的结构而没有内存泄漏

问题描述 投票:1回答:1

我正在尝试使用SWIG封装一个预先存在的库接口,该接口期望调用方管理某些const char *值的生存期。

struct Settings {
    const char * log_file;
    int log_level;
};

// The Settings struct and all members only need to be valid for the duration of this call.
int Initialize(const struct Settings* settings);
int DoStuff();
int Deinitialize();

我开始使用对SWIG的最基本输入来包装库:

%module lib
%{
#include "lib.h"
%}

%include "lib.h"

这将导致有关可能的内存泄漏的SWIG警告:

lib.h(2) : Warning 451: Setting a const char * variable may leak memory.

[通过观察lib_wrap.c完全可以理解,SWIG生成的代码会将malloc缓冲区放入log_file值,但从不释放它:]


SWIGINTERN PyObject *_wrap_Settings_log_file_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
  PyObject *resultobj = 0;
  struct Settings *arg1 = (struct Settings *) 0 ;
  char *arg2 = (char *) 0 ;
  void *argp1 = 0 ;
  int res1 = 0 ;
  int res2 ;
  char *buf2 = 0 ;
  int alloc2 = 0 ;
  PyObject *swig_obj[2] ;

  if (!SWIG_Python_UnpackTuple(args, "Settings_log_file_set", 2, 2, swig_obj)) SWIG_fail;
  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Settings, 0 |  0 );
  if (!SWIG_IsOK(res1)) {
    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Settings_log_file_set" "', argument " "1"" of type '" "struct Settings *""'"); 
  }
  arg1 = (struct Settings *)(argp1);
  res2 = SWIG_AsCharPtrAndSize(swig_obj[1], &buf2, NULL, &alloc2);
  if (!SWIG_IsOK(res2)) {
    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Settings_log_file_set" "', argument " "2"" of type '" "char const *""'");
  }
  arg2 = (char *)(buf2);
  if (arg2) {
    size_t size = strlen((const char *)((const char *)(arg2))) + 1;
    arg1->log_file = (char const *)(char *)memcpy(malloc((size)*sizeof(char)), arg2, sizeof(char)*(size));
  } else {
    arg1->log_file = 0;
  }
  resultobj = SWIG_Py_Void();
  if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
  return resultobj;
fail:
  if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
  return NULL;
}

如果将log_file的类型更改为char *,则警告消失,并且似乎多次尝试设置log_file的值将不再泄漏内存:

SWIGINTERN PyObject *_wrap_Settings_log_file_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
  PyObject *resultobj = 0;
  struct Settings *arg1 = (struct Settings *) 0 ;
  char *arg2 = (char *) 0 ;
  void *argp1 = 0 ;
  int res1 = 0 ;
  int res2 ;
  char *buf2 = 0 ;
  int alloc2 = 0 ;
  PyObject *swig_obj[2] ;

  if (!SWIG_Python_UnpackTuple(args, "Settings_log_file_set", 2, 2, swig_obj)) SWIG_fail;
  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Settings, 0 |  0 );
  if (!SWIG_IsOK(res1)) {
    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Settings_log_file_set" "', argument " "1"" of type '" "struct Settings *""'"); 
  }
  arg1 = (struct Settings *)(argp1);
  res2 = SWIG_AsCharPtrAndSize(swig_obj[1], &buf2, NULL, &alloc2);
  if (!SWIG_IsOK(res2)) {
    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Settings_log_file_set" "', argument " "2"" of type '" "char *""'");
  }
  arg2 = (char *)(buf2);
  if (arg1->log_file) free((char*)arg1->log_file);
  if (arg2) {
    size_t size = strlen((const char *)(arg2)) + 1;
    arg1->log_file = (char *)(char *)memcpy(malloc((size)*sizeof(char)), (const char *)(arg2), sizeof(char)*(size));
  } else {
    arg1->log_file = 0;
  }
  resultobj = SWIG_Py_Void();
  if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
  return resultobj;
fail:
  if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
  return NULL;
}

但是,当log_file对象在Python中被垃圾回收时,仍然似乎泄漏了为Settings分配的内存。

以避免这些内存泄漏的方式在SWIG中管理char *结构值的生存期的推荐方法是什么?

我正在尝试使用SWIG封装一个预先存在的库接口,该接口期望调用方管理某些const char *值的生存期。结构设置{const char * log_file; int ...

swig
1个回答
0
投票

您可以告诉SWIG对char*使用log_file语义。不幸的是,似乎无法使用Settings::log_file(所需的memberin不会显示在模式匹配中),因此,如果该数据成员名称也与其他类型一起使用,则可能会发生冲突但语义不同。看起来像:

© www.soinside.com 2019 - 2024. All rights reserved.