I was still stumped on this one due to the opaque error message and repeated 
comparisons to the original source appearing correct. I stepped away for a 
while to think about it, and the only option I see to help me along is to write 
a shared library in C that behaves similarly, and have it log noisily to STDOUT 
whatever it gets from a Racket program.

Since writing this shim would be tedious, are there any additional 
troubleshooting techniques or tools unique to Racket that can help me narrow 
down the root cause of a crash in foreign code?

-------- Original Message --------
On Oct 25, 2019, 1:56 AM, Sage Gerard wrote:

> Hi Ryan, and thank you for the detailed and informative reply!
>
> I gathered that I should trust Racket's handling of values across the foreign 
> boundary more,
> and used what I learned from your email to get past one error. Sadly, I 
> landed on
> "SIGSEGV MAPERR si_code 1 fault on addr (nil)" right after, and under a 
> different context.
> The affected expression can be found at [1], and I verified that I do not try 
> to use a NULL pointer.
>
> This is a case where foreign function returns a "dummy" pointer to another 
> function whose
> signature the client is expected to know in advance, but the address of the 
> foreign
> function would NOT be known to get-ffi-obj since the procedure is loaded 
> dynamically
> by the library itself [2][3].
>
> The Vulkan docs call for casting this pointer to the function I need. So if 
> I'm understanding your email
> correctly, I need to prepare a value such that I produce a callout object 
> that knows the right signature.
> I tried using (cast) and (function-ptr), both of which failed with different 
> errors. The SIGSEGV error
> came from the (cast) case, which is visible in the source code now a few 
> lines above the linked line.
>
> (function-ptr) seemed to produce a callback and not a callout, so it's still 
> not useful:
>
> ; application: not a procedure;
> ; expected a procedure that can be applied to arguments
> ; given: #<ffi-callback>
>
> I understand your point about conversions automatically happening as values 
> pass
> across the FFI boundary. But if I can't specify the requested type UNTIL a 
> (cast)
> and I'm sure the destination signature is correct, then what do I make of the 
> SIGSEGV error?
>
> [1]: 
> https://github.com/zyrolasting/racket-vulkan/blob/master/examples/mandelbrot.rkt#L260
> [2]: https://stackoverflow.com/a/37900692
> [3]: 
> https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/vkGetInstanceProcAddr.html
>
> ~slg
>
> ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
> On Thursday, October 24, 2019 8:54 PM, Ryan Culpepper <ry...@ccs.neu.edu> 
> wrote:
>
>> On 10/25/19 12:45 AM, Sage Gerard wrote:
>>
>> > I am porting some C++ code to Racket that uses a function pointer.
>> > C++ origin: See 294 through 306:
>> > https://github.com/Erkaman/vulkan_minimal_compute/blob/master/src/main.cpp#L294
>> > Racket destination:
>> > https://github.com/zyrolasting/racket-vulkan/blob/master/examples/mandelbrot.rkt#L240
>> > How do I use function-ptr on debug-report-callback to produce a valid
>> > function pointer matching this signature
>> > https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/PFN_vkDebugReportCallbackEXT.html?
>> > My current error comes from line 250, on the expression (function-ptr
>> > debug-report-callback _PFN_vkDebugReportCallbackEXT):
>> > ; function-ptr: contract violation
>> > ;   expected: (and ctype? (lambda (ct) (eq? 'fpointer (ctype->layout ct))))
>> > ;   given: #<ctype>
>> > It seems that my error was that _PFN_vkDebugReportCallbackEXT was
>> > (_cpointer/null (_fun ...)), but I am not sure what should take its place.
>> >
>> > - If I substitute _fpointer for _PFN_vkDebugReportCallbackEXT, I get
>> > the "application; not a procedure" error.
>> >
>> > - If I substitute the _fun form with the signature I want, then I get
>> > "#<ctype>->C: argument is not `#<ctype>' pointer"
>> >
>> >
>> > I suspect this has something to do with the /callout/ concept from the
>> > manual, but I don't understand how it applies here.
>>
>> The use of _cpointer/null seems wrong: its first argument is interpreted
>> as a tag, so that's the source of the last error you mentioned. The
>> `_cpointer/null` is unnecessary anyway, so just delete it:
>>
>> (define _PFN_vkDebugReportCallbackEXT (_fun ....))
>>
>> On line 250: I don't think you need to use function-ptr. The field
>> setter will automatically convert debug-report-callback (I assume that's
>> a Racket procedure) into a callback function pointer.
>>
>> A callout is a foreign function gets converted into a Racket
>> procedure; a callback is when a Racket procedure gets turned into a
>> function pointer so it can be called from foreign code. Both are
>> described by _fun ctypes.
>>
>> Here's a simpler example. Suppose you have the following C code:
>>
>> /* demo.c /
>> / gcc -fpic -shared -o demo.so demo.c */
>>
>> int an_int_fun(int x) {
>> return x + 1;
>> }
>>
>> typedef int (*int2int)(int);
>>
>> int apply_to_twelve(int2int f) {
>> return (*f)(12);
>> }
>>
>> struct two_funs {
>> int2int f;
>> int2int g;
>> };
>>
>> int apply_two_funs_and_sum(struct two_funs *tf, int arg) {
>> return (tf->f)(arg) + (tf->g)(arg);
>> }
>>
>> Here Racket bindings for the foreign code:
>>
>> (require ffi/unsafe ffi/unsafe/define)
>> (define-ffi-definer define-demo (ffi-lib "demo.so"))
>>
>> (define _int2int (_fun _int -> _int))
>>
>> (define-demo an_int_fun _int2int)
>> (define-demo apply_to_twelve (_fun _int2int -> _int))
>>
>> (define-cstruct _two_funs
>> ([f _int2int]
>> [g _int2int]))
>>
>> (define-demo apply_two_funs_and_sum
>> (_fun _two_funs-pointer _int -> _int))
>>
>> In that Racket program,`an_int_fun` is a callout: a Racket procedure
>> that calls foreign code when applied.
>>
>> (an_int_fun 5) ;; => 6
>>
>> If you call`apply_to_twelve` with a Racket procedure, like this:
>>
>> (apply_to_twelve add1) ;; => 13
>>
>> then the FFI converts`add1` (a Racket procedure) into a function
>> pointer using the _fun type `_int2int`. Foreign code can use that
>> function pointer to call back into Racket.
>>
>> Storing a function in a struct with _int2int fields does the same
>> automatic conversion. For example:
>>
>> (define (f x) (expt x 2))
>> (define (g x) (expt x 3))
>>
>> (define tf (make-two_funs #f #f))
>> (set-two_funs-f! tf f)
>> (set-two_funs-g! tf g)
>> ;; or equivalently, (define tf (make-two_funs f g))
>>
>> (apply_two_funs_and_sum tf 3) ;; => 36
>>
>> You can even fetch one of the function fields back and call it, like this:
>>
>> ((two_funs-f tf) 4) ;; => 16
>>
>> IIUC, that creates a callout procedure that calls the callback function
>> pointer that calls the original Racket procedure.
>>
>> I gave `f` and `g` names so they wouldn't be collected, but in general
>> you need to make sure a Racket procedure doesn't get collected when
>> foreign code still has a callback for it. For example, the following
>> code is likely to crash: because the callback function pointer stored in
>> tf2->g refers to a Racket procedure that has probably been GC'd:
>>
>> (define tf2 (make-two_funs f (lambda (x) (expt x 5))))
>> (collect-garbage)
>> (apply_two_funs_and_sum tf 3)
>>
>> See the #:keep argument of `_fun` for more information.
>>
>> Ryan
>
> --
> You received this message because you are subscribed to the Google Groups 
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to racket-users+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/racket-users/RvdA1FGCG0kqT-1KB-Qq-n4Qt2Lt1YAzgXoehgftKArWboBX5O6ymp-FJYYhFdKaoXjbjRl5GolUqOkyq9rgRamUWRcyU-ws2Rs4uTg-eTE%3D%40sagegerard.com.

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/racket-users/uph-IOkMK3lOVu2aqZ5o2AtuintdpcsZnwdlEi1Ql8FZzlbOf7gjgqWWuVKfVefLoXeC9AfvfUgHovzgXpPUzTiM2HzSNCxf1U357UVqjB0%3D%40sagegerard.com.

Reply via email to