Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Just how "unsafe" are Data.Vector's unsafeFreeze/unsafeThaw?

The documentation for Data.Vector.unsafeFreeze says:

Unsafe[ly] convert a mutable vector to an immutable one without copying. The mutable vector may not be used after this operation.

I would like to characterize exactly what "unsafe" means here. Experimentally, it appears to "only" imply that further modification of the originating mutable vector will cause the immutable vector(s) returned by unsafeFreeze to no longer be pure:

$ import qualified Data.Vector as V
$ import qualified Data.Vector.Mutable as MV
$ import Control.Monad.ST
$ :{
$ |runST $ do
$ |        mv <- V.thaw $ V.fromList [0..10]
$ |        v <- V.unsafeFreeze mv
$ |        MV.write mv 0 (-1)
$ |        MV.write mv 1 (-2)
$ |        v' <- V.freeze mv
$ |        v'' <- V.unsafeFreeze mv
$ |        return (v, v', v'')
$ |:}
([-1,-2,2,3,4,5,6,7,8,9,10],[-1,-2,2,3,4,5,6,7,8,9,10],[-1,-2,2,3,4,5,6,7,8,9,10])

I can imagine a modifying the source used in an "unsafe" freeze doing all sorts of gnarly things that would lead to much worse behaviour, e.g. segfaulting. I'm quickly out of my depth a.t.m. attempting to read the source around the unsafe operations, unfortunately.

Can I rely on said impurity being the sole way in which these operations are "unsafe"?

For context: I have need to implement a variety of modifying algorithms over a typically immutable data structure, and not reusing its public-facing API within that scope of internal mutability would be extremely inconvenient (since AFAICT there is no way to generically access both mutable and immutable vectors). (Ab)using unsafeFreeze when I need to use that API would be the perfect escape hatch, as long as I'm not setting myself up for much more unpleasant side effects down the road.

like image 502
cemerick Avatar asked Jan 04 '19 15:01

cemerick


1 Answers

This usage pattern can crash: see this message for reference. The reason is that mutating an immutable array can create minor GC roots which are not actually visible to minor GC. This error only occurs if your array is in the old GC generation and the written objects are in the new generation, hence you won't trigger it with the simplest tests.

like image 67
András Kovács Avatar answered Oct 27 '22 18:10

András Kovács