Is this a safe use of unsafeCoerce?

二次信任 提交于 2020-01-14 07:04:52

问题


I have a situation where I am at the moment using the extremely scary function unsafeCoerce. It's not for anything important fortunately, but I was wondering whether this seems to be a safe usage of this function, or whether there would be another way to solve this particular problem that other people know of.

The code I have is something like the following:

data Token b = Token !Integer

identical :: Token a -> Token b -> Bool
identical (Token a) (Token b) = a == b

data F a = forall b. F (Token b) (a -> b)

retrieve :: Token b -> F a -> Maybe (a -> b)
retrieve t (F t' f) = if identical t t' then Just (unsafeCoerce f) else Nothing

Two additional things to note, are that these tokens are used within a monad which I use to ensure that the supply of integers for them is unique (i.e. I don't make the same token twice). I also use a forall quantified shadow type variable, in the same way as the ST monad, to make sure that (assuming only the methods I expose in the module are used) there is no way to return a token (or in fact even an F) from the monad without it being a type error. I also don't expose the token constructor.

I think, as far as I can see, this should be a safe usage of unsafeCoerce, as I can say with (I hope) pretty high confidence that the value I am coercing is in fact of exactly the type that I am coercing it to, but I may be wrong. I have also tried using Data.Typeable, which works nicely, but at the moment I am trying this to avoid the Typeable constraint, especially as gcast seems to do something in many ways similar, and I would still need the tokens anyway to distinguish between different Fs of the same type.

Thanks very much for any help/advice.


回答1:


You have implemented a restricted form of dynamic typing, broadly following the style of Data.Dynamic -- namely, paring an (opaque) value with evidence of its type. At runtime you can do an unsafe coercion, based on the evidence you shipped with the data.

fromDyn (Dynamic t v) def
  | typeOf def == t = unsafeCoerce v
  | otherwise       = def

This is the canoncial approach, with a long history, going back to:

Mart´ın Abadi, Luca Cardelli, Benjamin Pierce, and Gordon Plotkin. Dynamic typing in a statically typed language. ACM Transactions on Programming Languages and Systems, 13(2):237–268, April 1991.

The safety of the approach relies on the unforgeability of runtime type tokens. In your case, anyone can build a token that equates two types -- you would need to guarantee a 1-1 mapping from types to tokens, and ensure that a malicious user can't construct incorrect tokens. In the GHC case, we trust the Typeable instances (and module abstraction).




回答2:


It's not safe per se:

oops :: F Bool
oops = F (Token 12) not

bad :: Token Int
bad = Token 12

*Token> maybe 3 ($ True) $ retrieve bad oops
1077477808

F a is an existentially quantified type, you don't know what type b went into it. Since identical doesn't care about the type parameters to Token, it cannot check whether the supplied b from retrieve's first argument has anything to do with what went into the F a.

Whether your protection

Two additional things to note, are that these tokens are used within a monad which I use to ensure that the supply of integers for them is unique (i.e. I don't make the same token twice). I also use a forall quantified shadow type variable, in the same way as the ST monad, to make sure that (assuming only the methods I expose in the module are used) there is no way to return a token (or in fact even an F) from the monad without it being a type error. I also don't expose the token constructor.

is strong enough to make it safe in practice, I cannot tell without seeing it. If indeed no Tokens can be created outside the computation, and the Integer value of the Token uniquely characterises the type parameter, it would be safe.



来源:https://stackoverflow.com/questions/14322311/is-this-a-safe-use-of-unsafecoerce

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!