buflib: fix bug in handle_table_shrink

The way it iterated over the handle table is unsafe if *every*
handle is free, leading to an out of bounds access.

This is a contrived example, but the bug can be triggered by
making several allocations, freeing them out of order so that
the handle table remains uncompacted, and then triggering a
compaction using buflib_alloc_maximum().

Change-Id: I879e2f0b223e6ca596769610ac46f4edf1107f5c
This commit is contained in:
Aidan MacDonald 2022-03-28 21:59:43 +01:00
parent 4d3bf1c446
commit c8365b2bdd

View file

@ -247,18 +247,20 @@ union buflib_data* handle_to_block(struct buflib_context* ctx, int handle)
/* Shrink the handle table, returning true if its size was reduced, false if
* not
*/
static inline
bool
handle_table_shrink(struct buflib_context *ctx)
static inline bool handle_table_shrink(struct buflib_context *ctx)
{
bool rv;
union buflib_data *handle;
for (handle = ctx->last_handle; !(handle->alloc); handle++);
union buflib_data *old_last = ctx->last_handle;
for (handle = ctx->last_handle; handle != ctx->handle_table; ++handle)
if (handle->alloc)
break;
if (handle > ctx->first_free_handle)
ctx->first_free_handle = handle - 1;
rv = handle != ctx->last_handle;
ctx->last_handle = handle;
return rv;
return handle != old_last;
}