From 05efe6bde3a884d4fcca88a227efaeee2c7e3b8a Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Mon, 26 Oct 2026 23:25:21 +0100 Subject: Avoid an UB of adding NULL + 0 by keeping an offset instead of advancing the pointer into a vector struct --- ot_vector.c | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) (limited to 'ot_vector.c') diff --git a/ot_vector.c b/ot_vector.c index 924d468..a56d55b 100644 --- a/ot_vector.c +++ b/ot_vector.c @@ -57,34 +57,39 @@ static uint8_t vector_hash_peer(ot_peer const *peer, size_t compare_size, size_t */ void *vector_find_or_insert(ot_vector *vector, void *key, size_t member_size, size_t compare_size, int *exactmatch) { uint8_t *match = vector_binary_search(key, vector->data, vector->size, member_size, compare_size, exactmatch); + size_t match_offset, bytes_after; if (*exactmatch) return match; + /* Hold the insertion point as an offset rather than a pointer: it survives + the realloc below, and an empty vector has no data pointer to offset from + in the first place */ + match_offset = vector->size ? (size_t)(match - (uint8_t *)vector->data) : 0; + bytes_after = member_size * vector->size - match_offset; + if (vector->size + 1 > vector->space) { - size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; - ptrdiff_t match_off = match - (uint8_t *)vector->data; - uint8_t *new_data = realloc(vector->data, new_space * member_size); + size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; + uint8_t *new_data = realloc(vector->data, new_space * member_size); if (!new_data) return NULL; - /* Adjust pointer if it moved by realloc */ - match = new_data + match_off; - vector->data = new_data; vector->space = new_space; } - memmove(match + member_size, match, ((uint8_t *)vector->data) + member_size * vector->size - match); + + match = (uint8_t *)vector->data + match_offset; + memmove(match + member_size, match, bytes_after); vector->size++; return match; } ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size, int *exactmatch) { - ot_peer *match, *end; + ot_peer *match; const size_t compare_size = OT_PEER_COMPARE_SIZE_FROM_PEER_SIZE(peer_size); - size_t match_to_end; + size_t match_offset, bytes_after; /* If space is zero but size is set, we're dealing with a list of vector->size buckets */ if (vector->space < vector->size) @@ -94,26 +99,26 @@ ot_peer *vector_find_or_insert_peer(ot_vector *vector, ot_peer const *peer, size if (*exactmatch) return match; - /* This is the amount of bytes that needs to be pushed backwards by peer_size bytes to make room for new peer */ - end = (ot_peer *)vector->data + vector->size * peer_size; - match_to_end = end - match; + /* Hold the insertion point as an offset rather than a pointer: it survives + the realloc below, and an empty vector has no data pointer to offset from + in the first place. bytes_after is what has to move up by peer_size to + make room for the new peer */ + match_offset = vector->size ? (size_t)(match - (ot_peer *)vector->data) : 0; + bytes_after = vector->size * peer_size - match_offset; if (vector->size + 1 > vector->space) { - ptrdiff_t offset = match - (ot_peer *)vector->data; - size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; - ot_peer *new_data = realloc(vector->data, new_space * peer_size); + size_t new_space = vector->space ? OT_VECTOR_GROW_RATIO * vector->space : OT_VECTOR_MIN_MEMBERS; + ot_peer *new_data = realloc(vector->data, new_space * peer_size); if (!new_data) return NULL; - /* Adjust pointer if it moved by realloc */ - match = new_data + offset; vector->data = new_data; vector->space = new_space; } - /* Here we're guaranteed to have enough space in vector to move the block of peers after insertion point */ - memmove(match + peer_size, match, match_to_end); + match = (ot_peer *)vector->data + match_offset; + memmove(match + peer_size, match, bytes_after); vector->size++; return match; @@ -150,11 +155,13 @@ int vector_remove_peer(ot_vector *vector, ot_peer const *peer, size_t peer_size) } void vector_remove_torrent(ot_vector *vector, ot_torrent *match) { - ot_torrent *end = ((ot_torrent *)vector->data) + vector->size; + ot_torrent *end; if (!vector->size) return; + end = ((ot_torrent *)vector->data) + vector->size; + free_peerlist(match->peer_list6); free_peerlist(match->peer_list4); -- cgit v1.3