Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Segfault with callback containing char* or void* params #2

Closed
samaaron opened this Issue · 9 comments

3 participants

@samaaron

Hi there,

We're trying to use clj-native for our new Overtone internal server. However, an error occurs when the example is modified as follows:

GeorgeJahad@2281060

Are we doing something silly, or is this a bug in clj-native?

@bagucode
Owner

First of all I have to tell you that I haven't touched clj-native in two years so I'm surprised it still works at all.
But I'm also happy that someone is actually trying to use it so I have looked into the issue a little bit.
The original example file seems to still work fine with clojure 1.4 and jna 3.4.0 which is nice, but even with the dependencies updated it still crashes in the same way when using your callback.
The crash happens inside jna which probably means that clj-native is generating broken callback specifications when callbacks take pointers as parameters.
I will try to fix it but I can't make any promises. The code is not that well factored and like I said it has been a long time since I hacked on it.

@bagucode bagucode was assigned
@samaaron

That would be absolutely awesome :-)

@bagucode
Owner

"Fixed" it. The new code is on my master branch.
I also updated project.clj to use clojure 1.4.0 and jna 3.4.0

The issue was not that the callback specification was broken. It was simply that it is not possible for jna to pass a ByteBuffer as a parameter to a callback.
Since jna cannot know the size of a char* memory block it can't automatically convert it to a ByteBuffer.
I have modified the callback parsing code to not allow any pointers other than void* as parameters to callbacks to protect against this kind of thing happening again.

The solution to your issue is to pass the char* as a void* and then use the getByteBuffer method of the jna Pointer class.
I modified your reply-callback in c_lib.clj to do that and it works fine for me now.

Please tell me if this works for you so I can close the issue.

@samaaron

Wonderful thanks so much - I'll give it a try and let you know later today.

Once again, many thanks :-)

@rosejn

Yessss! This did the trick. Using your latest and replacing all of the callback pointers with void* has worked, and now I'm running Overtone with a native synth server. Thanks a lot for tracking this down Markus. Our native interface has been an ongoing source of headache, and the all clojure version using clj-native will help streamline things a lot.

@samaaron

Fantastic :-)

Markus, would it be possible to push this new version of clj-native to Clojars?

@samaaron samaaron closed this
@bagucode
Owner

Sure thing. Just wanted to make sure it worked for you first.
0.9.2-SNAPSHOT now on Clojars:
https://clojars.org/clj-native

Good luck with your work on Overtone, it's a really cool project.

@samaaron

Thanks Markus. Also, thanks for making clj-native. It's certainly making our life easier. It looks like some ninja piece of work.

@samaaron

Hi Markus,

sorry for writing here, but I couldn't find your email address anywhere...

Firstly, I'd like to thank you again for clj-native - we now have working prototypes of our new native server running on Windows, Linux and OS X which we're really excited about. Your library is powering all of these, and we intend to make the new native server the default server implementation for Overtone.

However, one of the last pieces of the puzzle that's still evading us is how we can share byte buffers between Overtone and the server. SuperCollider provides the following public method:

    SC_DLLEXPORT_C int World_CopySndBuf(struct World *world, uint32 index, struct SndBuf *outBuf, bool onlyIfChanged, bool *didChange);

This can be found in context here: https://github.com/supercollider/supercollider/blob/master/include/server/SC_WorldOptions.h#L112

We're struggling to get this to work. Currently our approach is to declare a struct

(bool-val
  :value byte)

and then declare the interface as follows:

(world-copy-sound-buffer World_CopySndBuf [void* i32 sound-buffer* byte byte*] i32)

We're then trying to use is like this:

(defn scsynth-get-buffer-data
  "Get a an array of floats for the synthesis sound buffer with the given ID."
  [sc buf-id]
  (let [buf      (byref sound-buffer)
        changed? (byref bool-val)]
    (world-copy-sound-buffer (:world sc) buf-id buf 0 changed?)
    buf))

This can be found in context here: https://github.com/overtone/overtone/blob/master/src/overtone/sc/machinery/server/native.clj

Unfortunately it's not working, and we're not sure how to continue. Is there anything we're doing that's obviously wrong?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.