1

I'm working on a project around embedded systems that needs to use filesystem. I want to use liitlefs crate in rust but it uses mem::uninitialized that deprecated since 1.39.0 . https://github.com/brandonedens/rust-littlefs

pub struct LittleFs<T: Storage> {
    storage: T,
    lfs_config: lfs::lfs_config,
    lfs: lfs::lfs_t,
    read_buffer: [u8; READ_SIZE],
    prog_buffer: [u8; PROG_SIZE],
    lookahead_buffer: [u8; LOOKAHEAD / 8],
}

impl<T: Storage> LittleFs<T> {
    /// Create a new instance of the LittleFS.
    pub fn new(storage: T) -> Self {
        LittleFs {
            storage: storage,
            lfs: unsafe { mem::uninitialized::<lfs::lfs>() },
            lfs_config: unsafe { mem::uninitialized::<lfs::lfs_config>() },
            read_buffer: [0u8; READ_SIZE],
            prog_buffer: [0u8; PROG_SIZE],
            lookahead_buffer: [0u8; LOOKAHEAD / 8],
        }
    }

I tried to replace it in the following way but it caused unspecified behaviors by the system:

pub struct LittleFs<T: Storage> {
    storage: T,
    lfs_config: lfs::lfs_config,
    lfs: lfs::lfs_t,
    read_buffer: [u8; READ_SIZE],
    prog_buffer: [u8; PROG_SIZE],
    lookahead_buffer: [u8; LOOKAHEAD / 8],
}

impl<T: Storage> LittleFs<T> {
    pub fn new(storage: T) -> Self {
        LittleFs {
            storage,
            lfs: unsafe { MaybeUninit::uninit().assume_init() },
            lfs_config: unsafe { MaybeUninit::uninit().assume_init() },
            read_buffer: [0u8; READ_SIZE],
            prog_buffer: [0u8; PROG_SIZE],
            lookahead_buffer: [0u8; LOOKAHEAD / 8],
        }
    }

Does anyone have a solution to this problem? Thank you in advance.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
p3zhy
  • 81
  • 8
  • 4
    You can't do `uninit().assume_init()` -- it's definitely *not* initialized. `assume_init()` is only to be called once the data *is* initialized with real values. You'll need to change `lfs` to `MaybeUninit` and then deal with the downstream modifications needed in any code that accesses the field. – John Kugelman Jan 20 '22 at 18:32
  • 1
    You'll need `MaybeUninit` fields, or to return `MaybeUninit`. – mcarton Jan 20 '22 at 18:49
  • 2
    Is there a particular reason you need to use that crate? It hasn't been updated in 3 years - not something what I would rely on. – Colonel Thirty Two Jan 20 '22 at 19:01
  • @JohnKugelman If I do this then how can I rewrite this function for example: `pub fn format(&mut self) -> Result<(), FsError> { self.lfs_config.write(self.create_lfs_config()); let res = unsafe { lfs::lfs_format(&mut self.lfs, &self.lfs_config) }; lfs_to_fserror(res)}` – p3zhy Jan 20 '22 at 19:39
  • `MaybeUninit::uninit().assume_init()` is basically the same as `mem::uninitialized()`, and the reason it was deprecated is because it is UB for most types. – Chayim Friedman Jan 20 '22 at 21:03
  • 2
    This crate is crap. Calling any method on `LittleFs` without first calling `mount` or `format` means it uses the uninitialized lfs handle - something against the "no memory unsafety without `unsafe`" contract that safe rust is supposed to uphold. Similar issues with the `File` and `Dir` types. – Colonel Thirty Two Jan 20 '22 at 22:07

1 Answers1

4

You can't do uninit().assume_init() — it's definitely not initialized. assume_init() is only to be called once the data has been initialized with real values. The idea behind calling it is that you're promising, "Yes, I know this value is marked as maybe initialized. I promise that it is initialized now. It's not just a maybe."

You'll need to change the types of lfs and lfs_config:

lfs_config: MaybeUninit<lfs::lfs_config>,
lfs: MaybeUninit<lfs::lfs_t>,

That will have a ripple effect downstream, requiring you to then modify any code that accesses the fields.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578