Comments (17)
Now I am confused. Didn't you tell me that &'static mut
are a bad idea not too long ago?
from rtic.
What? No. &'static mut
is fine. The problem is aliasing the &'static mut
reference, which must be unique. Simple, actually memory unsafe, functions like the one below result in mutable aliasing (and break Rust memory model) so those are a bad idea:
fn foo() -> &'static mut u32 {
static mut FOO: u32 = 0;
unsafe { &mut FOO }
}
let a: &'static mut u32 = foo();
let b: &'static mut u32 = foo();
// BAD `a` and `b` point to the same thing
assert_ne!(a as *const _ as usize, b as *const _ as usize);
But if you have a mechanism to guarantee the uniqueness of the &'static mut
reference, like what's proposed in this RFC, then you are good to go.
from rtic.
I neither see how your suggestion automagically fixes the possibility of mutable aliasing nor how that would break Rusts memory model (since you can only initialise them with known types and const
functions anyway, Rust will always be aware of size and place). There're plenty of applications where concurrent access is just fine or even expected and/or out of program control (as in your DMA example).
from rtic.
@therealprof Under this proposal, mutable references are only handed out by RTFM to the init function (uniqueness is enforced by the app!
macro - when a resource is used by init
, it may not be used by any other task). Aliasing (Edit: Maybe, maybe not, who knows? And who needs a memory model anyways?)&mut
s, static or not, result in insta-UB (also see https://doc.rust-lang.org/nomicon/transmutes.html).
(I've only skimmed this proposal, but it looks safe - and a safe and simple abstraction over DMA is totally awesome!)
from rtic.
There's no transmute happening in the example brought up by @japaric and the transmute chapter does not handle aliasing at all as far as I can see, that would be https://doc.rust-lang.org/nomicon/aliasing.html . As soon as you want to use shared memory or hand off the pointer for the use of DMA you're accepting the fact that you (or the hardware) is aliasing memory anyway. And for a lot of applications that is just okay.
from rtic.
@therealprof You might be right about the safety of aliasing. Certainly, as it stands, Rust defers the UB decision to LLVM, which allows aliasing noalias
/&mut
pointers as long as their uses don't violate aliasing rules. However, Rust doesn't specify LLVM's behaviour. In fact, Rust doesn't really specify anything.
But giving the user aliasing &mut
allows UB in safe code, which is a big no-no. I also don't understand your point about DMA - it also needs mutable access to the data, but the program doesn't need to (and isn't allowed to) access the memory while the transfer is in progress, and this is perfectly expressed by this proposal (peripherals and memory involved in a transfer are unusable until the application waits for the transfer to complete - no conflicting access is happening).
from rtic.
from rtic.
@jonas-schievink A lot of languages implemented on LLVM do allow aliasing pointers so there shouldn't be any problem there.
My point re: aliasing was that aliasing (whether it happens in software an/or hardware is not relevant) is not necessarily a bad thing and sometimes quite expected.
Anyhow, I'm very much in favour of this proposal despite the confusion around the badness of aliased mut statics...
from rtic.
@therealprof Other languages do not set noalias
attribute on their pointers, so they don't have any problem with aliasing.
Here is a classical example of UB: https://godbolt.org/g/LrFMjL
Notice how removing pub
keyword from function bar
changes return value of abc
from rtic.
@pftbest Fully understood that you can do really bad stuff with aliased pointers.
from rtic.
you can do really bad stuff with aliased pointers
This is just a trivial example, the real code may be much more subtle. And it's not always about what you write, similar code may be generated after some optimization steps.
The whole idea of Rust is to make it impossible to trigger UB in a safe code. No matter how bad the code is, if it's in safe rust it should either not compile, or panic at runtime.
If you can trigger UB in a safe code that means your unsafe blocks are designed incorrectly.
from rtic.
@japaric Thanks for tagging me. I've looked over your proposal, and everything looks good to me, with two caveats:
- I'm not intimitely familiar with the workings of
&'static mut
, so I might be missing something. It looks like you've done your homework though! - I'm largely unfamiliar with RTFM, so I might be missing something there, too.
I'm also a bit unclear on how this fits into the larger context. Specifically, how does this proposal relate to rust-embedded/embedded-hal#14? That proposal mentions static_ref::Ref
, which seems to be a predecessor of Static
. Am I correct in assuming that Static
will be completely deprecated, even outside of RTFM?
It seems to me that Static
wouldn't be useful, since it can only be created using unsafe
, and once unsafe
is an option, I can just create a &'static mut
, and use that as suggested in this proposal.
from rtic.
Specifically, how does this proposal relate to rust-embedded/embedded-hal#14?
This proposal is for RTFM. I think, though, that Static
, previously static_ref::Ref{,Mut}
, is
not enough to create memory safe DMA APIs (I haven't documented the mem::swap
problem but I think
Static
is not enough to prevent it). Thus I think that the standardized DMA API that will end
in embedded-hal should use &'static mut
references, not Static
. That raises the question: what
will be the fate of non-RTFM applications where it's not safe to create &'static mut
references?
Except that I just thought of a way to safely create &'static mut
references in non-RTFM
applications. There is no free lunch though: this approach will incur in non-elidable runtime
checks. Here's the idea: a macro that creates &'static mut
references using the singleton check I
introduced in rust-embedded/svd2rust#157:
// this macro could be simplified: for instance `$ident` is kind of useless
macro_rules! alloc {
(static $ident:ident: $ty:ty = $expr:expr) => {
cortex_m::interrupt::free(unsafe {
static mut USED: bool = false;
if USED {
None
} else {
static mut $ident: $ty = $expr;
let e: &'static mut $ty = &mut $ident;
USED = true;
Some(e)
}
})
}
}
let a = alloc!(static BUFFER: [u8; 16] = [0; 16]).unwrap();
let b = alloc!(static BUFFER: [u8; 16] = [0; 16]).unwrap();
// OK `a` and `b` are not aliases -- they are pointing to different `static` variables
assert_ne!(a.as_ptr(), b.as_ptr());
fn alias() -> &'static mut [u8; 16] {
alloc!(static BUFFER: [u8; 16] = [0; 16]).unwrap()
}
let c = alias();
// this will panic! if it didn't it would create an alias to the `BUFFER` variable in `alias`
let d = alias();
Am I correct in assuming that Static will be completely deprecated, even outside of RTFM?
I think the only user of Static
is RTFM so yeah it will probably vanish into nothingness after
this change.
from rtic.
@pftbest We're fully on the same page here and I'm absolutely not suggesting this to be used in any user facing crate.
from rtic.
@japaric Thanks for your reply. Interesting proposal. I don't have a firm opinion on the matter right now. Integrating DMA into one of my projects is on my todo list though, so I assume I'll have more to say then.
from rtic.
Since this has received positive feedback and no objections I'm going to rubber stamp the RFC and land the open PRs.
I'll send another PR to cortex-m to discuss a checked version of this that works without RTFM.
from rtic.
I'll send another PR to cortex-m to discuss a checked version of this that works without RTFM.
See rust-embedded/cortex-m#70. Feedback on the macro syntax is welcome!
from rtic.
Related Issues (20)
- timeout_after memory usage HOT 1
- nested lock() can allow access to unlocked resources HOT 5
- `docs.rs` page for `rtic` v2.1.1 is not available
- broken usage example for i2c sharing HOT 2
- Software/Hardware Task interfaction with RTIC v2 HOT 2
- How to invoke code before RTIC main part. HOT 1
- Docs: Examples are broken and not showing HOT 3
- `atomic-polyfill` is deprecated
- rtic_monotonics 2.0 not in crates.io??? HOT 5
- Consider adding a hook to run code at the beginning of the entry point HOT 3
- SPI devices on shared bus (embedded-hal-bus) HOT 3
- Locked Status with Multiple Shared Resources HOT 2
- Software tasks and the stack HOT 2
- Support for embedded_alloc
- Call to SCB::sys_reset() results in locked up core. HOT 3
- rtic-monotonic on stm32 TIM20 or TIM17 HOT 2
- How to get the time stamp in a RTIC Rust Embedded application HOT 1
- Proplems while setting up rtic 2.1.1 HOT 2
- Multicore Support HOT 3
- How can I share the spawn handle? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rtic.