mirror of
https://github.com/git/git.git
synced 2026-08-07 00:22:05 +00:00
`binsearch()` performs a binary search over a range of `sz` elements by repeatedly calling the comparison function with indices into that range. When the range is empty though, there is no valid index to call the comparison function with. We still end up executing the comparison function though with an index of 0, which of course will cause an out-of-bounds read. Return early when the range is empty. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
255 lines
5.6 KiB
C
255 lines
5.6 KiB
C
/*
|
|
Copyright 2020 Google LLC
|
|
|
|
Use of this source code is governed by a BSD-style
|
|
license that can be found in the LICENSE file or at
|
|
https://developers.google.com/open-source/licenses/bsd
|
|
*/
|
|
|
|
#include "unit-test.h"
|
|
#include "lib-reftable.h"
|
|
#include "reftable/basics.h"
|
|
#include "reftable/reftable-error.h"
|
|
|
|
struct integer_needle_lesseq_args {
|
|
int needle;
|
|
int *haystack;
|
|
};
|
|
|
|
static int integer_needle_lesseq(size_t i, void *_args)
|
|
{
|
|
struct integer_needle_lesseq_args *args = _args;
|
|
return args->needle <= args->haystack[i];
|
|
}
|
|
|
|
static void *realloc_stub(void *p UNUSED, size_t size UNUSED)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void test_reftable_basics__binsearch(void)
|
|
{
|
|
int haystack[] = { 2, 4, 6, 8, 10 };
|
|
struct {
|
|
int needle;
|
|
size_t expected_idx;
|
|
} testcases[] = {
|
|
{-9000, 0},
|
|
{-1, 0},
|
|
{0, 0},
|
|
{2, 0},
|
|
{3, 1},
|
|
{4, 1},
|
|
{7, 3},
|
|
{9, 4},
|
|
{10, 4},
|
|
{11, 5},
|
|
{9000, 5},
|
|
};
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) {
|
|
struct integer_needle_lesseq_args args = {
|
|
.haystack = haystack,
|
|
.needle = testcases[i].needle,
|
|
};
|
|
size_t idx;
|
|
|
|
idx = binsearch(ARRAY_SIZE(haystack),
|
|
&integer_needle_lesseq, &args);
|
|
cl_assert_equal_i(idx, testcases[i].expected_idx);
|
|
}
|
|
}
|
|
|
|
static int unreachable_lesseq(size_t i UNUSED, void *args UNUSED)
|
|
{
|
|
cl_fail("comparison function called for empty range");
|
|
return 0;
|
|
}
|
|
|
|
void test_reftable_basics__binsearch_empty(void)
|
|
{
|
|
cl_assert_equal_i(binsearch(0, &unreachable_lesseq, NULL), 0);
|
|
}
|
|
|
|
void test_reftable_basics__names_length(void)
|
|
{
|
|
const char *a[] = { "a", "b", NULL };
|
|
cl_assert_equal_i(names_length(a), 2);
|
|
}
|
|
|
|
void test_reftable_basics__names_equal(void)
|
|
{
|
|
const char *a[] = { "a", "b", "c", NULL };
|
|
const char *b[] = { "a", "b", "d", NULL };
|
|
const char *c[] = { "a", "b", NULL };
|
|
|
|
cl_assert(names_equal(a, a));
|
|
cl_assert(!names_equal(a, b));
|
|
cl_assert(!names_equal(a, c));
|
|
}
|
|
|
|
void test_reftable_basics__parse_names(void)
|
|
{
|
|
char in1[] = "line\n";
|
|
char in2[] = "a\nb\nc\n";
|
|
char **out = NULL;
|
|
int err = parse_names(in1, strlen(in1), &out);
|
|
cl_assert(err == 0);
|
|
cl_assert(out != NULL);
|
|
cl_assert_equal_s(out[0], "line");
|
|
cl_assert(!out[1]);
|
|
free_names(out);
|
|
|
|
out = NULL;
|
|
err = parse_names(in2, strlen(in2), &out);
|
|
cl_assert(err == 0);
|
|
cl_assert(out != NULL);
|
|
cl_assert_equal_s(out[0], "a");
|
|
cl_assert_equal_s(out[1], "b");
|
|
cl_assert_equal_s(out[2], "c");
|
|
cl_assert(!out[3]);
|
|
free_names(out);
|
|
}
|
|
|
|
void test_reftable_basics__parse_names_missing_newline(void)
|
|
{
|
|
char in1[] = "line\nline2";
|
|
char **out = NULL;
|
|
int err = parse_names(in1, strlen(in1), &out);
|
|
cl_assert(err == REFTABLE_FORMAT_ERROR);
|
|
cl_assert(out == NULL);
|
|
}
|
|
|
|
void test_reftable_basics__parse_names_drop_empty_string(void)
|
|
{
|
|
char in[] = "a\n\nb\n";
|
|
char **out = NULL;
|
|
int err = parse_names(in, strlen(in), &out);
|
|
cl_assert(err == 0);
|
|
cl_assert(out != NULL);
|
|
cl_assert_equal_s(out[0], "a");
|
|
/* simply '\n' should be dropped as empty string */
|
|
cl_assert_equal_s(out[1], "b");
|
|
cl_assert(out[2] == NULL);
|
|
free_names(out);
|
|
}
|
|
|
|
void test_reftable_basics__common_prefix_size(void)
|
|
{
|
|
struct reftable_buf a = REFTABLE_BUF_INIT;
|
|
struct reftable_buf b = REFTABLE_BUF_INIT;
|
|
struct {
|
|
const char *a, *b;
|
|
int want;
|
|
} cases[] = {
|
|
{"abcdef", "abc", 3},
|
|
{ "abc", "ab", 2 },
|
|
{ "", "abc", 0 },
|
|
{ "abc", "abd", 2 },
|
|
{ "abc", "pqr", 0 },
|
|
};
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(cases); i++) {
|
|
cl_assert_equal_i(reftable_buf_addstr(&a, cases[i].a), 0);
|
|
cl_assert_equal_i(reftable_buf_addstr(&b, cases[i].b), 0);
|
|
cl_assert_equal_i(common_prefix_size(&a, &b), cases[i].want);
|
|
reftable_buf_reset(&a);
|
|
reftable_buf_reset(&b);
|
|
}
|
|
reftable_buf_release(&a);
|
|
reftable_buf_release(&b);
|
|
}
|
|
|
|
void test_reftable_basics__put_get_be64(void)
|
|
{
|
|
uint64_t in = 0x1122334455667788;
|
|
uint8_t dest[8];
|
|
uint64_t out;
|
|
reftable_put_be64(dest, in);
|
|
out = reftable_get_be64(dest);
|
|
cl_assert(in == out);
|
|
}
|
|
|
|
void test_reftable_basics__put_get_be32(void)
|
|
{
|
|
uint32_t in = 0x11223344;
|
|
uint8_t dest[4];
|
|
uint32_t out;
|
|
reftable_put_be32(dest, in);
|
|
out = reftable_get_be32(dest);
|
|
cl_assert_equal_i(in, out);
|
|
}
|
|
|
|
void test_reftable_basics__put_get_be24(void)
|
|
{
|
|
uint32_t in = 0x112233;
|
|
uint8_t dest[3];
|
|
uint32_t out;
|
|
reftable_put_be24(dest, in);
|
|
out = reftable_get_be24(dest);
|
|
cl_assert_equal_i(in, out);
|
|
}
|
|
|
|
void test_reftable_basics__put_get_be16(void)
|
|
{
|
|
uint32_t in = 0xfef1;
|
|
uint8_t dest[3];
|
|
uint32_t out;
|
|
reftable_put_be16(dest, in);
|
|
out = reftable_get_be16(dest);
|
|
cl_assert_equal_i(in, out);
|
|
}
|
|
|
|
void test_reftable_basics__alloc_grow(void)
|
|
{
|
|
int *arr = NULL, *old_arr;
|
|
size_t alloc = 0, old_alloc;
|
|
|
|
cl_assert_equal_i(REFTABLE_ALLOC_GROW(arr, 1, alloc), 0);
|
|
cl_assert(arr != NULL);
|
|
cl_assert(alloc >= 1);
|
|
arr[0] = 42;
|
|
|
|
old_alloc = alloc;
|
|
old_arr = arr;
|
|
reftable_set_alloc(NULL, realloc_stub, NULL);
|
|
cl_assert(REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc));
|
|
cl_assert(arr == old_arr);
|
|
cl_assert_equal_i(alloc, old_alloc);
|
|
|
|
old_alloc = alloc;
|
|
reftable_set_alloc(NULL, NULL, NULL);
|
|
cl_assert_equal_i(REFTABLE_ALLOC_GROW(arr, old_alloc + 1, alloc), 0);
|
|
cl_assert(arr != NULL);
|
|
cl_assert(alloc > old_alloc);
|
|
arr[alloc - 1] = 42;
|
|
|
|
reftable_free(arr);
|
|
}
|
|
|
|
void test_reftable_basics__alloc_grow_or_null(void)
|
|
{
|
|
int *arr = NULL;
|
|
size_t alloc = 0, old_alloc;
|
|
|
|
REFTABLE_ALLOC_GROW_OR_NULL(arr, 1, alloc);
|
|
cl_assert(arr != NULL);
|
|
cl_assert(alloc >= 1);
|
|
arr[0] = 42;
|
|
|
|
old_alloc = alloc;
|
|
REFTABLE_ALLOC_GROW_OR_NULL(arr, old_alloc + 1, alloc);
|
|
cl_assert(arr != NULL);
|
|
cl_assert(alloc > old_alloc);
|
|
arr[alloc - 1] = 42;
|
|
|
|
old_alloc = alloc;
|
|
reftable_set_alloc(NULL, realloc_stub, NULL);
|
|
REFTABLE_ALLOC_GROW_OR_NULL(arr, old_alloc + 1, alloc);
|
|
cl_assert(arr == NULL);
|
|
cl_assert_equal_i(alloc, 0);
|
|
reftable_set_alloc(NULL, NULL, NULL);
|
|
|
|
reftable_free(arr);
|
|
}
|