Inadvertedly requiring racket/unsafe/ops

31 views
Skip to first unread message

Dominik Pantůček

unread,
Dec 14, 2019, 4:03:14 PM12/14/19
to Racket Users
Hello,

the documentation at https://docs.racket-lang.org/reference/fixnums.html
is misleading at best. If you - as I did - use the suggested approach of
requiring optimized (and unsafe) fx... operations from racket/unsafe/ops
with:

(require (filtered-in
(λ (name) (regexp-replace #rx"unsafe-" name ""))
racket/unsafe/ops))

You end up using _all_ symbols from racket/unsafe/ops. All of them are -
of course - uncontracted. Which means that if you issue for example
vector-ref on something that is not a vector, it can crash the runtime
without any apparent reason - instead of just throwing an exception as
one would expect.

A simple documentation fix should probably go along the lines:

(require racket/require
(filtered-in
(λ (name)
(and (regexp-match #rx"^unsafe-fx" name)
(regexp-replace #rx"unsafe-" name "")))
racket/unsafe/ops))

Or is it just me running into corner cases with optimized Racket code?


Cheers,
Dominik

Jack Firth

unread,
Dec 14, 2019, 8:57:54 PM12/14/19
to Racket Users
I think that documentation fix is a good idea. More broadly, it seems awkward that all of the unsafe ops for different data types are combined together into a single module. I would instead expect there to be modules like racket/fixnum/unsafe, racket/struct/unsafe, racket/vector/unsafe, etc. But I've never used the unsafe ops before, maybe those who have can chime in?

Eric Griffis

unread,
Dec 15, 2019, 2:14:48 AM12/15/19
to Racket Users
Unsafe operations are usually defined externally, like in a C extension, where safety is harder to guarantee and module hierarchies are less idiomatic. The "unsafe" moniker is a standard warning that you are responsible for understanding the underlying implementation and calling into it responsibly, or risk crashing.

The documentation, assuming you know this, explains how to swap the unsafe variants into a module that already uses the safe API, effectively bypassing safety features like contracts and dynamic dispatch.

If you're going to use unsafe operations, make sure you need the extra juice and are confident nothing is going to break. This isn't just the deep end of the pool -- it's the screws holding the drain to the bottom.

Eric


--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/c118c47e-fccd-4fab-b252-7a24afe6eef1%40googlegroups.com.

Dominik Pantůček

unread,
Dec 15, 2019, 5:13:06 AM12/15/19
to racket...@googlegroups.com
Hi,

On 15. 12. 19 2:57, Jack Firth wrote:
> I think that documentation fix is a good idea.

I'll submit a PR to appropriate repository later on.

> More broadly, it seems awkward that all of the unsafe ops for
> different data types are combined together into a single module. I
> would instead expect there to be modules like racket/fixnum/unsafe,
> racket/struct/unsafe, racket/vector/unsafe, etc. But I've never used
> the unsafe ops before, maybe those who have can chime in?

it's not that easy as it is really about the "ops" part. For example if
you need (make-fxvector ...), you still need to require it using
(only-in racket/fixnum make-fxvector) as there is no racket/unsafe/ops
equivalent (which is really NOT surprising).

And also splitting the racket/unsafe/ops into more modules might break a
thing or two as it has been this way for quite some time. Also it is
nice - if you are in need of heavy optimizations - to see the list of
unsafe ops in one place.


Cheers,
Dominik

>
> On Saturday, December 14, 2019 at 1:03:14 PM UTC-8, Dominik Pantůček
> wrote:
>
> Hello,
>
> the documentation at
> https://docs.racket-lang.org/reference/fixnums.html
> <https://docs.racket-lang.org/reference/fixnums.html> is misleading
> at best. If you - as I did - use the suggested approach of requiring
> optimized (and unsafe) fx... operations from racket/unsafe/ops with:
>
> (require (filtered-in (λ (name) (regexp-replace #rx"unsafe-" name
> "")) racket/unsafe/ops))
>
> You end up using _all_ symbols from racket/unsafe/ops. All of them
> are - of course - uncontracted. Which means that if you issue for
> example vector-ref on something that is not a vector, it can crash
> the runtime without any apparent reason - instead of just throwing
> an exception as one would expect.
>
> A simple documentation fix should probably go along the lines:
>
> (require racket/require (filtered-in (λ (name) (and (regexp-match
> #rx"^unsafe-fx" name) (regexp-replace #rx"unsafe-" name "")))
> racket/unsafe/ops))
>
> Or is it just me running into corner cases with optimized Racket
> code?
>
>
> Cheers, Dominik
>
> -- 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...@googlegroups.com
> <mailto:racket-users...@googlegroups.com>. To view this
<https://groups.google.com/d/msgid/racket-users/c118c47e-fccd-4fab-b252-7a24afe6eef1%40googlegroups.com?utm_medium=email&utm_source=footer>.

Dominik Pantůček

unread,
Dec 23, 2019, 12:23:08 PM12/23/19
to racket...@googlegroups.com
Hello all,

a short followup on the issue.

I opened a PR[1] and Sam raised an interesting question:

(require (filtered-in
(λ (name)
(and (regexp-match #rx"^unsafe-fx" name)
(regexp-replace #rx"unsafe-" name "")))
racket/unsafe/ops))

ensures that only unsafe-fx... bindings get required as fx... bindings
and no other bindings from racket/unsafe/ops are. However, the following:

(require (filtered-in
(λ (name) (regexp-replace #rx"unsafe-fx" name ""))
racket/unsafe/ops))

does the same trick of not shadowing for example vector-ref with
unsafe-vector-ref - which also solves the problem I encountered and
therefore it might be better suited (as it is a smaller change).

To be honest - both solutions are OK. My personal preference for not
polluting the current namespace with all those unsafe-... bindings is
mostly irrelevant here. Can anyone using racket/unsafe/ops share their
thoughts here?

Also please note that the same applies to flonums and extflonums - which
do not mention the unsafe-... option in the documentation at all. I am
inclined to think that this might be good to fix as well.


Cheers,
Dominik

[1] https://github.com/racket/racket/pull/2975
Reply all
Reply to author
Forward
0 new messages