Adopted data-backed cache in lfs3_file_t to avoid undefined behavior
This fixes a strict aliasing violation in lfs3_file_sync_, where we cast
the file cache -> lfs3_data_t to avoid an extra stack allocation, by
modifying the file's cache struct to use an lfs3_data_t directly.
- file.cache.pos -> file.cache.pos
- file.cache.buffer -> file.cache.d.u.buffer_
- file.cache.size -> file.cache.d.size
- (const lfs3_data_t*)&file->cache -> &file->cache.d
Note the underscore_ in file.cache.d.u.buffer_. This did not fit
together as well as I had hoped, due to different const expectation
between the file cache and lfs3_data_t.
Up until this point lfs3_data_t has only been used to refer to const
data (ignoring side-band pointer casting in lfs3_mtree_traverse*), while
the file cache very much contains mutable data. To work around this I
added data.u.buffer_ as a mutable variant, which works, but risks an
accidental const violation in the future.
---
Unfortunately this does come with a minor RAM cost, since we no longer
hide file.cache.pos in lfs3_data_t's buffer padding:
code stack ctx
before: 36844 2368 684
after: 36832 (-0.0%) 2376 (+0.3%) 684 (+0.0%)
lfs3_file_t before: 164
lfs3_file_t after: 168 (+2.4%)
I think it's pretty fair to call C's strict aliasing rules a real wet
blanket. It would be interesting to create a -fno-strict-aliasing
variant of littlefs in the future, to see how much code/RAM could be
saved if we were given free reign to abuse the available memory.
Probably not enough to justify the extra work, but it would be an
interesting experiment.
This commit is contained in:
@@ -636,6 +636,7 @@ typedef struct lfs3_data {
|
||||
lfs3_size_t size;
|
||||
union {
|
||||
const uint8_t *buffer;
|
||||
uint8_t *buffer_;
|
||||
struct {
|
||||
lfs3_block_t block;
|
||||
lfs3_size_t off;
|
||||
@@ -741,14 +742,11 @@ typedef struct lfs3_file {
|
||||
#endif
|
||||
|
||||
// in-RAM cache
|
||||
//
|
||||
// note this lines up with lfs3_data_t's buffer representation
|
||||
struct {
|
||||
lfs3_off_t size;
|
||||
uint8_t *buffer;
|
||||
#ifndef LFS3_KVONLY
|
||||
lfs3_off_t pos;
|
||||
#endif
|
||||
lfs3_data_t d;
|
||||
} cache;
|
||||
|
||||
// on-disk leaf bptr
|
||||
|
||||
Reference in New Issue
Block a user