Insight
Insight

Reputation: 33

ctypes does not allow dereference of pointer more than once

I have been working in extending some C++ classes to python via ctypes. I first try verifying the address is not equal to NULL via GDB and in the code. It is indeed not equal to NULL. I try printing out the pointer via printf and it prints the address out, but the next line of code involving the pointer throws a segmentation fault. What is strange is that without that printf statement, the next line of code that would come after the printf statement would work. However, the very next function that involved the pointer would then throw a segmentation fault just like with the printf.

Here is my code for reference:

C++->C ctypes wrapper

#include <jetfuelmedia.h>

#define MAX_FILE_NAME_SIZE 1024

extern "C"{
jetfuel::media::Music *Music_new(){
    return new jetfuel::media::Music();
}

void Music_delete(jetfuel::media::Music *music){
    puts("Destroyed Music object");
    delete music;
}

bool Music_is_music_playing(){
    return Mix_PlayingMusic();
}

bool Music_is_music_paused(){
    return Mix_PausedMusic();
}

bool Music_load_music_file(jetfuel::media::Music *music,
                           const wchar_t *musicfilepath){
    char musicfilepathchar[MAX_FILE_NAME_SIZE];

    wcstombs(musicfilepathchar,musicfilepath,
            MAX_FILE_NAME_SIZE);

    puts("Music file is:");
    puts(musicfilepathchar);
    puts("Music ref is:");
    printf("%p",music);

    if(!music->Load_music_file(musicfilepathchar)){
        puts(musicfilepathchar);
        puts(Mix_GetError());
        return false;
    }

    puts("C/C++ code ran");

    return true;
}

bool Music_play(jetfuel::media::Music *music){
    puts("C/C++ Play code ran");
    return music->Play();
}

void Music_pause(jetfuel::media::Music *music){
    music->Pause();
}

void Music_resume(jetfuel::media::Music *music){
    music->Resume();
}

const char *Get_music_error(){
    const char *sdlerror = Mix_GetError();

    if(sdlerror == NULL){
        return "Music object was equal to NULL";
    }
    return Mix_GetError();
}
}

Python class wrapper:

from ctypes import cdll
from ctypes import c_wchar_p
from ctypes import c_void_p
from ctypes import c_bool

class music():  
   _jetfuel = None;
   _musicref = None;

    def __init__(self,jetfuelsofilepath):
        self._jetfuel = cdll.LoadLibrary(jetfuelsofilepath);
        self._musicref = self._jetfuel.Music_new();

    def __enter__(self):
        return self;

    def __exit__(self, exc_type, exc_value, traceback):
        if(self._musicref != None):
            self._jetfuel.Music_delete(c_void_p(self._musicref));

    def is_music_playing(self):
        return self._jetfuel.Music_is_music_playing();

    def is_music_paused(self):
        return self._jetfuel.Music_is_music_paused();

    def load_music_file(self, musicfilepath):
        loadmusicfile = self._jetfuel.Music_load_music_file;
        loadmusicfile.argtypes = [c_void_p, c_wchar_p];
        loadmusicfile.restype = c_bool;

        return loadmusicfile(c_void_p(self._musicref), 
                         c_wchar_p(musicfilepath));

    def play(self):
        return self._jetfuel.Music_play(c_void_p(self._musicref));

    def pause(self):
        self._jetfuel.Music_pause(c_void_p(self._musicref));

    def resume(self):
        self._jetfuel.Music_resume(c_void_p(self._musicref));

    def print_debug(self):
        print("Music ref is ="+str(c_void_p(self._musicref)));

    def get_music_error(self):
        return self._jetfuel.Get_music_error();

How can I make this code work with pointers that can be dereferenced multiple times?

If this concerns anything, my system info is:

Upvotes: 2

Views: 434

Answers (1)

tom
tom

Reputation: 22949

You forgot to set restype of Music_new:

def __init__(self,jetfuelsofilepath):
    self._jetfuel = cdll.LoadLibrary(jetfuelsofilepath)
    self._jetfuel.Music_new.restype = c_void_p
    self._musicref = self._jetfuel.Music_new()

The default is int, which messes up the pointer. The other functions will need similar treatment. To keep things tidy, I suggest you do all of that in one place (e.g. a function load_jetfuel_library).

Upvotes: 1

Related Questions