Skip to content
This repository has been archived by the owner on Jan 24, 2022. It is now read-only.

Disable default-features on rand dependency to avoid std version #107

Merged
merged 3 commits into from
Sep 8, 2018

Conversation

therealprof
Copy link
Contributor

Due to the single dependency tree, the attempted use of a std version
flips all depending crates to the std version as well which will not
compile on no_std systems.

Fixes #105

Signed-off-by: Daniel Egger daniel@eggers-club.de

@therealprof therealprof requested a review from a team as a code owner September 6, 2018 20:49
@japaric
Copy link
Member

japaric commented Sep 6, 2018

LGTM. Could you add an example that links to rand with default features disabled? That should serve as a regression test.

@japaric
Copy link
Member

japaric commented Sep 6, 2018

note that to get the example to build on CI you'll have to add it:

cortex-m-rt/ci/script.sh

Lines 14 to 28 in 5baa082

local examples=(
alignment
divergent-default-handler
divergent-exception
entry-static
main
minimal
override-exception
pre_init
state
unsafe-default-handler
unsafe-hard-fault
unsafe-entry
unsafe-exception
)

@therealprof
Copy link
Contributor Author

therealprof commented Sep 6, 2018

Shouldn't any of the existing examples do? The rand stuff is used for generation of unique linker symbols, no?

@therealprof
Copy link
Contributor Author

@japaric Please have a look now.

@japaric
Copy link
Member

japaric commented Sep 6, 2018

Hmm, the build is failing since the first commit with: "error[E0658]: use of unstable library feature 'rustc_private'", and I don't understand why ...

@therealprof
Copy link
Contributor Author

😀. And now travis-ci is running into the exact same problem I mentioned in the ticket before...

@therealprof
Copy link
Contributor Author

I think it's because the version seems to be newer than the upstream version so it uses that instead which triggers this problem. As I said: I'm having the same troubles locally.

proc-macro2 = "0.4.15"

[dependencies.syn]
features = ["extra-traits", "full"]
version = "0.14.8"

[depedencies.rand]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh lol. I see the problem. This is a typo; the "n" is missing after "depe".

@japaric
Copy link
Member

japaric commented Sep 6, 2018

The typo solves the weird "rustc_private" issue, but this still doesn't work because thread_rng doesn't exist in rand w/o default features.

@therealprof how did you get this working locally?

@therealprof
Copy link
Contributor Author

I simply compiled the example via cargo build --example rand. Worked without problems.

@therealprof
Copy link
Contributor Author

LOL and of course once I fixed the type it does not compile anymore. 😀

Raining lemons today...

@japaric
Copy link
Member

japaric commented Sep 6, 2018

@therealprof you didn't add #![feature(rustc_private)] to macros/src/lib.rs right? That would "fix" the problem by making the crate using the rand shipped with the toolchain but we can't use that because it's unstable.

@therealprof
Copy link
Contributor Author

That's indeed what I did. Do you want me to rewrite the rand stuff in macros to use the seedable rng which works in no_std?

@japaric
Copy link
Member

japaric commented Sep 6, 2018

Do you want me to rewrite the rand stuff in macros to use the seedable rng which works in no_std?

Yes, please. Though, I'm concerned that using a seed which is not randomly generated will result in (a) predictable identifiers which then the user can the use to call exception handlers breaking the non-reentrant invariant, and / or (b) collisions between #[entry] fn foo() -> ! { .. } and #[pre_init] unsafe fn foo() {} if the seed is derived from the identifier.

@therealprof
Copy link
Contributor Author

therealprof commented Sep 6, 2018

@japaric Well, the stuff is not really cryptographic anyway. If someone wants to desperately do bad stuff with the entry points, they can still do it. Collisions would be indeed a problem but a rand::SeedableRng is not going to have more of a collision than the threaded rng. We could use mem::uninitialized() to seed the RNG, that would make it slightly more unpredictable, if you're worried about reusing the same seed over and over again.

@japaric
Copy link
Member

japaric commented Sep 6, 2018

If someone wants to desperately do bad stuff with the entry points, they can still do it.

They can't with the current implementation.

If they call cargo expand and see that entry was renamed to bsb49kvt39ff0w29 and then modify their code to call bsb49kvt39ff0w29 it won't compile next time because the attribute will generate a different identifier. The key property here is that the attribute produces a different identifier on each run. It's not important what RNG is used; it's important that the seed of the RNG is different on each run.

We could use mem::uninitialized() to seed the RNG

That could turn into UB in any future LLVM release so it's not an option.

@adamgreig
Copy link
Member

Can we just prevent the function from being called from safe code? I get that we can't just hide it in a private module (sadly, as that seems like it would totally fix the issue) but perhaps we can stick it inside an unsafe function wrapper with a predictable name? Or any other options to avoid rand?

Otherwise... seed with the build time... 😈

@therealprof
Copy link
Contributor Author

If they call cargo expand and see that entry was renamed to bsb49kvt39ff0w29 and then modify their code to call bsb49kvt39ff0w29 it won't compile next time because the attribute will generate a different identifier.

