Proper way to free a pointer array in SWIG input typemap?

我的梦境 提交于 2019-12-02 14:06:56

问题


Hi I'm trying to wrap the following function using SWIG.

static void readTable(int argc, t_atom *argv) { //accepts table in Lua e.g. readTable({"ab",3});

        for (int i=0; i<argc; ++i) {

            if (argv[i].a_type == A_FLOAT)
                printf("FLOAT : %g\n", argv[i].a_w.w_float);
            else if (argv[i].a_type == A_SYMBOL)
                printf("SYMBOL : %s\n", argv[i].a_w.w_symbol->s_name);
        }
    }

Here's the typemap I created.

%include "exception.i"
%typemap(in) (int argc, t_atom *argv)
{
    if (!lua_istable(L, 1)) {
      SWIG_exception(SWIG_RuntimeError, "argument mismatch: table expected");
    }
    lua_len(L, 1);
    $1 = lua_tointeger(L, -1);
    $2 = (t_atom *)getbytes($1 * sizeof(t_atom)); //internally calls calloc()

    for (int i=0; i<$1; ++i) {

        lua_pushinteger(L, i+1);
        lua_gettable(L, 1);

        if(lua_isnumber(L, -1)) {

            $2[i].a_type = A_FLOAT;
            $2[i].a_w.w_float = lua_tonumber(L, -1);
        }          
        else if(lua_isstring(L, -1)) {

            $2[i].a_type = A_SYMBOL;
            $2[i].a_w.w_symbol = gensym(lua_tostring(L, -1));
        }
    }
    freebytes($2, $1 * sizeof(t_atom)); //internally calls free()
}

As you can see, I allocate memory for an array using getbytes() which internally calls calloc() and free the memory using freebytes() which internally calls free().

Surprisingly, when I call readTable() function in Lua, it works fine without crashing.

for example, calling test.readTable({3, "abc"}) in Lua prints the following result.

FLOAT : 3
SYMBOL : abc

My questions are

a) How can readTable() print results without crashing when I freed the memory in SWIG interface? Maybe memory is not being properly freed?

b) If a) doesn't make sense or is not safe to use, would you recommend calling the freebytes() inside the function readTable() instead so it can be like the following?

static void readTable(int argc, t_atom *argv) {

        for (int i=0; i<argc; ++i) {

            if (argv[i].a_type == A_FLOAT)
                post("FLOAT : %g", argv[i].a_w.w_float);
            else if (argv[i].a_type == A_SYMBOL)
                post("SYMBOL : %s", argv[i].a_w.w_symbol->s_name);
        }
        freebytes(argv, argc * sizeof(t_atom));
    }

回答1:


That is exactly the situation which %typemap(freearg) is for.

%include "exception.i"

%typemap(in) (int argc, t_atom *argv) {
    if (!lua_istable(L, $input)) {
        SWIG_exception(SWIG_RuntimeError, "argument mismatch: table expected");
    }
    lua_len(L, $input);
    $1 = lua_tointeger(L, -1);
    $2 = (t_atom *)getbytes($1 * sizeof(t_atom)); // internally calls calloc()

    for (int i = 0; i < $1; ++i) {

        lua_pushinteger(L, i + 1);
        lua_gettable(L, $input);

        if (lua_isnumber(L, -1)) {
            $2[i].a_type = A_FLOAT;
            $2[i].a_w.w_float = lua_tonumber(L, -1);
        } else if (lua_isstring(L, -1)) {
            $2[i].a_type = A_SYMBOL;
            $2[i].a_w.w_symbol = gensym(lua_tostring(L, -1));
        } else {
            SWIG_exception(SWIG_RuntimeError, "unhandled argument type");
        }
    }
}

%typemap(freearg) (int argc, t_atom *argv) {
    freebytes($2, $1 * sizeof(t_atom)); // internally calls free()
}

static void readTable(const std::string &name, int argc, t_atom *argv);

This is the generated code from SWIG 3.0

static int _wrap_readTable(lua_State* L) {
  int SWIG_arg = 0;
  std::string *arg1 = 0 ;
  int arg2 ;
  t_atom *arg3 = (t_atom *) 0 ;

  SWIG_check_num_args("readTable",2,2)
  if(!lua_isuserdata(L,1)) SWIG_fail_arg("readTable",1,"std::string const &");

  if (!SWIG_IsOK(SWIG_ConvertPtr(L,1,(void**)&arg1,SWIGTYPE_p_std__string,0))){
    SWIG_fail_ptr("readTable",1,SWIGTYPE_p_std__string);
  }

  {
    if (!lua_istable(L, 2)) {
      SWIG_exception(SWIG_RuntimeError, "argument mismatch: table expected");
    }
    lua_len(L, 2);
    arg2 = lua_tointeger(L, -1);
    arg3 = (t_atom *)getbytes(arg2 * sizeof(t_atom)); // internally calls calloc()

    for (int i = 0; i < arg2; ++i) {
      lua_pushinteger(L, i + 1);
      lua_gettable(L, 2);

      if (lua_isnumber(L, -1)) {
        arg3[i].a_type = A_FLOAT;
        arg3[i].a_w.w_float = lua_tonumber(L, -1);
      } else if (lua_isstring(L, -1)) {
        arg3[i].a_type = A_SYMBOL;
        arg3[i].a_w.w_symbol = gensym(lua_tostring(L, -1));
      } else {
        SWIG_exception(SWIG_RuntimeError, "unhandled argument type");
      }
    }
  }
  readTable((std::string const &)*arg1,arg2,arg3);

  {
    freebytes(arg3, arg2 * sizeof(t_atom)); // internally calls free()
  }
  return SWIG_arg;

  if(0) SWIG_fail;

fail:
  {
    freebytes(arg3, arg2 * sizeof(t_atom)); // internally calls free()
  }
  lua_error(L);
  return SWIG_arg;
}


来源:https://stackoverflow.com/questions/50703758/proper-way-to-free-a-pointer-array-in-swig-input-typemap

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!