I don't think it was ever the intention that 'safe' should have a guaranteed serialisation property. I think the idea was that 'threadsafe' was the most desirable, with 'safe' and 'unsafe' only available for use if you wanted more efficiency and had some separate guarantees that the extra efficiency was not at the expense of correctness.
To be completely explicit, I think that increasing the safety level of any foreign import should never make the program fail.
If I recall correctly, the motivation for keeping "safe" was that we wanted to be able to make calls into non-threadsafe C libraries. Which, incedentally, would break the property that Simon mentions above: a non-threadsafe library would *require* foreign imports to be labelled "safe" rather than "threadsafe". However, at the time I don't think we appreciated the implementation diffiulties arising from "safe". Also, Wolfgang has pointed out that you can simulate serialisation in Haskell using MVars. Cheers, Simon