libblock: Fix sparse disk

The qsort() in sparse_disk_get_new_block() may move the appended key
which invalidates the pointer.

Close #4142.
This commit is contained in:
Sebastian Huber
2020-10-12 08:09:13 +02:00
parent 8111a6ba88
commit b434dc1874

View File

@@ -111,22 +111,43 @@ static int sparse_disk_compare( const void *aa, const void *bb )
}
}
static rtems_sparse_disk_key *sparse_disk_find_block(
const rtems_sparse_disk *sparse_disk,
rtems_blkdev_bnum block
)
{
rtems_sparse_disk_key key = { .block = block };
return bsearch(
&key,
sparse_disk->key_table,
sparse_disk->used_count,
sizeof( rtems_sparse_disk_key ),
sparse_disk_compare
);
}
static rtems_sparse_disk_key *sparse_disk_get_new_block(
rtems_sparse_disk *sparse_disk,
const rtems_blkdev_bnum block )
const rtems_blkdev_bnum block
)
{
rtems_sparse_disk_key *key;
if ( sparse_disk->used_count < sparse_disk->blocks_with_buffer ) {
key = &sparse_disk->key_table[sparse_disk->used_count];
key->block = block;
++sparse_disk->used_count;
qsort( sparse_disk->key_table, sparse_disk->used_count,
sizeof( rtems_sparse_disk_key ), sparse_disk_compare );
} else
if ( sparse_disk->used_count >= sparse_disk->blocks_with_buffer ) {
return NULL;
}
return key;
key = &sparse_disk->key_table[ sparse_disk->used_count ];
key->block = block;
++sparse_disk->used_count;
qsort(
sparse_disk->key_table,
sparse_disk->used_count,
sizeof( rtems_sparse_disk_key ),
sparse_disk_compare
);
return sparse_disk_find_block( sparse_disk, block );
}
static int sparse_disk_read_block(
@@ -135,23 +156,13 @@ static int sparse_disk_read_block(
uint8_t *buffer,
const size_t buffer_size )
{
rtems_sparse_disk_key *key;
rtems_sparse_disk_key block_key = {
.block = block,
.data = NULL
};
size_t bytes_to_copy = sparse_disk->media_block_size;
rtems_sparse_disk_key *key;
if ( buffer_size < bytes_to_copy )
bytes_to_copy = buffer_size;
key = bsearch(
&block_key,
sparse_disk->key_table,
sparse_disk->used_count,
sizeof( rtems_sparse_disk_key ),
sparse_disk_compare
);
key = sparse_disk_find_block( sparse_disk, block );
if ( NULL != key )
memcpy( buffer, key->data, bytes_to_copy );
@@ -167,14 +178,10 @@ static int sparse_disk_write_block(
const uint8_t *buffer,
const size_t buffer_size )
{
unsigned int i;
size_t bytes_to_copy = sparse_disk->media_block_size;
bool block_needs_writing = false;
rtems_sparse_disk_key *key;
rtems_sparse_disk_key block_key = {
.block = block,
.data = NULL
};
size_t bytes_to_copy = sparse_disk->media_block_size;
size_t i;
if ( buffer_size < bytes_to_copy )
bytes_to_copy = buffer_size;
@@ -183,13 +190,7 @@ static int sparse_disk_write_block(
* If the read method does not find a block it will deliver the fill pattern anyway.
*/
key = bsearch(
&block_key,
sparse_disk->key_table,
sparse_disk->used_count,
sizeof( rtems_sparse_disk_key ),
sparse_disk_compare
);
key = sparse_disk_find_block( sparse_disk, block );
if ( NULL == key ) {
for ( i = 0; ( !block_needs_writing ) && ( i < bytes_to_copy ); ++i ) {