drracket icon indicating copy to clipboard operation
drracket copied to clipboard

Surprising caching using define-ffi-definer (in DrRacket only)

Open default-kramer opened this issue 1 year ago • 1 comments

Racket 8.12 CS on Windows 10 - The problem appears in DrRacket only (but I suppose the bug could still be in define-ffi-definer).

I kind of can't believe it, but the following code runs and produces output as if I had passed in "zlib1" (which works on Windows) instead of "BLAH"

#lang racket/base

(require ffi/unsafe
         ffi/unsafe/define)

(define-ffi-definer define-zlib
  (ffi-lib "BLAH" #:fail (lambda () #f))
  #:default-make-fail make-not-available)

(define-zlib zlibVersion (_fun -> _string))

(zlibVersion) ; outputs "1.2.12"

(define-zlib compressBound (_fun _ulong ; uLong sourceLen
                                 -> _ulong))

(compressBound 100) ; outputs 113

I was trying to modify my code such that when zlib is not available the error would be delayed until as late as possible. If I omit the #:fail argument, I get the early error telling me that "BLAH" does not exist. But when I add the #:fail argument, it must be finding cached versions of zlibVersion and compressBound from when I was passing in "zlib1"?

Surprisingly, pasting the code into a completely new file, closing and re-opening DrRacket is not enough to thwart this caching. I will do more investigation to see if I can reliably reproduce this.

default-kramer avatar Jul 13 '24 17:07 default-kramer

Wow! I uninstalled Racket 8.12 CS, rebooted, and installed Racket 8.13 CS. I created a new file ffi-test.rkt in a completely different location and pasted in the code from my original report. It still "works" in DrRacket somehow!

Of course, when I run racket ffi-test.rkt from the command line I get what I expect:

C:\Users\kramer\Documents\code>racket ffi-test.rkt
zlibVersion: implementation not found;
 no arguments provided
  context...:
   body of "C:\Users\kramer\Documents\code\ffi-test.rkt"

Perhaps there is something special about zlib because it is bundled with Racket on Windows?

default-kramer avatar Jul 13 '24 17:07 default-kramer

Your (ffi-lib "BLAH" #:fail (lambda () #f)) returns #f, but define-ffi-definer treats #f in that position as equivalent to (ffi-lib #f). Per the documentation for ffi-lib:

If path is #f, then the resulting foreign-library value represents all libraries loaded in the current process, including libraries previously opened with ffi-lib. In particular, use #f to access C-level functionality exported by the run-time system (as described in Inside: Racket C API).

I believe Zlib is loaded on Windows as part of loading racket/gui or racket/draw. On some platforms and build configurations, even the base Racket runtime system may make its internal use of Zlib visible.

Also, note that, unless you supply a non-false #:custodian argument to ffi-lib, the library will remain loaded for the duration of the OS-level Racket process.

LiberalArtist avatar May 21 '25 00:05 LiberalArtist

Aha, that makes sense, thank you! I'll close this as it is not a bug.

default-kramer avatar May 24 '25 17:05 default-kramer