Hi ,

I have a simple interface that I am porting to several languages concurrently using Swig 2.0, and only Perl seems to be giving me problems.   I'm wrapping a C interface while using the "C++" option due to the fact that the original API is in C  ( and can't become C++ ) and I enjoy the additional functionality provided by the C++ extentions within Swig ( operator overloading ...etc ).

I've isolated the problem in both the Swig side and in the generated Perl code. The problem in the Perl generated code is the following

sub DESTROY {
    return unless $_[0]->isa('HASH');
    my $self = tied(%{$_[0]});
    return unless defined $self;
    delete $ITERATORS{$self};
    if (exists $OWNER{$self}) {
        AIOUSBc::delete_DIOBuf($self);
        delete $OWNER{$self};   <-   This line causes a Segmentation fault.
    }
}

I don't see a segmentation fault with any other languages that I am wrapping . These include Python, Ruby and Octave.  All of these work just fine and I believe it has to do with the fact that their "to_string" functionality is more robust than the Perl version.


My key  files are as follows:

/*--------------------------- Makefile.PL -------------------------------*/
use ExtUtils::MakeMaker;
WriteMakefile(
    "NAME"       => "Test",    # Name of module
    "LIBS"       => ["-L$ENV{AIOUSB_ROOT}/lib/Test -lusb-1.0 -lpthread -lDIOBuf"],
    "CCFLAGS"      => "-std=gnu99",
    "INC"        => "-I/usr/include/libusb-1.0/",
    "OBJECT" => "DIOBuf_wrap.o"
   );
/*---------------------------------------------------------------------------*/



/*---------------------------------- DIOBuf.i ---------------------------- */
%module Test

%{
 #include "DIOBuf.h"
%}

%include "DIOBuf.h"

%newobject NewDIOBuf;
/* %delobject DeleteDIOBuf; */


%extend DIOBuf {

  DIOBuf( int size ) {
    printf("Creating object\n");
    return (DIOBuf *)NewDIOBuf( size );
  }

  ~DIOBuf() {
    printf("Deleting object\n");
    DeleteDIOBuf( $self );
  }

  /* Causes the problem after Garbage collecting any Test::DIOBuf objects */
  const char *__str__() {
    return DIOBufToString( $self );
  }
}


/*---------------------------------------------------------------------------*/


/*-------------------------------- DIOBuf.h -----------------------------*/
#ifndef _DIO_BUF_H
#define _DIO_BUF_H
typedef unsigned char DIOBufferType ;

typedef struct {
  unsigned _size;
  unsigned char *_buffer;        /**> Actual elements  */
  char *_strbuf;                 /**> Display string   */

} DIOBuf;

DIOBuf *NewDIOBuf ( unsigned size );
void DeleteDIOBuf ( DIOBuf  *buf );
DIOBuf  *DIOBufResize( DIOBuf  *buf , unsigned size );
unsigned DIOBufSize( DIOBuf  *buf );
const char *DIOBufToString( DIOBuf  *buf );
int DIOBufSetIndex( DIOBuf *buf, unsigned index, unsigned value );
int DIOBufGetIndex( DIOBuf *buf, unsigned index );

#endif

/*---------------------------------------------------------------------------*/

/*-------------------------------- DIOBuf.c-------------------------------*/
#include "DIOBuf.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>


DIOBuf *NewDIOBuf( unsigned size ) {
  DIOBuf *tmp = (DIOBuf *)malloc(sizeof(DIOBuf));
  if( ! tmp )
    return tmp;
  tmp->_buffer = (DIOBufferType *)calloc(size, sizeof(DIOBufferType));
  if ( !tmp->_buffer ) {
    free( tmp );
    return NULL;
  }
  tmp->_strbuf = (char *)malloc(sizeof(char)*size+1);
  if ( !tmp->_strbuf ) {
    free(tmp->_buffer);
    free(tmp);
    return NULL;
  }
  tmp->_size = size;
  return tmp;
}

void DeleteDIOBuf( DIOBuf *buf ) {
  if( buf ) {
    printf("Inside of Delete for address %x\n", buf );
    free( buf->_buffer );
    printf("\tDeleted _buffer\n");
    free( buf->_strbuf );
    printf("\tDeleted _strbuf\n");
    free( buf );
    printf("Finished freeing buf\n");
    buf->_size = 0;
    buf = NULL;
  }
}

DIOBuf *DIOBufResize( DIOBuf *buf , unsigned newsize ) {
  buf->_buffer = (unsigned char *)realloc( buf->_buffer, newsize*sizeof(unsigned char));
  if ( !buf->_buffer ) {
    buf->_size = 0;
    buf->_strbuf = (char *)realloc( buf->_strbuf, (newsize+1)*sizeof(char));
    buf->_strbuf[0] = '\0';
    return NULL;
  }
  if( newsize > buf->_size )
    memset( &buf->_buffer[buf->_size], 0, ( newsize - buf->_size ));

  buf->_strbuf = (char *)realloc( buf->_strbuf, (newsize+1)*sizeof(char));
  if ( !buf->_strbuf )
    return NULL;
  buf->_size = newsize;
  return buf;
}

unsigned DIOBufSize( DIOBuf *buf ) {
  return buf->_size;
}

const char *DIOBufToString( DIOBuf *buf ) {
  int i;
  for( i = 0; i < buf->_size ; i ++ )
    buf->_strbuf[i] = ( buf->_buffer[i] == 0 ? '0' : '1' );
  buf->_strbuf[buf->_size] = '\0';
  return buf->_strbuf;
}


int DIOBufSetIndex( DIOBuf *buf, unsigned index, unsigned value )
{
  if ( index > buf->_size ) {
    return -1;
  }
  buf->_buffer[index] = value;
  return 0;
}

int DIOBufGetIndex( DIOBuf *buf, unsigned index ) {
  if ( index > buf->_size )
    return -1;
 
  return buf->_buffer[ index ];
}


/*---------------------------------------------------------------------------*/


Some notes that are relevent;

1. I build the example as follows:

swig -c++ -perl DIOBuf.i
perl Makefile.PL CCFLAGS="-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -L${PWD} -std=gnu99 -fno-merge-constants"
make


and after building , I am able to run it as follows:

perl  -I. -Iblib/arch -e 'use Test;  { my $a = Test::DIOBuf->new(10) ; my $b = Test::DIOBuf->new(100);  $a = 2 }'
Creating object
Creating object
Deleting object
Inside of Delete for address 8d2df90
    Deleted _buffer
    Deleted _strbuf
Finished freeing buf
Reached
Deleting object
Inside of Delete for address 8d1e6b8
    Deleted _buffer
    Deleted _strbuf
Finished freeing buf
Segmentation fault (core dumped)


2. I'm building this from C source files but using the "C++" flag to swig .
3. All of my memory allocation behind the scenes involves malloc/realloc/free and not new / delete.
4. Commenting out this line ( listed below ) from the generated file Test.pm works.  However, I won't get the nice features of displaying the string form
in my code. 

use overload
#    '""' => sub { $_[0]->__str__() } ,  <-  Comments out the stringify functions




5. I have a Hack fix which is to add in custom Perl code ( to DIOBuf.i  )

%perlcode %{
sub DESTROY {
    return unless $_[0]->isa('HASH');
    my $self = tied(%{$_[0]});
    return unless defined $self;
    delete $ITERATORS{$self};
    if (exists $OWNER{$self}) {
        Testc::delete_DIOBuf($self);
        #delete $OWNER{$self};
    }
}
%}

but I would prefer to get input as to what a better way might be.  

Thanks for any ideas on this,


-Jimi