<thejpster[m]>
they are not unsafe to call (they may just print a message and return an integer, which is totally safe), but when called by the ASM exception handlers, the choice of returned value can very easily lead to UB.
<whitequark[cis]>
i think that if you wanted to do this in a rigorous way, you would make the function safe, but the return value a newtype around usize which is unsafe to construct
<whitequark[cis]>
and which is also passed as an argument (modulo that i don't know aarch64 semantics enough to know if you have a choice of arg or arg+4, or if it's essentially fixed per exception handler)
<whitequark[cis]>
in my opinion the semantic you describe translates to, essentially, "the function must require unsafe { return ...; }" but that's not really a thing in rust, and what i'm suggesting is the next closest thing
<whitequark[cis]>
you could also make the function `-> !` and have a function/macro with a bit of inline assembly that does the actual return that would be unsafe to call and required in lieu of falling off the end or a `return` statement
<whitequark[cis]>
from my experience with other architectures, I would lean toward the former since it allows writing entirely safe exception handlers by passing in the !Clone newtype as a token and then requiring it back as a return value, which you can't do with a exception_return!(addr) macro. it's also conceptually a bit simpler than a macro, i think
korbin[m] has quit [Quit: Idle timeout reached: 172800s]
<JamesMunns[m]>
I don't really have any context, but "you need a type that is unsafe to create to return" from a function seems like a really neat trick.
<JamesMunns[m]>
It would also mean you could safely define a handler that diverges with `!`
<JamesMunns[m]>
real hotel california approach to safety
<whitequark[cis]>
(hotel california?)
<JamesMunns[m]>
"you can check in any time you like, but you can never leave"
<JamesMunns[m]>
(it's a song by the Eagles)
<whitequark[cis]>
<JamesMunns[m]> "I don't really have any context,..." <- i use these types of tricks a lot; they are natural to me because i think of rustc as an automated proof assistant. in this case i request the programmer to prove they have discharged their obligations by presenting a witness value
<JamesMunns[m]>
yep! totally makes sense, it's just not a trick I'd seen before, and I'm definitely going to remember it :D
<whitequark[cis]>
but i also see a lot of people just go for "make the thing unsafe" when this doesn't actually prevent the unsafety from happening and it confuses me a bit, i guess just because i have a different context and am familiar with different approaches
<JamesMunns[m]>
ive seen it on ENTRY to a function, critical section tokens work like that. just never on EXIT of a function
<whitequark[cis]>
btw, you should also make the token !Send, !Sync since otherwise you could theoretically use one exception handler to stash it somewhere before never returning (exploding or spinning forever) while another exception handler later fetches the token and uses it to cause havok
<whitequark[cis]>
nobody would actually do this but the unsoundness of this case bothers me too much to not mention it
<whitequark[cis]>
if you put a raw pointer inside that should do the trick
pcs38 has quit [Quit: leaving]
jannic[m] has joined #rust-embedded
<jannic[m]>
And make sure that you can't call such a function from rust code: I didn't check, but I guess that calling a function that's `-> !` but that in fact returns using some `asm!` trickery is also UB, as the compiler won't expect that such a function ever returns and there may not be a next instruction to return to.
<jannic[m]>
* > you could also make the function -> ! and have a function/macro with a bit of inline assembly that does the actual return
<jannic[m]>
And make sure that you can't call such a function from rust code: I didn't check, but I guess that calling a function that's `-> !` but that in fact returns using some `asm!` trickery is also UB, as the compiler won't expect that such a function ever returns and there may not be a next instruction to return to.
dirbaio[m] has joined #rust-embedded
<dirbaio[m]>
How's this handled in cortex-m? You can also return from exceptions there
<jannic[m]>
You can't (easily) call the exception handlers from rust code IIRC, I don't remember how it was implemented, some name mangling by the exception macro probably.
<jannic[m]>
And if the exception handler is called by some actual exception, that's fine: There's never been an actual function call or return from the "caller"'s point of view. It would only be a problem if some rust code manually called such an exception handler.
sroemer has quit [Quit: WeeChat 4.5.2]
adamgreig[m] has joined #rust-embedded
<adamgreig[m]>
the cortex-m exception handlers can't change where execution resumes with their return value, unlike the ones proposed in cortex-ar, aiui
<adamgreig[m]>
so in cortex-m we need to ensure you don't call the exception handler from rust code (by name mangling as jannic mentioned) but we don't care about being able to return
<adamgreig[m]>
there is talk of having HardFault be given an &mut argument that would allow this, though
<thejpster[m]>
Yeah I want to let you recover from a faulting instruction by returning to the one after
<thejpster[m]>
I could change to to return an enum { TryAgain, SkipIt }
<thejpster[m]>
But I didn’t want to rule out returning to arbitrary places, like you might do in an RTOS when it switches tasks.
<thejpster[m]>
Also the number of bytes you have to skip is 4 if you faulted on an A32 instruction but 2 (or maybe 4) on a T32 instruction.
<thejpster[m]>
I think what I have is ok for a v0.2 and the PR is probably large enough already.
<thejpster[m]>
I’d be very happy to see other people contribute ideas here. We have lots of examples that we test in CI so you can refactor fearlessly.
<whitequark[cis]>
(wouldn't you need to swap the stack and the context in an RTOS?)
<thejpster[m]>
Yes, but you could probably just change the stack pointer and let the normal context restore in the asm trampoline restore a different context.
pcs38 has joined #rust-embedded
pcs38 has quit [Quit: leaving]
Kaspar[m] has joined #rust-embedded
<Kaspar[m]>
<thejpster[m]> "Yes, but you could probably just..." <- That's pretty much how RTOSes do the context switch on CortexM. And deal with the high regs that the exception entry/exit doesn't save/restore.
cr1901_ has quit [Read error: Connection reset by peer]