djpetti
djpetti

Reputation: 191

Problems wrapping and using a function that returns a struct with SWIG (python)

This should be a simple procedure but it has still eluded me for a couple of days now.

My situation is as follows:

I am wrapping a relatively simple C++ interface with SWIG, so I can use it with Python. The matter is complicated, however, by the fact that one of the methods returns a custom struct, whose definition is as follows:

struct DashNetMsg {
  uint64_t timestamp;
    char type[64];
    char message[1024];
};

Here is my SWIG interface file for accomplishing this:

%module DashboardClient
%{
#include "aos/atom_code/dashboard/DashNetMsg.h"
#include "DashboardClient.h"
%}

%import "aos/atom_code/dashboard/DashNetMsg.h"
%include "DashboardClient.h"

%ignore Recv(DashNetMsg *);

"DashboardClient.h" and "DashboardClient.cpp" declare and defines the class "DashboardClient" and its methods, which I am wrapping. "DashNetMsg.h" is a header file that literally contains nothing but the above struct definition. Here is the definition for the DashboardClient.Recv method, from DashboadClient.cpp:

DashNetMsg DashboardClient::Recv() {
  DashNetMsg ret;
  if (Recv(&ret)) {
    // Indicate a null message
    strcpy(ret.type, "NullMessage");
  }

  return ret;
}

Two interesting and (I think) interrelated issues arise when I compile this and load it into python:

Python 3.1.3 (r313:86834, Nov 28 2010, 10:01:07) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import DashboardClient
>>> d = DashboardClient.DashboardClient()
>>> m = d.Recv()
>>> m
<Swig Object of type 'DashNetMsg *' at 0x7f4d4fc2d3c0>
>>> m.type
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'SwigPyObject' object has no attribute 'type'
>>> exit()
swig/python detected a memory leak of type 'DashNetMsg *', no destructor found.

First off, DashNetMsg obviously does define an attribute called "type". Second, what's with this memory leak? According to SWIG:

SWIG creates default constructor and destructor functions if none are defined in the interface.

(http://www.swig.org/Doc2.0/SWIG.html, section 5.5)

Doesn't that mean that it should be creating a destructor for this wrapped type? Also, why can't I access the attributes of my struct?

Solutions that didn't work

My best guess that could explain what is happening is that SWIG for some reason is not actually wrapping the DashNetMsg struct and is instead treating it as an opaque pointer. Because SWIG seems to indicate that freeing what these pointers point to must be done manually, it could also explain the memory leak, I guess. But, even if this is the case, I do not see why SWIG would not wrap the struct.

I read here that swig must have structs declared C-style in order to recognize them. Thus, I tried this:

typedef struct DashNetMsg {
  uint64_t timestamp;
    char type[64];
    char message[1024];
} DashNetMsg;

It had the exact same result as the above.

Upvotes: 3

Views: 2648

Answers (1)

nneonneo
nneonneo

Reputation: 179392

Returning structs by value with SWIG is tricky. From their documentation:

C functions that return structures or classes datatypes by value are more difficult to handle...SWIG only really supports pointers.

SWIG allocates a new object and returns a reference to it. It is up to the user to delete the returned object when it is no longer in use. Clearly, this will leak memory if you are unaware of the implicit memory allocation and don't take steps to free the result.

Upvotes: 1

Related Questions