Skip to content

Commit

Permalink
Fix memory leaks in lfs_mount and lfs_format
Browse files Browse the repository at this point in the history
Squashed:
- Change lfs_deinit() return to void to simplify error handling
- Move lfs_deinit() before lfs_init()
- Fix memory leaks in lfs_init()
- Fix memory leaks in lfs_format()
- Fix memory leaks in lfs_mount()
  • Loading branch information
FreddieChopin authored and geky committed Jul 19, 2018
1 parent 11ad3a2 commit 0422c55
Showing 1 changed file with 45 additions and 31 deletions.
76 changes: 45 additions & 31 deletions lfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2016,6 +2016,21 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {


/// Filesystem operations ///
static void lfs_deinit(lfs_t *lfs) {
// free allocated memory
if (!lfs->cfg->read_buffer) {
lfs_free(lfs->rcache.buffer);
}

if (!lfs->cfg->prog_buffer) {
lfs_free(lfs->pcache.buffer);
}

if (!lfs->cfg->lookahead_buffer) {
lfs_free(lfs->free.buffer);
}
}

static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->cfg = cfg;

Expand All @@ -2025,7 +2040,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
} else {
lfs->rcache.buffer = lfs_malloc(lfs->cfg->read_size);
if (!lfs->rcache.buffer) {
return LFS_ERR_NOMEM;
goto cleanup;
}
}

Expand All @@ -2035,7 +2050,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
} else {
lfs->pcache.buffer = lfs_malloc(lfs->cfg->prog_size);
if (!lfs->pcache.buffer) {
return LFS_ERR_NOMEM;
goto cleanup;
}
}

Expand All @@ -2051,7 +2066,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
} else {
lfs->free.buffer = lfs_malloc(lfs->cfg->lookahead/8);
if (!lfs->free.buffer) {
return LFS_ERR_NOMEM;
goto cleanup;
}
}

Expand All @@ -2071,23 +2086,10 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
lfs->deorphaned = false;

return 0;
}

static int lfs_deinit(lfs_t *lfs) {
// free allocated memory
if (!lfs->cfg->read_buffer) {
lfs_free(lfs->rcache.buffer);
}

if (!lfs->cfg->prog_buffer) {
lfs_free(lfs->pcache.buffer);
}

if (!lfs->cfg->lookahead_buffer) {
lfs_free(lfs->free.buffer);
}

return 0;
cleanup:
lfs_deinit(lfs);
return LFS_ERR_NOMEM;
}

int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
Expand All @@ -2107,19 +2109,19 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
lfs_dir_t superdir;
err = lfs_dir_alloc(lfs, &superdir);
if (err) {
return err;
goto cleanup;
}

// write root directory
lfs_dir_t root;
err = lfs_dir_alloc(lfs, &root);
if (err) {
return err;
goto cleanup;
}

err = lfs_dir_commit(lfs, &root, NULL, 0);
if (err) {
return err;
goto cleanup;
}

lfs->root[0] = root.pair[0];
Expand Down Expand Up @@ -2150,24 +2152,28 @@ int lfs_format(lfs_t *lfs, const struct lfs_config *cfg) {
&superblock.d, sizeof(superblock.d)}
}, 1);
if (err && err != LFS_ERR_CORRUPT) {
return err;
goto cleanup;
}

valid = valid || !err;
}

if (!valid) {
return LFS_ERR_CORRUPT;
err = LFS_ERR_CORRUPT;
goto cleanup;
}

// sanity check that fetch works
err = lfs_dir_fetch(lfs, &superdir, (const lfs_block_t[2]){0, 1});
if (err) {
return err;
goto cleanup;
}

lfs_alloc_ack(lfs);
return lfs_deinit(lfs);

cleanup:
lfs_deinit(lfs);
return err;
}

int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
Expand All @@ -2187,15 +2193,15 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
lfs_superblock_t superblock;
err = lfs_dir_fetch(lfs, &dir, (const lfs_block_t[2]){0, 1});
if (err && err != LFS_ERR_CORRUPT) {
return err;
goto cleanup;
}

if (!err) {
err = lfs_bd_read(lfs, dir.pair[0], sizeof(dir.d),
&superblock.d, sizeof(superblock.d));
lfs_superblock_fromle32(&superblock.d);
if (err) {
return err;
goto cleanup;
}

lfs->root[0] = superblock.d.root[0];
Expand All @@ -2204,22 +2210,30 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {

if (err || memcmp(superblock.d.magic, "littlefs", 8) != 0) {
LFS_ERROR("Invalid superblock at %d %d", 0, 1);
return LFS_ERR_CORRUPT;
err = LFS_ERR_CORRUPT;
goto cleanup;
}

uint16_t major_version = (0xffff & (superblock.d.version >> 16));
uint16_t minor_version = (0xffff & (superblock.d.version >> 0));
if ((major_version != LFS_DISK_VERSION_MAJOR ||
minor_version > LFS_DISK_VERSION_MINOR)) {
LFS_ERROR("Invalid version %d.%d", major_version, minor_version);
return LFS_ERR_INVAL;
err = LFS_ERR_INVAL;
goto cleanup;
}

return 0;

cleanup:

lfs_deinit(lfs);
return err;
}

int lfs_unmount(lfs_t *lfs) {
return lfs_deinit(lfs);
lfs_deinit(lfs);
return 0;
}


Expand Down

0 comments on commit 0422c55

Please sign in to comment.