#include "array.h"
#include "seq-range-array.h"
+static bool seq_range_is_overflowed(const ARRAY_TYPE(seq_range) *array)
+{
+ const struct seq_range *range;
+ unsigned int count;
+
+ range = array_get(array, &count);
+ return count == 1 && range[0].seq1 == 0 &&
+ range[0].seq2 == (uint32_t)-1;
+}
+
static bool ATTR_NOWARN_UNUSED_RESULT
seq_range_lookup(const ARRAY_TYPE(seq_range) *array,
uint32_t seq, unsigned int *idx_r)
} else {
exists = seq_range_array_add_slow_path(array, seq);
}
+ i_assert(!seq_range_is_overflowed(array));
return exists;
}
array_delete(array, idx1 + 1, idx2 - idx1);
}
}
+ i_assert(!seq_range_is_overflowed(array));
}
void seq_range_array_add_range(ARRAY_TYPE(seq_range) *array,
for (idx2 = idx; idx2 < count; idx2++) {
if (data[idx2].seq1 > seq2)
break;
+ i_assert(UINT_MAX - remove_count >= seq_range_length(&data[idx2]));
remove_count += seq_range_length(&data[idx2]);
}
array_delete(array, idx, idx2-idx);
unsigned int seq_range_array_remove_seq_range(ARRAY_TYPE(seq_range) *dest,
const ARRAY_TYPE(seq_range) *src)
{
- unsigned int ret = 0;
+ unsigned int count, full_count = 0;
const struct seq_range *src_range;
array_foreach(src, src_range) {
- ret += seq_range_array_remove_range(dest, src_range->seq1,
- src_range->seq2);
+ count = seq_range_array_remove_range(dest, src_range->seq1,
+ src_range->seq2);
+ i_assert(UINT_MAX - full_count >= count);
+ full_count += count;
}
- return ret;
+ return full_count;
}
void seq_range_array_remove_nth(ARRAY_TYPE(seq_range) *array,
const ARRAY_TYPE(seq_range) *src)
{
const struct seq_range *src_range;
- unsigned int i, count, ret = 0;
+ unsigned int i, count, remove_count, full_count = 0;
uint32_t last_seq = 0;
src_range = array_get(src, &count);
for (i = 0; i < count; i++) {
if (last_seq + 1 < src_range[i].seq1) {
- ret += seq_range_array_remove_range(dest,
- last_seq + 1, src_range[i].seq1 - 1);
+ remove_count = seq_range_array_remove_range(dest,
+ last_seq + 1, src_range[i].seq1 - 1);
+ i_assert(UINT_MAX - full_count >= remove_count);
+ full_count += remove_count;
}
last_seq = src_range[i].seq2;
}
if (last_seq != (uint32_t)-1) {
- ret += seq_range_array_remove_range(dest, last_seq + 1,
- (uint32_t)-1);
+ remove_count = seq_range_array_remove_range(dest, last_seq + 1,
+ (uint32_t)-1);
+ i_assert(UINT_MAX - full_count >= remove_count);
+ full_count += remove_count;
}
- return ret;
+ return full_count;
}
bool seq_range_exists(const ARRAY_TYPE(seq_range) *array, uint32_t seq)
const struct seq_range *range;
unsigned int seq_count = 0;
- array_foreach(array, range)
+ array_foreach(array, range) {
+ i_assert(UINT_MAX - seq_count >= seq_range_length(range));
seq_count += seq_range_length(range);
+ }
return seq_count;
}
#ifndef SEQ_RANGE_ARRAY_H
#define SEQ_RANGE_ARRAY_H
+/* NOTE: A full 0..UINT_MAX sequence range isn't valid to use here, because its
+ size would become UINT_MAX+1, which can't be returned by e.g.
+ seq_range_count() and similar functions. Attempting to use such sequence
+ ranges will result in assert-crash. */
+
struct seq_range {
uint32_t seq1, seq2;
};
static inline uint32_t ATTR_PURE seq_range_length(const struct seq_range *range)
{
i_assert(range->seq2 >= range->seq1);
+ i_assert(range->seq1 > 0 || range->seq2 < (uint32_t)-1);
return range->seq2 - range->seq1 + 1;
}
TEST(test_random)
FATAL(fatal_random)
TEST(test_seq_range_array)
+FATAL(fatal_seq_range_array)
TEST(test_stats_dist)
TEST(test_str)
TEST(test_strescape)
test_begin("seq_range_array_remove_range()");
t_array_init(&range, 8);
- seq_range_array_add_range(&range, 0, (uint32_t)-1);
+ seq_range_array_add_range(&range, 0, (uint32_t)-2);
test_assert(seq_range_array_remove_range(&range, 0, 2) == 3);
- r = array_front(&range); test_assert(r->seq1 == 3 && r->seq2 == (uint32_t)-1);
+ r = array_front(&range); test_assert(r->seq1 == 3 && r->seq2 == (uint32_t)-2);
- seq_range_array_add_range(&range, 0, (uint32_t)-1);
+ seq_range_array_add_range(&range, 0, (uint32_t)-2);
test_assert(array_count(&range) == 1);
- /* return value wraps to 0 because it doesn't fit into uint32_t */
- test_assert(seq_range_array_remove_range(&range, 0, (uint32_t)-1) == 0);
+ test_assert(seq_range_array_remove_range(&range, 0, (uint32_t)-2) == UINT_MAX);
test_assert(array_count(&range) == 0);
seq_range_array_add_range(&range, (uint32_t)-1, (uint32_t)-1);
} tests[] = {
{ -1, -1, -1, -1,
0, 0xffffffff, -1, -1 },
- { 0, 0xffffffff, -1, -1,
- -1, -1, -1, -1 },
+ /*{ 0, 0xffffffff, -1, -1, too large, will assert-crash
+ -1, -1, -1, -1 }, */
{ 0, 0xfffffffe, -1, -1,
0xffffffff, 0xffffffff, -1, -1 },
{ 1, 0xfffffffe, -1, -1,
test_seq_range_array_have_common();
test_seq_range_array_random();
}
+
+enum fatal_test_state fatal_seq_range_array(unsigned int stage)
+{
+ ARRAY_TYPE(seq_range) arr;
+ struct seq_range *range;
+
+ t_array_init(&arr, 2);
+ switch (stage) {
+ case 0:
+ test_begin("seq_range_array fatals");
+ test_expect_fatal_string("!seq_range_is_overflowed(array)");
+ seq_range_array_add_range(&arr, 0, (uint32_t)-1);
+ return FATAL_TEST_FAILURE;
+ case 1:
+ seq_range_array_add_range(&arr, 1, (uint32_t)-1);
+ test_expect_fatal_string("!seq_range_is_overflowed(array)");
+ seq_range_array_add(&arr, 0);
+ return FATAL_TEST_FAILURE;
+ case 2:
+ seq_range_array_add_range(&arr, 0, (uint32_t)-2);
+ test_expect_fatal_string("!seq_range_is_overflowed(array)");
+ seq_range_array_add(&arr, (uint32_t)-1);
+ return FATAL_TEST_FAILURE;
+ case 3:
+ range = array_append_space(&arr);
+ range->seq2 = (uint32_t)-1;
+ test_expect_fatal_string("range->seq1 > 0 || range->seq2 < (uint32_t)-1");
+ i_error("This shouldn't return: %u", seq_range_count(&arr));
+ return FATAL_TEST_FAILURE;
+ case 4:
+ range = array_append_space(&arr);
+ range->seq2 = (uint32_t)-2;
+ test_assert(seq_range_count(&arr) == (uint32_t)-1);
+
+ range = array_append_space(&arr);
+ range->seq1 = (uint32_t)-2;
+ range->seq2 = (uint32_t)-1;
+ test_expect_fatal_string("UINT_MAX - seq_count >= seq_range_length(range)");
+ i_error("This shouldn't return: %u", seq_range_count(&arr));
+ return FATAL_TEST_FAILURE;
+ }
+ test_end();
+ return FATAL_TEST_FINISHED;
+}