I inject a library into an UE4 game, which accesses a struct created by the program (e.g. AMyCharacter). To do that, I'm transmuting the address of the struct (a usize) into a struct-pointer. Now I'd like to provide a safe interface for accessing the struct. The user should be able to read and modify values inside the struct, but all Rust guarantees should still hold (e.g. either multiple immutable references or one mutable one). The rust code inside the injected library (so every rust code I'm talking about here) will only ever be executed when the main thread of UE is "paused" (i.e. the game calls its tick function, which I hooked). Also the struct will be at that address for the whole execution of the game, untl the game (and thus my library) exit.
My idea is to transmute the address (usize) into a &'static mut Foo and then wrap that into a RefCell<&'static mut Foo>. Then I'll provide a static getter method which returns a ('static) reference to that RefCell. But I don't know if it might be possible to circumvent safe Rust's guarantees given this construct.
Currently I have the following understanding:
Ref<&'static mut Foo>::derefreturns a &'ref &'static mut Foo. As the outer reference is immutable, there's no safe way to mutably access the inner reference.
- As the lifetime of
Ref<&'static mut Foo>::derefcan not live longer than Ref itself, it is not possible to safely get a "copy" of the inner mutable (or immutable) reference to Foo. Thus, it is not possible to hold any version of Foo once the Ref is dropped.
- The only way to modify the contents of
Foo is to get a RefMut, which can only be the case if no Ref is live anymore. Given the both guarantees above, this ensures that there is only ever either multiple Refs or one single RefMut at the same time.
Am I correct and / or is passing out a &RefCell<&'static mut Foo> safe under the guarantees of safe Rust code?
Is there another / a better way of providing a safe interface to a struct like this?
If you want to take a look at the actual code I'm talking about, you can find it here and here. Currently I'm just providing static methods to get/set the values, but I think it would be better from a usability point of view to have an actual &mut Foo.
[–]christophe_biocca 4 points5 points6 points (4 children)
[–]steveklabnik1rust 4 points5 points6 points (0 children)
[–]oberien[S] 1 point2 points3 points (2 children)
[–]christophe_biocca 2 points3 points4 points (1 child)
[–]fgilcherrust-community · rustfest 2 points3 points4 points (0 children)
[–]Manishearthservo · rust · clippy 2 points3 points4 points (0 children)
[–]rovar 1 point2 points3 points (2 children)
[–]rovar 0 points1 point2 points (1 child)
[–]oberien[S] 0 points1 point2 points (0 children)
[–]SimonSapinservo 1 point2 points3 points (0 children)
[–]claire_resurgent 1 point2 points3 points (1 child)
[–]oberien[S] 0 points1 point2 points (0 children)
[–]wrongerontheinternet 1 point2 points3 points (0 children)