300: Fix OOB get_unchecked, shadow Vec::as_ptr methods r=japaric a=saethlin
The fixes in #280 missed one instance of UB. The get_unchecked_mut
inside VacantEntry::Insert can be out of bounds of the initialized
region of the backing Vec. When that happens, the call is UB. This is
detected both by the standard library's debug assertions which can be
enabled with -Zbuild-std and with Miri but only with
-Zmiri-tag-raw-pointers.
This also adds inherent as_ptr and as_mut_ptr methods to Vec which
shadow those provided by the Deref to a slice. Without this shadowing,
the change from get_unchecked_mut to as_mut_ptr.add wouldn't actually
fix the problem identified by the debug assertions or Miri, it just
hides it from the debug assertions. The core problem is that references
narrow provenance, so if we want to access outside of the initialized
region of a Vec we need to get a pointer to the array without passing
through a reference to the initialized region first. The pointers from
these shadowing methods can be used to access anywhere in the allocation,
whereas vec.as_slice().as_ptr() would be UB to use for access into the
uninitialized region.
Co-authored-by: Ben Kimock <kimockb@gmail.com>
The fixes in #280 missed one instance of UB. The get_unchecked_mut
inside VacantEntry::Insert can be out of bounds of the initialized
region of the backing Vec. When that happens, the call is UB. This is
detected both by the standard library's debug assertions which can be
enabled with -Zbuild-std and with Miri but only with
-Zmiri-tag-raw-pointers.
This also adds inherent as_ptr and as_mut_ptr methods to Vec which
shadow those provided by the Deref to a slice. Without this shadowing,
the change from get_unchecked_mut to as_mut_ptr.add wouldn't actually
fix the problem identified by the debug assertions or Miri, it just
hides it from the debug assertions. The core problem is that references
narrow provenance, so if we want to access outside of the initialized
region of a Vec we need to get a pointer to the array without passing
through a reference to the initialized region first. The pointers from
these shadowing methods can be used to access anywhere in the allocation,
whereas vec.as_slice().as_ptr() would be UB to use for access into the
uninitialized region.
277: Add support for Arduino Uno and 2560 r=japaric a=mutantbob
This patch includes changes I needed to build my Arduino Uno sketches. I incorporated the work from https://github.com/japaric/heapless/pull/264 to reduce the chance of conflicts.
Now that atomic-polyfill 0.1.8 supports AVR, things are a bit easier.
Co-authored-by: Robert Forsman <git@thoth.purplefrog.com>
298: compile-time check power of two invariant in Index{Set,Map}'s default method r=korken89 a=japaric
closes#295
I tested this manually with both `FnvIndexSet` and `FnvIndexMap`. I tried to add a compile fail test but discovered (the hard way) that all the const assert trickery in `sealed` is checked when the code is built with `cargo build` but *not* when the code is built with `cargo check`. As `trybuild` uses `cargo check` under the hood it's not possible to compile fail test any of those const asserts.
r? `@korken89`
Co-authored-by: Jorge Aparicio <jorge.aparicio@ferrous-systems.com>
299: remove the scoped_threads feature gate r=japaric a=japaric
the feature has been stabilized in a recent nightly
Co-authored-by: Jorge Aparicio <jorge.aparicio@ferrous-systems.com>
262: add BinaryHeap::into_vec r=japaric a=Lambda-Logan
std::collections::BinaryHeap provides an into_vec method https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html#method.into_vec
My use case is I want a sorted iterator similar to BinaryHeap.into_sorted_iter. I found my self creating a new heapless:Vec from heapless::BinaryHeap::into_iter and then sorting it. It seemed better to return the underlying vec and sort that.
But the functionality seemed generally useful and helps the API jive a little better with std::collections::BinaryHeap.
Do you see any issues with this implementation? Also, apologies for anything weird... This is my first PR :)
Co-authored-by: Logan Dimond <Lambda.Dimond@gmail.com>
Co-authored-by: Logan Dimond <lambda.dimond@gmail.com>
293: unconditionally depend on atomic-polyfill for riscv32i target r=japaric a=japaric
due to a limitation in the llvm backend [1] the `riscv32i-unknown-none-elf` target lacks the `core::sync::atomic` API even though the actual hardware is capable of atomic loads and stores (`fence` instruction). thus, at this point in time, this target needs `atomic-polyfill` for a working SPSC implementation
[1]: https://github.com/knurling-rs/defmt/issues/597#issuecomment-934467023fixes#271closes#272closes#273
Co-authored-by: Jorge Aparicio <jorge.aparicio@ferrous-systems.com>
264: Add support for AVR. r=japaric a=jeremysalwen
In order to support AVR, the following changes were made:
- AVR was added to the list of architectures not supporting atomics or cas.
- AVR was configured to not use AtomicUsize, similarly to armv6m.
- SortedLinkedList was modified to account for the fact that usize is differently sized on
different architectures (16 bits on AVR).
Co-authored-by: Jeremy Salwen <jeremysalwen@gmail.com>
289: entry API for IndexMap r=japaric a=japaric
rebased version of PR #276
`@MarcusGrass` thanks for the PR!
Co-authored-by: gramar <marcus.grass@gmail.com>
Co-authored-by: Jorge Aparicio <jorge.aparicio@ferrous-systems.com>
274: Implement FromIterator for String r=japaric a=VersBinarii
Implements FromIterator trait on String.
It also addresses issue: https://github.com/japaric/heapless/issues/245
Co-authored-by: VersBinarii <versbinarii@gmail.com>
280: Fix undefined behavior identified by Miri r=japaric a=jgallagher
Hi! We ran into an exception triggered by new undefined behavior checks inserted into the nightly compiler (https://github.com/rust-lang/rust/pull/92686/files#diff-54110dcedc5a4d976321aa5d2a6767ac0744a3ef1363b75ffc62faf81cf14c30R230-L229). Running `heapless`'s test suite under Miri didn't flag anything at first, but it did once we added `MIRIFLAGS="-Zmiri-tag-raw-pointers"`. All three of the fixes in this PR were identified via
```
MIRIFLAGS="-Zmiri-tag-raw-pointers -Zmiri-ignore-leaks" cargo +nightly miri test -- --skip pool::
```
and the fixes came from copying the implementations from the equivalent methods in `std`. Note that I skipped the `pool::` tests; there is at least one miri failure in them, but it wasn't immediately obvious how to fix it so I skipped it for now. It's probably worth adding the flag above to the CI miri run, but I didn't do that either (since it would immediately cause failures given I didn't fix the problem in `pool`).
The specific output for `pool` is
```
test pool::singleton::tests::sanity ... error: Undefined Behavior: trying to reborrow <untagged> for SharedReadWrite permission at alloc36[0x1], but that tag does not exist in the borrow stack for this location
--> /home/john/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/non_null.rs:380:18
|
380 | unsafe { &*self.as_ptr() }
| ^^^^^^^^^^^^^^^
| |
| trying to reborrow <untagged> for SharedReadWrite permission at alloc36[0x1], but that tag does not exist in the borrow stack for this location
| this error occurs as part of a reborrow at alloc36[0x1..0x9]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
= note: inside `std::ptr::NonNull::<pool::stack::Node<u8>>::as_ref` at /home/john/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/non_null.rs:380:18
note: inside `pool::stack::Stack::<u8>::push` at src/pool/cas.rs:43:17
--> src/pool/cas.rs:43:17
|
43 | / new_head
44 | | .as_raw()
45 | | .as_ref()
| |_____________________________^
note: inside `pool::Pool::<u8>::grow` at src/pool/mod.rs:390:25
--> src/pool/mod.rs:390:25
|
390 | self.stack.push(p);
| ^^^^^^^^^^^^^^^^^^
note: inside `<pool::singleton::tests::sanity::A as pool::singleton::Pool>::grow` at src/pool/singleton.rs:78:9
--> src/pool/singleton.rs:78:9
|
78 | Self::ptr().grow(memory)
| ^^^^^^^^^^^^^^^^^^^^^^^^
note: inside `pool::singleton::tests::sanity` at src/pool/singleton.rs:362:9
--> src/pool/singleton.rs:362:9
|
362 | A::grow(unsafe { &mut MEMORY });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside closure at src/pool/singleton.rs:353:5
--> src/pool/singleton.rs:353:5
|
352 | #[test]
| ------- in this procedural macro expansion
353 | / fn sanity() {
354 | | const SZ: usize = 2 * mem::size_of::<Node<u8>>() - 1;
355 | | static mut MEMORY: [u8; SZ] = [0; SZ];
356 | |
... |
373 | | assert_eq!(*A::alloc().unwrap().init(1), 1);
374 | | }
| |_____^
= note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
```
Co-authored-by: John Gallagher <john@oxidecomputer.com>