Sure... but then again if someone really wants to do it they can do still it after the fact, i.e. without recompiling from source.

it's important that the seed of the RNG is different on each run.

Well, it's a new feature anyway. 😏

That could turn into UB in any future LLVM release so it's not an option.

Uhm....

Otherwise... seed with the build time... 😈

Or address of something in the running process. ;)

@japaric
Copy link
Member

japaric commented Sep 6, 2018

perhaps we can stick it inside an unsafe function wrapper with a predictable name?

That's an option but we would need a trampoline to preserve the safety that the user declared:

#[exception]
fn SysTick() { .. }

// expands into
#[no_mangle]
pub unsafe fn SysTic() {
    // copy paste the user function here
    #[inline(always)]
    fn SysTick() { .. }

    SysTick()
}

Otherwise... seed with the build time...

Seed with Instant::now().nanos() or something like that, maybe.

@japaric
Copy link
Member

japaric commented Sep 6, 2018

Uhm....

You should read through the Unsafe Code Guidelines team discussions. Apparently most unsafe operations are UB now. In any case, mem::uninitialized is going to be deprecated in favor of MaybeUninit and it's UB to read out its inner value if it has not been previously initialized.

@therealprof
Copy link
Contributor Author

You should read through the Unsafe Code Guidelines team discussions. Apparently most unsafe operations are UB now. In any case, mem::uninitialized is going to be deprecated in favor of MaybeUninit and it's UB to read out its inner value if it has not been previously initialized.

I'm aware of MaybeUninit and general I agree with the notion of having everything sane and safe. But sometimes it is sufficient to know something exists (like a address in memory) without caring about it's value...

Due to the single dependency tree, the attempted use of a std version
flips all depending crates to the std version as well which will not
compile on no_std systems.

Fixes rust-embedded#105

Signed-off-by: Daniel Egger <daniel@eggers-club.de>
Signed-off-by: Daniel Egger <daniel@eggers-club.de>
@therealprof
Copy link
Contributor Author

... and of course the Rng is seeded on each invocation of the random token function while the seed is only increasing each second which one fast machines means: crap (and I've been able to experience it first hand). I've added an atomic counter, increased on each invocation (much easier than the pro way of initialising once and reusing the same Rng), to continuously change the seed. Now collisions are a thing of the past.

Copy link
Member

@japaric japaric left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. r=me with nits addressed.


use core::mem;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why core::mem and not std::mem?

@@ -492,7 +499,10 @@ pub fn pre_init(args: TokenStream, input: TokenStream) -> TokenStream {

// Creates a random identifier
fn random_ident() -> Ident {
let mut rng = rand::thread_rng();
let seed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
CALL_COUNT.fetch_add(1, Ordering::SeqCst);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This returns the previous value. Why not use that instead of doing another atomic load?

let seed = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
CALL_COUNT.fetch_add(1, Ordering::SeqCst);
let seed = [seed, CALL_COUNT.load(Ordering::SeqCst) as u64];
let mut rng = rand::rngs::SmallRng::from_seed( unsafe { mem::transmute(seed) } );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not use unsafe code here. There are methods to go from u64 to [u8; 8] and vice versa that could be used here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To the best of my knowledge only in nightly...
https://doc.rust-lang.org/nightly/std/primitive.u64.html#method.to_be_bytes

Of course I could do some bitmasking. ;)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To the best of my knowledge only in nightly...

Still? I thought it was already stabilized. Perhaps I was thinking of f32.to_bits.

Of course I could do some bitmasking. ;)

I would prefer that over unsafe code.

@adamgreig
Copy link
Member

Could we use .subsec_nanos() instead of .as_secs() to avoid the issue? I'm not sure which systems have std but don't give nanosecond-level timers...

@therealprof
Copy link
Contributor Author

Could we use .subsec_nanos() instead of .as_secs() to avoid the issue? I'm not sure which systems have std but don't give nanosecond-level timers...

Where did you dig that out? 😲
However that only yields a 32 bit value so that doesn't simplify things...

@adamgreig
Copy link
Member

I was more thinking you could seed it once with that and then not worry about the counter. Though I guess you have to do the same twiddling to turn it into [u8; 8].

The RNG is seeded from the current time and an counter increasing with
each call to yield different random values on each invocation.

Signed-off-by: Daniel Egger <daniel@eggers-club.de>
@therealprof
Copy link
Contributor Author

So... bit twiddling it is.

Copy link
Member

@japaric japaric left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

bors r+

bors bot added a commit that referenced this pull request Sep 8, 2018
107: Disable default-features on rand dependency to avoid std version r=japaric a=therealprof

Due to the single dependency tree, the attempted use of a std version
flips all depending crates to the std version as well which will not
compile on no_std systems.

Fixes #105

Signed-off-by: Daniel Egger <daniel@eggers-club.de>

Co-authored-by: Daniel Egger <daniel@eggers-club.de>
@bors
Copy link
Contributor

bors bot commented Sep 8, 2018

Build succeeded

@bors bors bot merged commit ca4e52b into rust-embedded:master Sep 8, 2018
@korken89
Copy link
Contributor

korken89 commented Sep 9, 2018

Great work!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants