[racket-dev] Should `register-finalizer` unwrap impersonators?

From: Neil Toronto (neil.toronto at gmail.com)
Date: Sat Aug 16 11:02:34 EDT 2014

That's what I think. The more contracted our values get in Racket 
programs, the less we can trust `register-finalizer` if it doesn't change.

Currently, `register-finalizer` tends to be used right after allocation, 
when objects don't usually have contracts yet. It doesn't have to be, 
though.

Neil ⊥

On 08/16/2014 10:46 AM, Sam Tobin-Hochstadt wrote:
> That's clearly the right solution for this particular bug, but it does
> seem like there's a more general problem here.
>
> Sam
>
> On Sat, Aug 16, 2014 at 10:40 AM, Robby Findler
> <robby at eecs.northwestern.edu> wrote:
>> Seems simplest to be to have typed racket know to trust register finalizer
>> and thus avoid wrapping it with a contract.
>>
>> Robby
>>
>>
>> On Saturday, August 16, 2014, Neil Toronto <neil.toronto at gmail.com> wrote:
>>>
>>> Short version: the contract system doesn't allow `register-finalizer` to
>>> be used in Typed Racket.
>>>
>>> Long version: consider the following Typed Racket program, in which
>>> instances of `os-resource-wrapper` represent an operating system resource
>>> `os-resource`, which itself is just a counter. It attempts to register a
>>> finalizer for allocated wrappers, which decrements the counter.
>>>
>>>
>>> #lang typed/racket
>>>
>>> (require/typed
>>>   ffi/unsafe
>>>   [register-finalizer  (All (A) (-> A (-> A Any) Void))])
>>>
>>> (: os-resource Integer)
>>> (define os-resource 0)
>>>
>>> (struct os-resource-wrapper ())
>>>
>>> (: alloc-os-resource (-> os-resource-wrapper))
>>> (define (alloc-os-resource)
>>>    (set! os-resource (add1 os-resource))
>>>    (define w (os-resource-wrapper))
>>>    (register-finalizer w (λ (w) (set! os-resource (sub1 os-resource))))
>>>    w)
>>>
>>> (define w (alloc-os-resource))
>>> (printf "os-resource = ~v~n" os-resource)
>>> (collect-garbage)
>>> (sleep 1)  ; give finalizers a chance to run
>>> (printf "os-resource = ~v~n" os-resource)
>>>
>>>
>>> I get this output:
>>>
>>>    os-resource = 1
>>>    os-resource = 0
>>>
>>> The finalizer is being run while the program still has a pointer to the
>>> wrapper object. I think it's because the wrapper object is being
>>> impersonated when it's sent across the contract barrier, and the
>>> *impersonator* is getting the finalizer. (Or it's a chaperone, or an
>>> impostor, or a charlatan, or whatever. Let's go with impersonator.)
>>>
>>> In my specific case, the OS resources are OpenGL objects; e.g. vertex
>>> object arrays. The call to `register-finalizer` *must* be in Typed Racket
>>> code because the wrapper contains an (Instance GL-Context<%>), which can't
>>> have a contract put on it, so it can't pass from untyped to typed code.
>>>
>>> Is there any reason for `register-finalizer` to behave this way? Does it
>>> ever make sense to register a finalizer on an impersonator?
>>>
>>> Neil ⊥
>>> _________________________
>>>   Racket Developers list:
>>>   http://lists.racket-lang.org/dev
>>
>>
>> _________________________
>>    Racket Developers list:
>>    http://lists.racket-lang.org/dev
>>


Posted on the dev mailing list.