<thejpster[m]>
Perhaps there should be a standing agenda item to list and note any no-std target related PRs so we keep on top of them? Iām sure that can be done with a filter, or a script.
<dirbaio[m]>
APIs with `&'static mut` bufs are thorougly unusable
<dirbaio[m]>
so in embassy we decided in the name of practicality to do it anyway
<dirbaio[m]>
even if it's not 100% sound
<dirbaio[m]>
because it's very hard to accidentally forget a future
<dirbaio[m]>
the Rc/Arc cycles are much less likely since you usually don't use alloc
JamesMunns[m] has joined #rust-embedded
<JamesMunns[m]>
dirbaio I feel like this would be a good blog post/docs item to have for embassy
<JamesMunns[m]>
like "DMA, forget, and safety"
<dirbaio[m]>
docs, what docs? š¤£
<dirbaio[m]>
yeah when there's docs it'll be documented
<JamesMunns[m]>
Just copy and paste the last 5 times we've discussed this on Matrix :p
<JamesMunns[m]>
(not judging Hugh here - it's a reasonable question that has been discussed here, but I don't think it's documented anywhere discoverable)
Foxyloxy has joined #rust-embedded
jamwaffles[m] has joined #rust-embedded
<jamwaffles[m]>
Is there a way to find the final written-to-flash size (preferably RAM too) of a Rust binary? I'm already using cargo size --release which is helpful but I'm wondering if that's not quite what's written to the target MCU
<JamesMunns[m]>
size should be exact
<JamesMunns[m]>
unless you have some sort of bootloader step like elf2uf2
<JamesMunns[m]>
it might be rounded up to erase the next flash page (like 4K block or whatever)
<dirbaio[m]>
cargo size does .text+.rodata+.data I think, the binary might be bigger if you have more custom sections?
<dirbaio[m]>
how does it know which sections to count?
<jamwaffles[m]>
Nah all bog standard sections and no bootloader š so I think I can trust the cargo size numbers
<dirbaio[m]>
perhaps I'm wrong and it looks at the section attributes, idk
<JamesMunns[m]>
you can also pass -- -Ax to get sections as well
<JamesMunns[m]>
(I'm on mac, maybe that doesn't have rust ones, on linux I was pretty sure I had it)
<JamesMunns[m]>
I guess it's GCC binutils vs LLVM binutils
Eraden[m] has joined #rust-embedded
<Eraden[m]>
Can someone give me hint what I'm doing wrong? Or article which works today?
<Eraden[m]>
Hi, I'm starting with embedded on arduino uno. I can't find any working solutions to compile avr-oxide (error while compile --target split-debug is bad flag)
Mebus[m] has quit [Quit: Idle timeout reached: 172800s]
almindor[m] has quit [Quit: Idle timeout reached: 172800s]
therealprof[m] has quit [Quit: Idle timeout reached: 172800s]
<firefrommoonligh>
<dirbaio[m]> "APIs with `&'static mut` bufs..." <- I disagree failed (104: Unknown error) while reading response header
<firefrommoonligh>
<dirbaio[m]> "APIs with `&'static mut` bufs..." <- How so?
<firefrommoonligh>
I use them all the time!
<dirbaio[m]>
impossible to build sane abstractions
<dirbaio[m]>
if you have, say, an HTTP client which uses TCP which uses a network stack which uses a driver for an SPI ethernet chip and want to use DMA for the SPI
<firefrommoonligh>
I guess I don't understand
<dirbaio[m]>
you have to pass the required `&'static mut [u8]` buffers all the way down through all the layers
<firefrommoonligh>
You put the buf in the fn
<firefrommoonligh>
And then it works
<firefrommoonligh>
I guess I usually don't have more than a layer or two
<dirbaio[m]>
so it's impossible to, for example, do a trait for "ethernet device"
<firefrommoonligh>
So, incompatible with Traits?
<dirbaio[m]>
because the trait API has to pass the mut buffer through
<firefrommoonligh>
I have plenty of sane APIs that use it; they're POFs
<firefrommoonligh>
I need to start using that term
<firefrommoonligh>
Plain Old Functions
<dirbaio[m]>
I guess the things you work on don't have much levels of abstraction then
<firefrommoonligh>
Yea. Probalby why we have diff perspectives on this. I don't see a way to make them work with Traits off the top of my head
<dirbaio[m]>
doing the HTTP - TCP - IP - Ethernet - SPI stack without traits would suck
<dirbaio[m]>
you have to port it over and over again to different MCUs, different ethernet chips, different network stacks?
<firefrommoonligh>
I can see where that would be incompatible
<dirbaio[m]>
and even with POFs you have to pass down the buffers which is very annoying
<firefrommoonligh>
It depends on how the program is architected. Ie in some cases, you pass them down; in others you point to the buffer directly. I try to keep the buffers scoped to the module that access them, but pass them down sometimes
<firefrommoonligh>
s/point/call/, s/to//
<firefrommoonligh>
That's more applicable to firmware design than generic API design
<dirbaio[m]>
scope them to the module with e.g static mut?
<dirbaio[m]>
then if the user creates two instances of your thing and uses them concurrently, you get corruption
eldruin[m] has quit [Quit: Idle timeout reached: 172800s]
<firefrommoonligh>
Yep
<firefrommoonligh>
More relevant when you are the user and it's not an API
<firefrommoonligh>
If it is an API, it's up to the user not to do anything inappropriate with the static mut
<firefrommoonligh>
*wait no. THe user creates the buf
<firefrommoonligh>
The api has a fn sig like `fn(buf: &'static mut [u8])`
<firefrommoonligh>
Mainly comes up for me for CMSIS filters (FFI), and DMA
<firefrommoonligh>
But DMA is everywhere, so it ends up all over
<firefrommoonligh>
*not relevant for your SPI/internet-stack example
<whitequark[cis]>
<dirbaio[m]> "so in embassy we decided in..." <- this is ... sad
<whitequark[cis]>
(mostly because I want to rely on #[forbid(unsafe)] as a useful tool in my embedded development to the extent where that was the literal impetus for writing smoltcp)
<dirbaio[m]>
well, the leakpocalypse thing is imo a Rust design flaw
<whitequark[cis]>
the reason I'm calling it "sad" and not "wrong" is because usually you would use embassy in your toplevel and the toplevel is mostly unsafe code anyway
<dirbaio[m]>
there's talks of fixing it in Rust, like with a Leak auto trait that'd say "it's OK to forget this type"
<dirbaio[m]>
so Embasy could mark DMA-using futures as !Leak
<whitequark[cis]>
though given how stm32-metapac (I think?) breaks safety by default anyway by ignoring that the use of DMA is unsafe I expect I'll just have to rewrite everything I rely on again if I do any significant amount of embedded dev in Rust
<dirbaio[m]>
but it's unlikely to happen
<firefrommoonligh>
whitequark[cis]: I don't think that's practical. How is it going so far?
<firefrommoonligh>
For other domains, def
<firefrommoonligh>
For embedded, I'm skeptical
<firefrommoonligh>
PC programs, web stuff, no unsafe is easy
<whitequark[cis]>
firefrommoonligh: `smoltcp` only lacks `#[forbid(unsafe)]` because some of the OS-specific drivers require unsafe libc manipulation; all of the actual code in smoltcp is safe
<firefrommoonligh>
* For PC programs and web stuff, no unsafe is easy
<whitequark[cis]>
of course, at the toplevel, you will inevitably have a blob of unsafe. what I want is to minimize its size and impact
<firefrommoonligh>
Got it
<whitequark[cis]>
by yeeting almost all of the code out of the toplevel crate and using #[forbid(unsafe)] everywhere else as a technical approach
<JamesMunns[m]>
dirbaio the issue with embassy and DMA is mostly using stack/pinned task buffers for DMA, right?
<dirbaio[m]>
yes
<whitequark[cis]>
tbh I wonder if we're somehow doing DMA wrong all this time and all of the DMA-related issues could be solved in one go
<JamesMunns[m]>
in that the future/task itself acts as a mutex, but if you forget that, it "acts as if" you have multiple access
<JamesMunns[m]>
(basically - dma stop doesn't get called on forgetting the mutex handle, AND makes the buffer "available" again)
<whitequark[cis]>
James Munns: on STM32, I think you could use the DMA enable bit as the mutex state
<whitequark[cis]>
i.e. make it unsafe to enable DMA (which it should already be and it's a bug in stm32-metapac that it's not) and refuse to ever enable it twice
<JamesMunns[m]>
Catherine yeah, I think Eliza did something like that for the D1 I2C driver
<JamesMunns[m]>
(it was interrupt enable instead of dma enable, but similar concept)
<whitequark[cis]>
this makes it 'zero cost' by folding the cost into something you're already doing
<whitequark[cis]>
well it's not actually zero cost because there's the panic check, but I think this will make people happier than a flag somewhere in .bss
<whitequark[cis]>
I understand the practicality but on a personal level it's been frustrating to see the lack of ambition in this space :(
<JamesMunns[m]>
It's something we've discussed for near 5 years now
<JamesMunns[m]>
I wouldn't call it a lack of ambition
<JamesMunns[m]>
but I don't think anyone has struck a "works for everyone" balance.
<whitequark[cis]>
I feel like the recent change to stm32-metapac that made any use of DMA unsafe does fall under that description
<dirbaio[m]>
so, use the "dma is running" bit as kind of a mutex, and panic if the bit is already set when you're going to start a transfer?
<whitequark[cis]>
dirbaio: yep
<whitequark[cis]>
s/unsafe/safe/
<dirbaio[m]>
that doesn't work. forgetting the future releases the borrow on the buffer, which allows deallocating it
<dirbaio[m]>
and then DMA keeps writing to deallocated memory
<dirbaio[m]>
it's immediate UB, it's not just later when you go start the next transfer
<whitequark[cis]>
dirbaio: oh, right, you'd need to travel in time for this to work
<dirbaio[m]>
the only way is outlawing forget() and co
<JamesMunns[m]>
fwiw: bbqueue *is* safe in this, in that forgetting the allocation (a grant) causes that buffer to be "forever burned"
<JamesMunns[m]>
and in general, for mnemos, we generally only plan to impl DMA with allocated buffers, so forgetting a future means forgetting the associated buffer (leaking it)
<whitequark[cis]>
dirbaio: without outlawing `forget()`, you could require all DMA allocations to come from a separate allocator
<dirbaio[m]>
* that's "requiring `&'static mut` buffers" in a trenchcoat
<JamesMunns[m]>
yeah, you'd need to use some kind of slab/static/oneshot allocator that burns that alloc if the DMA transfer is forgotten
<whitequark[cis]>
dirbaio: does it have the same flaws? for one you don't violate aliasing rules by passing those pointers around
<dirbaio[m]>
yes, it leaks through APIs all over the place
<whitequark[cis]>
JamesMunns[m]: I think you don't even need a special allocator, actually
<dirbaio[m]>
you can no longer do "please read bytes into this &mut [u8]"
<dirbaio[m]>
you have to do "here you have a MyCustomBox<[u8; 1024]>, please read onto range 15...32 of it and then give it back when you're done thx"
<whitequark[cis]>
James Munns: you could do it with a normal `Box` if you pre-`forget()` the box and rematerialize it when the transfer is done
<dirbaio[m]>
at least with `&'static mut` you can slice them
<JamesMunns[m]>
Catherine if the future owns the box and the future is forgotten, so is the box
<dirbaio[m]>
* <del>at least, * slice them</del> no you can't
<dirbaio[m]>
boxing has the same issues as `&'static mut` re abstractions/traits
<dirbaio[m]>
plus it's not zero cost, and introduces the possibility of having out-of-memory panics at runtime
<JamesMunns[m]>
yeah, I agree, for embedded the answer is requiring Box or MyBox (the latter being a fancy thingy)
<JamesMunns[m]>
* yeah, I agree, for embedded the answer is requiring Box or MyBox (the latter being a fancy thingy if you don't require alloc)
<whitequark[cis]>
dirbaio: tbf I think the restriction makes sense, it is not safe to pass `&mut [u8]` to a different thread no matter how much you want it. DMA is a different thread
<dirbaio[m]>
> it is not safe to pass &mut [u8] to a different thread
<dirbaio[m]>
only if leaking is possible
<whitequark[cis]>
'in current Rust' yeah
<dirbaio[m]>
if leaking is impossible, you're guaranteed your drop() is called, where you can synchronously stop DMA.the other thread.
<whitequark[cis]>
I'm interested to hear that forbidding leaking is considered again; wasn't it pretty thoroughly eliminated as an idea many years ago?
<dirbaio[m]>
it was
<whitequark[cis]>
so what changed?
<dirbaio[m]>
and they're rediscovering how much it sucks for io_uring š¤Ŗ
<whitequark[cis]>
and for overlapped I/O in Windows, yes
<dirbaio[m]>
so there's some interest
<JamesMunns[m]>
I think there's two overlapping desires:
<whitequark[cis]>
yeah but interest isn't enough to make something untrue true
<dirbaio[m]>
but it has a very high bar to clear yep
<dirbaio[m]>
the only way to introduce Leak is to make it a default trait like Sized. so generic params are Leak by default and you opt out with : ?Leak
<JamesMunns[m]>
* Making something live forever
<JamesMunns[m]>
* Making sure something can never be released without a destructor being called
<dirbaio[m]>
and the lang team has said the complexity cost of adding new ?Traits is very high
<dirbaio[m]>
there's *some* interest from big corp for io-uring
<dirbaio[m]>
nobody cares about Windows
<dirbaio[m]>
nobody cares about embedded
<JamesMunns[m]>
the issue with the stack is that it CAN be reused even if the destructor is not called
<JamesMunns[m]>
which is not the case for alloc types
<whitequark[cis]>
and until that happens the decision is to just ship an unsound API?
<dirbaio[m]>
yes
<whitequark[cis]>
thanks I hate it
<JamesMunns[m]>
(for embassy, yes)
<dirbaio[m]>
ĀÆ\_(ć)_/ĀÆ
<JamesMunns[m]>
or has that made it into the e-h-async traits now too?
<dirbaio[m]>
sound, no-alloc, ergonomic: choose two
<dirbaio[m]>
embassy chooses no-alloc + ergonomic
<whitequark[cis]>
that's like choosing consistency and availability in the CAP theorem
<dirbaio[m]>
it's a valid choice imo
<dirbaio[m]>
especially in this case because "sound/unsound" is not so black and white
<dirbaio[m]>
you have to go out of your way to mem::forget() a future
<dirbaio[m]>
it's impossible to do it accidentally
<dirbaio[m]>
vs giving up "no-alloc" has a huge impact
<dirbaio[m]>
* the impact is tiny
<dirbaio[m]>
vs giving up "no-alloc" has a huge impact
<dirbaio[m]>
and giving up "ergonomic" has a huge impact too
<whitequark[cis]>
I mean the impact is that now embassy is actively deciding to ship an unsound API
<dirbaio[m]>
yes
<dirbaio[m]>
but it allows shipping no-alloc firmwares very fast, with an almost-zero risk of actual UB
<dirbaio[m]>
* allows shipping working no-alloc firmwares
<dirbaio[m]>
that's what matters at the end of the day
<JamesMunns[m]>
you could require a call to an unsafe fn i_solemnly_swear_to_never_forget() at the top of main :p
<whitequark[cis]>
lmfao
<JamesMunns[m]>
with a safety comment of // SAFETY: you must never forget a future that is holding a DMA transaction while it is active
<whitequark[cis]>
dirbaio[m]: not for me I suppose; I'd like to write my embedded firmware in Rust, not in a subset of Rust decided by whoever ships embassy
<dirbaio[m]>
then don't use Embassy
<JamesMunns[m]>
(this is part of why embassy is not a rust-embedded official project)
<dirbaio[m]>
š
<dirbaio[m]>
* š¤·
<whitequark[cis]>
JamesMunns[m]: I see
<JamesMunns[m]>
well, and tbh dirbaio is doing his own thing in his own project, and has been for a while, it's not like it's been proposed to merge it :)
<dirbaio[m]>
yeah I don't want Embassy to be a WG project
<whitequark[cis]>
I think I misunderstood the relationship between Embassy and the WG, honestly
<JamesMunns[m]>
r-e has been pretty "framework agnostic" - we've never attempted to make rtic or tock or embassy official
<dirbaio[m]>
I'm already upstreaming to the WG the parts that matter for interoperability (critical-section, embedded-hal-async, embedded-io)
<JamesMunns[m]>
we're sort of the "meeting place of people doing stuff, attempting to improve the common state of the art"
<dirbaio[m]>
everything else doesn't need to be part of the WG
<JamesMunns[m]>
JamesMunns[m]: We've also never said you MUST use these tools or whatever
<JamesMunns[m]>
tock-os notably has never had much overlap with r-e
<JamesMunns[m]>
but we still collab on occasion, at least when it comes to upstream discussions.
<whitequark[cis]>
there is still the stm32-metapac change, but as far as I understand that's something that can just be fixed by someone sufficiently motivated (probably me, once I find enough time to do it)
<JamesMunns[m]>
I think that's mostly adamgreig? not sure tho.
<JamesMunns[m]>
(or is metapac the embassy one?)
<whitequark[cis]>
I'm wondering if in Amaranth SoC we can add an attribute to the SoC metadata describing which bits can potentially impact memory safety and which cannot
<adamgreig[m]>
metapac is embassy, I maintain the stm32-rs ones
<adamgreig[m]>
Svd2rust is rewg, chiptool is embassy
<dirbaio[m]>
there's a ton of regs that can impact memory safety
<whitequark[cis]>
yep
<dirbaio[m]>
DMA, anything that remaps memory, pretty much all RCC, FLASH regs, voltage scaling...
<adamgreig[m]>
The "turn off the ram" bit, lol
<dirbaio[m]>
you're going to spend tons of time hunting down each and every one of them, marking them as unsafe
<dirbaio[m]>
then in the HAL you're going to need giant unsafe{} blocks with hard to justify safety contracts
<adamgreig[m]>
Or make it all unsafe all the time and have the HAL decide, I guess
<adamgreig[m]>
But now you have a million unsafe blocks
<whitequark[cis]>
adamgreig[m]: that's what it used to do
<dirbaio[m]>
adamgreig[m]: that's what metapac did before, and it sucked
<dirbaio[m]>
it drowns the "real" unsafe
<adamgreig[m]>
Yea, and masks a lot of actually unsafe stuff inside an unsafe block
<dirbaio[m]>
when I removed all the unsafe blocks I found quite a few places inside the giant unsafe{} blocks that were actual (not reg access) unsafe
Guest9119 has left #rust-embedded [Error from remote client]
<dirbaio[m]>
a few of them not properly documented/justified
<whitequark[cis]>
I would very much like to see "things that remap memory" require an unsafe block
<adamgreig[m]>
stm32ral has this concept
<adamgreig[m]>
A big "unsafe names" list of register names it will never make safe, even when otherwise fully described by the svd
<dirbaio[m]>
IMO the PAC is the wrong layer to create safe APIs
<dirbaio[m]>
it's the HAL
<adamgreig[m]>
And two types of register, one safe and one unsafe
<adamgreig[m]>
But yea, it's not great really. And it's obviously very easy to miss something
<whitequark[cis]>
dirbaio[m]: I'm also fine with blanket marking the PAC as `unsafe`
<dirbaio[m]>
PACs should be autogenerated and as dumb as possible
<whitequark[cis]>
I'm not fine with having unsound APIs all around (which in this case are pretty easy to trigger unintentionally, unlike with the previous example)
<dirbaio[m]>
embassy tried the "blanket mark as unsafe" thing, and it's been proven to increase the probability of bugs because it drowns the real unsafe in noise
<dirbaio[m]>
in Linux Rust you can safely open("/dev/mem") and write to arbitrary memory with seek() and write().
<whitequark[cis]>
I've started using Rust before it had volatile because I liked the promise of better embedded development (I didn't care about any other use of Rust back then) and memory safety guarantees were a big part of it
<dirbaio[m]>
should open() be blanket-marked as unsafe too? :)
<whitequark[cis]>
dirbaio[m]: which I consider a bug
<dirbaio[m]>
it's unfixable
<whitequark[cis]>
it is fixable
<whitequark[cis]>
you can check for /dev/mem access by looking at the major,minor
<whitequark[cis]>
the /proc/self/mem one is harder
dhylands[m] has joined #rust-embedded
<dhylands[m]>
IIRC only root can open /dev/men
<dhylands[m]>
s/men/mem/
<JamesMunns[m]>
dhylands[m]: Still unsafe for root
<whitequark[cis]>
whitequark[cis]: so a dependency shipping unsafe code, to me, is disregarding an important part of this promise. yes, there's an amount of work required. ambition usually does.
<JamesMunns[m]>
(I think the usual "next argument" here is "what about symlinks")
<whitequark[cis]>
s/unsafe/unsound/
<whitequark[cis]>
JamesMunns[m]: `lstat`
<whitequark[cis]>
or... whichever one is looking at the symlink target?
<whitequark[cis]>
anyway, like I mentioned, you can identify /dev/mem by the device numbers, it's an overhead of one syscall
<whitequark[cis]>
if you want to make a better argument you could say that spawning gdb and giving it a script that writes to one's memory is safe
crabbedhaloablut has quit []
<whitequark[cis]>
and there's nothing you can do about that
<dirbaio[m]>
what if your process inherits an already-opened /dev/mem as e.g. stdout?
<dhylands[m]>
And then what about custom drivers?
<dirbaio[m]>
what if smeone sends you a /dev/mem fd through e.g. unix socket fd passing?
<whitequark[cis]>
dirbaio[m]: oh, that's a good one
<whitequark[cis]>
actually, that... that soudns like a potential vulnerability?
<dirbaio[m]>
maybe these cases wouldn't be your mem, but the other process's mem? so it's fine?
<whitequark[cis]>
I think there's a bunch of Linux desktop things that rely on fd passing and write to the fd?
<whitequark[cis]>
hold on, is this going to become a CVE
<whitequark[cis]>
dirbaio[m]: no I am pretty sure that writing to the major,minor of /dev/mem is always your memory
<JamesMunns[m]>
Don't you need like ptrace perms to write to another process's memory space?
<dirbaio[m]>
probably not a vuln, the other process would've needed root to open /dev/mem
<dirbaio[m]>
and if it was root it could've directly ptrace'd you (?)
<JamesMunns[m]>
(or whatever perms ptrace needs or other sampling profilers or whatever)
<whitequark[cis]>
dirbaio[m]: without selinux yeah
<whitequark[cis]>
dirbaio[m]: then didn't we just reduce this to "running processes as root is inherently memory-unsafe"?
<whitequark[cis]>
this is a good argument for, e.g., not running anything except for pid1 as root, and delegating permissions elsewhere. which I'm all for
<JamesMunns[m]>
I have a long overdue opinion piece about how even system languages can only make guarantees within the environment of which they have defined
<JamesMunns[m]>
and the system extends beyond the scope of the environment defined or required by the programming language
<JamesMunns[m]>
not invalidating any points in either direction here, but "rust the abstract model" has no way of handling relatively obscure things like "we turned off half the wired memory"
<whitequark[cis]>
I do think that falls under Rust's unsafe
<JamesMunns[m]>
and open(/dev/mem) does invalidate the environmental contract of the rust abstract model
<JamesMunns[m]>
in that - all memory will have exclusive access
<whitequark[cis]>
what I want from Rust's unsafe is highlighting the places where my program could end up causing memory errors; turning off memory does tend to cause memory errors!
Guest9119 has joined #rust-embedded
<whitequark[cis]>
so does screwing up your clocking, so does resetting things that DMA (I don't think resetting something non-DMA-capable could cause a memory error)
<JamesMunns[m]>
whitequark[cis]: anything with XIP or internal flash
<whitequark[cis]>
(though I do realize that pretty much everything on an STM32 is DMA-capable)
<whitequark[cis]>
I really don't understand how "messing with memory should be memory-unsafe" is a controversial statement
<JamesMunns[m]>
whitequark[cis]: nrf52 too, every peripheral is dma only
<whitequark[cis]>
* should be considered memory-unsafe" is
<JamesMunns[m]>
whitequark[cis]: Second order effects of blanket marking ALL interactions as unsafe causing "unsafe fatigue"?
M9names[m] has quit [Quit: Idle timeout reached: 172800s]
<whitequark[cis]>
JamesMunns[m]: it's not all of them though? clocking, reset, and memory modules are a small subset of a typical SoC
<whitequark[cis]>
regardless of whether it's marked as unsafe I do want to see an explanation of why resetting this random peripheral would leave the rest of firmware functional
<whitequark[cis]>
not just because of DMA but because of deadlocks too
<whitequark[cis]>
(you could make this less bad for a typical firmware by making it so that enabling a clock and deasserting a reset is safe)
<JamesMunns[m]>
Deadlocks wouldn't be memory unsafe?
<whitequark[cis]>
they aren't
mattyinterrupt[m has joined #rust-embedded
<mattyinterrupt[m>
there are also valid scenarios for changing the clocks while running..
<whitequark[cis]>
let me rephrase: adding a justification for why it's memory-safe is only a part of an existing expectation I have about documenting a live reset of some peripheral
<JamesMunns[m]>
I think the issue here is that there is very limited developer-effort available
<JamesMunns[m]>
and I sorta agree with dirbaio - the time is better spent improving the hal level, than exhaustively improving the PAC
<whitequark[cis]>
mattyinterrupt[m: I'm not proposing forbidding that (or anything else in the PAC)
<JamesMunns[m]>
but I generally agree with everything you've said Catherine - in that having that fidelity would be good
<whitequark[cis]>
I'm only talking about aligning the PAC with Rust's soundness model
<JamesMunns[m]>
and if amaranth generates it, and it has good signal:noise vs "off the shelf" svds, it does change the balance
<whitequark[cis]>
dirbaio: btw, if you swap `/dev/mem` in your example with `/proc/self/mem` it becomes a lot stronger because you can access that anywhere
<whitequark[cis]>
it looks like if you hold an fd to /proc/self/mem open across an execve you will end up reading the wrong memory with no permission check?
<whitequark[cis]>
at least, according to the commit message?
<dirbaio[m]>
just the old process's virtual memory, not other processes's
<whitequark[cis]>
yes, but setuid processes exist
<whitequark[cis]>
I guess you still have to trick one into opening that or something
<whitequark[cis]>
it's still a really... weird way to do things
<JamesMunns[m]>
Has it changed again in the last 13 years?
<JamesMunns[m]>
or is that still the current state?
<JamesMunns[m]>
(I know almost nothing about linux internals, so š )
<whitequark[cis]>
ultimately the basis of Rust's safety guarantees is "the only way to access memory is that bit of memory" and anything that violates that will undermine it
<whitequark[cis]>
James Munns: ah, thanks
<JamesMunns[m]>
whitequark[cis]: I dunno if that's still where you end up if you open proc self mem
<whitequark[cis]>
whitequark[cis]: the two possible approaches is "try to fit the environment to be more like Rust's expectations" and "give up on that"
<whitequark[cis]>
I want to be able to make claims about my embedded Rust code that are fundamentally stronger than what I can make about my embedded C++ code
<whitequark[cis]>
and I'm happy to pay the cost for it, in development time, (sometimes) runtime, etc
<whitequark[cis]>
back in pre-1.0 times when I picked up Rust, it was also a significant opportunity cost, as no one even applied it to embedded before, as far as I know (didn't we try to figure it out before?)
<whitequark[cis]>
if I go through my notes in that period, the main alternative to Rust I considered was Scheme and my own, long discontinued, language
<whitequark[cis]>
so of course I'd go with "yes I'm going to chase down a bunch of places in a PAC where you could have memory unsafety"; that's way cheaper than developing and promoting your own Rust-like language from scratch!
<whitequark[cis]>
s/alternative/alternatives/
<whitequark[cis]>
* so of course I'd go with "yes I'm going to chase down a bunch of places in a PAC where you could have memory unsafety"; that's way cheaper than developing and promoting your own Rust-like language from scratch!
<whitequark[cis]>
I'm quite serious about it :p
<dirbaio[m]>
well if you want to, PRs welcome to stm32-data / chiptool
<whitequark[cis]>
smoltcp exists because instead of the practical solution of "I'll just find the bug in lwIP" I went with "I'm going to design and implement a TCP/IP stack from scratch"
<dirbaio[m]>
i'd result in some big unsafe blocks in embassy-stm32, probably mainly rcc, but I'd be OK with that
<dirbaio[m]>
as long as it's not all regs like before
<whitequark[cis]>
perfect! I'm happy to collaborate on that; I do like stm32-metapac
<dirbaio[m]>
the leakpocalypse thing on the other hand is a lost cause š„²
<whitequark[cis]>
it... yeah I honestly don't know what to do about it
<whitequark[cis]>
I'm considering actually making the "subsetting Rust" thing official
<whitequark[cis]>
or... actually, dirbaio, do you know what's the typical lifetime of the future? as in, how does the translated code for it and its environment look like?
<whitequark[cis]>
I'm wondering if it's possible to make an (unstable) attribute that marks the future as something that needs to be dropped in view of the compiler or it's an error to compile
<whitequark[cis]>
I don't know enough about async to say if this is feasible
<JamesMunns[m]>
That sounds a lot like ?Leak?
<whitequark[cis]>
James Munns: except not in the type system
<whitequark[cis]>
which makes it uglier but cheaper
<dirbaio[m]>
they become fields in bigger futures which are fields in bigger futures, then the executor puts the top level task's future in a static
<dirbaio[m]>
futures are like "fancy enums" where each variant is a state (one .await point) and the variant's contents are the locals alive through that point
<dirbaio[m]>
so typically a future gets stored there and then dropped when it completes and the parent advances to the next state
<dirbaio[m]>
that applies to rust-generated async fn and async{} only though
<dirbaio[m]>
you can also write futures by hand
<whitequark[cis]>
James Munns: if it's not in the type system, you can be a lot less principled about it, meaning you can just reject otherwise valid programs because someone used this attribute
<dirbaio[m]>
and there's cases where what you want to be unleakable is not a future, but a struct. for example in BufferedUart it's the whole BufferedUart what must be unleakable, not the read/write futures.
<JamesMunns[m]>
whitequark[cis]: I'll have to defer to you! Lang design and rustc impl is not my area of expertise, for sure.
<dirbaio[m]>
because BufferedUart is what keeps DMA active at all times
<dirbaio[m]>
so an attribute-based solution that only works in futures wouldn't cover all cases
<dirbaio[m]>
it'd have to work on arbitrary types
<whitequark[cis]>
JamesMunns[m]: I have a decent grasp of lang design but not of rustc impl, hence my question
<dirbaio[m]>
at which point it looks exactly like an auto trait
<whitequark[cis]>
dirbaio[m]: unless you implement it as a global flow analysis and ignore all the complicated cases like "the task exists on the heap and not in a static"
<whitequark[cis]>
I don't know if it'll work and make no claims to how valid my guesses are, but my gut feel is that this might just work enough to investigate it
<whitequark[cis]>
I think it would be cool if a global analysis you could pull in somehow would be what makes embassy entirely sound
<dirbaio[m]>
my gut feeling is you'd be reimplementing (a dumb version of) the trait solver
<whitequark[cis]>
without gating it on T-lang
<dirbaio[m]>
because you have stuff like "Option<T> is leakable only if T is leakable"
<whitequark[cis]>
dirbaio[m]: no this would happen entirely after the type system accepts the code
<whitequark[cis]>
it would be a MIR check probably
<dirbaio[m]>
doing it post-mono would get you in C++-territory of "templates only fail if you try to actually instantiate them"
<whitequark[cis]>
so all of the types exist in their concrete forms
<dirbaio[m]>
which would suck
<whitequark[cis]>
dirbaio[m]: yes
<dirbaio[m]>
and is unlikely to get merged
<whitequark[cis]>
but that lets you use Rust and not non-mechanically-defined-subset-of-Rust
<whitequark[cis]>
there are other things you want to do in embedded that have the same flavor to them
<whitequark[cis]>
for example, stack overflow checking
<dirbaio[m]>
and if we're going to maintain a fork, we might as well implement ?Leak in the type system proper in it
<whitequark[cis]>
you can only do that post-codegen and only for some call trees
<whitequark[cis]>
dirbaio[m]: I do not mind that option, but my proposal lets us stay compatible with everything on crates.io syntactically, which is useful
<dirbaio[m]>
yeah...
<whitequark[cis]>
anyway, thanks James Munns and dirbaio for the discussion, I now understand the problem domain a lot better and even have a potential solution (that I probably won't return to for years); it is now night, which means it is time to duct tape a lens to this image intensifier and spy on cats :3
<dirbaio[m]>
meow
<whitequark[cis]>
meow!
<adamgreig[m]>
Thermal cam has been my go-to for finding cats in the dark. But the downside is they look terrifying in IR
<adamgreig[m]>
Nvd seems better :p
<whitequark[cis]>
I'm really excited about my NVD
<whitequark[cis]>
it's a Gen3 tube so the image is supposed to be really good
diondokter[m] has joined #rust-embedded
<diondokter[m]>
<adamgreig[m]> "Thermal cam has been my go-to..." <- Lol, maybe I should buy one. It's night here too and one of my cats hasn't returned yet. Kinda waiting on her now
<whitequark[cis]>
holy shit this tube is incredible
<whitequark[cis]>
I don't have any way to take a picture of it (I'm not joking about the duct tape) but the image quality is mindblowing
<whitequark[cis]>
it's approaching video game night vision levels
<diondokter[m]>
<diondokter[m]> "Lol, maybe I should buy one. It..." <- Found her after a 5 minute walk through the neighborhood!
<dirbaio[m]>
your cats are lucky to be able to roam around so freely
<dirbaio[m]>
can't do that in the city :P
<whitequark[cis]>
I think a thermal cam is better for finding cats
<whitequark[cis]>
but a night vision device is better for chasing cats
<whitequark[cis]>
ideally you would have both, or maybe one eye with a thermal vision device, another with a night vision one
<whitequark[cis]>
I'm normal
<whitequark[cis]>
and can be trusted with milsurp equipment
<diondokter[m]>
Haha luckily my cat does come when I call her, but that doesn't work when she's out of audible range. And I'm not gonna scream in the middle of the night in a neighborhood š
<adamgreig[m]>
my cat will absolutely ignore calling, but shaking her food bag usually gets results
<adamgreig[m]>
she also really doesn't care to go outside though so it's not usually a problem
alianunnaki[m] has quit [Quit: Idle timeout reached: 172800s]
gdamjan[m]1 has quit [Quit: Idle timeout reached: 172800s]
Foxyloxy has quit [Read error: Connection reset by peer]