Description
Miri currently treats fn ptrs and data ptrs very similarly, in particular with regards to provenance. When calling a function pointer, its provenance is consulted to identify which function to invoke. This makes int2fnptr transmutes a problem (see rust-lang/rust#97321). fnptr2int transmutes are also UB because fn ptrs carry provenance which integers must not.
However, the trouble with provenance for data pointers come from multiple pointers with the same address but different provenance. Function pointers can't be offset and don't have aliasing restrictions or a "one-past-the-end" rule, so none of this applies. Hence we potentially could make them not carry provenance, and we could do the mapping from pointer to function without its provenance (basically, doing the int2ptr cast at the time the call is made).
Beyond these formal details, there are pragmatic concerns on niche architectures, such as whether data and function pointers even have the same size and representation.
Also see this Zulip discussion.
Activity
thomcc commentedon May 24, 2022
It would be pretty nice if they don't, as for a while now we've taught that the way to invert the
fn_ptr as usize
cast is to transmute back. Given that the justification just seems to be simplification of the model (which doesn't really matter to most programmers, especially given that from their perspective, the incantation to do the inverse cast is less simple now), I think it should be defined.RalfJung commentedon May 25, 2022
Have we?
As far as I found in the stdlib docs, no such pattern is taught there (at least nothing that doctests would cover), and the
transmute
docs actually cast to a raw ptr first.That's fair. I think a large part of programmers that write unsafe code also want to understand the model, so we shouldn't make it more complicated than absolutely necessary. However, the majority of programmers will probably never look at the model so there also is value is making it "do the expected thing", and it is worth spending some complexity on that. So to me this depends on how complicated we have to go to support this.
I would also like to distinguish the two directions:
digama0 commentedon May 25, 2022
This isn't just about fnptr2int transmutes so maybe I should bring this up somewhere else, but I really think it is a bad idea to make these transmutes UB instead of simply stripping the provenance. (That is, when converting bytes with provenance to a value of integer type, the provenance is lost, and when it is saved again the provenance is not recovered.) I see no gain in making it immediate UB.
RalfJung commentedon May 25, 2022
That is basically #286. Though that thread is so huge now, not sure how useful it still is...
It's definitely off-topic for this thread though. :)
LunaBorowska commentedon Aug 3, 2022
I think function pointers on CHERI do have provenance (you cannot simply make up function pointers from integers) which is an argument supporting function pointers having provenance.
[-]Do function pointers have provenance?[/-][+]Do function pointers behave like data pointers (wrt provenance and other aspects)?[/+]RalfJung commentedon Apr 27, 2023
#309 got folded into this issue, so I generalized the title a bit to not just be a about provenance -- there are also questions around whether these types even have the same size etc
Nemo157 commentedon Jan 6, 2025
Somewhat related to this is: what are even the semantics of function {item,pointer} to {pointer,address} cast. These are named in the reference but don't appear in the following semantics section. AFAIK the example in the
transmute
docs linked above is the only place that implies thattransmute<*const (), fn()>(some_fn as _)
is a round-trip.RalfJung commentedon Jan 6, 2025
Function items have no data, so casting those to function pointers is a very special operation that synthesizes a suitable pointer "out of thin air". This operation is non-deterministic; executing it multiple times for the same function can produce different pointers.
Functions points are either like
usize
or like*const ()
(depending on the outcome of the discussion in this issue) so either way their casts tousize
behave like the corresponding carrier type.8 remaining items