littlefs icon indicating copy to clipboard operation
littlefs copied to clipboard

HardFault on lfs_file_close() after upgrade to v2.5.0

Open lidavid opened this issue 2 years ago • 10 comments

I upgraded littlefs to v2.5.0 and I now encounter a HardFault when trying to close a file.

my function call sequence is :

  • lfs_file_opencfg()
    • write X data blocks
      • lfs_file_seek()
      • lfs_file_write()
  • lfs_file_close()

call stack: image

The failed line: image

variable values: image

The data address is invalid for my system it is 0x4e000000.

This worked for me before updating to v2.5.0 although I used it a bit differently with lfs_file_open() instead of lfs_file_opencfg().

Any idea what's going on ?

lidavid avatar Aug 28 '22 11:08 lidavid

Probably worth enabling the LFS_ASSERT macro to see where your fault could be. Also are you setting a value in the lfs_config for the new metadata_max parameter?

Xenoamor avatar Sep 05 '22 13:09 Xenoamor

LFS_ASSERT was enabled in the original post ( I made sure it triggers on false config ). It doesn't trigger. I am not setting metadata_max .

lidavid avatar Sep 07 '22 11:09 lidavid

Is it possible you're running out of memory and malloc is giving you an address past RAM?

0x4e000000 certainly looks like an address, but if it's not an address it would be a weird value to see in a buffer overrun.

geky avatar Sep 07 '22 18:09 geky

littlefs is compiled with LFS_NO_MALLOC so malloc shouldn't be used.

0x4e000000 is a reserved address for my MCU ( https://pdfserv.maximintegrated.com/en/an/ug6766.pdf - page 33 )

lidavid avatar Sep 08 '22 06:09 lidavid

The wrong buffer address is coming for lfs_dir_traverse() : image

Is there any thing I can check that will help debug this problem ?

lidavid avatar Sep 08 '22 07:09 lidavid

Can you show your buffer definition and the call to lfs_file_opencfg?

Xenoamor avatar Sep 08 '22 10:09 Xenoamor

int do_fs_lfs_file_open(do_fs_lfs_file_handler_s *file_handler, do_lfs_file_system_e fs, const char *path, bool append)
{
    int ret, flags;
    struct lfs_file_config cfg = {.attr_count = 0, .attrs = 0, .buffer = do_fs_lfs_cache_buffer};

    // close any open file
    do_fs_lfs_file_close(file_handler);

    file_handler->lfs = do_fs_lfs_get_file_system(fs);
    file_handler->append = append;

    if (file_handler->append)
    {
        flags = LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND;
    }
    else
    {
        flags = LFS_O_WRONLY | LFS_O_CREAT;
    }

    ret = lfs_file_opencfg(file_handler->lfs, &(file_handler->file), path, flags, &cfg);

    return ret;
}

as a global variable : static uint8_t do_fs_lfs_cache_buffer[DO_FS_LFS_CACHE_SIZE] __attribute__((aligned(4)));

lidavid avatar Sep 08 '22 12:09 lidavid

Hmmm, I'm not sure it's related but I think the entire struct lfs_file_config needs to be static or global as it's content doesn't get copied. I can see some scenarios where this would cause the wrong operation

The usage says this:

The config struct must be allocated while the file is open, and the config struct must be zeroed for defaults and backwards compatibility

Xenoamor avatar Sep 08 '22 14:09 Xenoamor

@Xenoamor Thank you !

This fixes my HardFault.

To me it is not 100% clear from the usage that this struct has to be allocated statically/globally .

lidavid avatar Sep 11 '22 08:09 lidavid

To me it is not 100% clear from the usage that this struct has to be allocated statically/globally .

This is something I want to move away from eventually. The small RAM savings in certain circumstances does not outweigh the unintuitiveness. But on its own it's not worth a breaking change to the APIs. So it will probably stay how it is until there are other breaking API changes.

geky avatar Sep 12 '22 17:09 geky

I've been investigating the same hardfault today, but under slightly different circumstances. In my case, I'd accidentally called lfs_file_close() without first opening a file. This bit was my fault, however there probably should be some additional checking here - the hardfault was ultimately being caused because file->cfg was NULL.

lfs_file_rawsync() calls lfs_dir_commit() with two tags - the first of which will be OK, but the second is derived from file->cfg->attr_count and file->cfg->attrs, both of which are undefined. This false tag is eventually passed to lfs_dir_traverse(), and fails on line 948 because a[i] points to somewhere invalid.

I'm not sure of the correct way to fix this - I'll leave that up to people who know the source code a bit better than I do... but thought this would help if anyone else has been chasing the same problem.

patrickkeys avatar Sep 22 '22 15:09 patrickkeys

Is this not caught if you use LFS_ASSERT? Fairly sure it checks the API usage and that the file is open, it's usually worth using this in your debug builds

Xenoamor avatar Oct 12 '22 09:10 Xenoamor