mirror of
https://github.com/git/git.git
synced 2025-12-12 20:36:24 +01:00
reftable: check for trailing newline in 'tables.list'
In the reftable format, the 'tables.list' file contains a newline separated list of tables. While we parse this file, we do not check or care about the last newline. Tighten the parser in `parse_names()` to return an appropriate error if the last newline is missing. This requires modification to `parse_names()` to now return the error while accepting the output as a third argument. Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
committed by
Junio C Hamano
parent
1ef32f0989
commit
f644206377
@@ -195,44 +195,55 @@ size_t names_length(const char **names)
|
|||||||
return p - names;
|
return p - names;
|
||||||
}
|
}
|
||||||
|
|
||||||
char **parse_names(char *buf, int size)
|
int parse_names(char *buf, int size, char ***out)
|
||||||
{
|
{
|
||||||
char **names = NULL;
|
char **names = NULL;
|
||||||
size_t names_cap = 0;
|
size_t names_cap = 0;
|
||||||
size_t names_len = 0;
|
size_t names_len = 0;
|
||||||
char *p = buf;
|
char *p = buf;
|
||||||
char *end = buf + size;
|
char *end = buf + size;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
while (p < end) {
|
while (p < end) {
|
||||||
char *next = strchr(p, '\n');
|
char *next = strchr(p, '\n');
|
||||||
if (next && next < end) {
|
if (!next) {
|
||||||
*next = 0;
|
err = REFTABLE_FORMAT_ERROR;
|
||||||
|
goto done;
|
||||||
|
} else if (next < end) {
|
||||||
|
*next = '\0';
|
||||||
} else {
|
} else {
|
||||||
next = end;
|
next = end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p < next) {
|
if (p < next) {
|
||||||
if (REFTABLE_ALLOC_GROW(names, names_len + 1,
|
if (REFTABLE_ALLOC_GROW(names, names_len + 1,
|
||||||
names_cap))
|
names_cap)) {
|
||||||
goto err;
|
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
names[names_len] = reftable_strdup(p);
|
names[names_len] = reftable_strdup(p);
|
||||||
if (!names[names_len++])
|
if (!names[names_len++]) {
|
||||||
goto err;
|
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p = next + 1;
|
p = next + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap))
|
if (REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap)) {
|
||||||
goto err;
|
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
names[names_len] = NULL;
|
names[names_len] = NULL;
|
||||||
|
|
||||||
return names;
|
*out = names;
|
||||||
|
return 0;
|
||||||
err:
|
done:
|
||||||
for (size_t i = 0; i < names_len; i++)
|
for (size_t i = 0; i < names_len; i++)
|
||||||
reftable_free(names[i]);
|
reftable_free(names[i]);
|
||||||
reftable_free(names);
|
reftable_free(names);
|
||||||
return NULL;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int names_equal(const char **a, const char **b)
|
int names_equal(const char **a, const char **b)
|
||||||
|
|||||||
@@ -167,10 +167,11 @@ void free_names(char **a);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse a newline separated list of names. `size` is the length of the buffer,
|
* Parse a newline separated list of names. `size` is the length of the buffer,
|
||||||
* without terminating '\0'. Empty names are discarded. Returns a `NULL`
|
* without terminating '\0'. Empty names are discarded.
|
||||||
* pointer when allocations fail.
|
*
|
||||||
|
* Returns 0 on success, a reftable error code on error.
|
||||||
*/
|
*/
|
||||||
char **parse_names(char *buf, int size);
|
int parse_names(char *buf, int size, char ***out);
|
||||||
|
|
||||||
/* compares two NULL-terminated arrays of strings. */
|
/* compares two NULL-terminated arrays of strings. */
|
||||||
int names_equal(const char **a, const char **b);
|
int names_equal(const char **a, const char **b);
|
||||||
|
|||||||
@@ -169,12 +169,7 @@ static int fd_read_lines(int fd, char ***namesp)
|
|||||||
}
|
}
|
||||||
buf[size] = 0;
|
buf[size] = 0;
|
||||||
|
|
||||||
*namesp = parse_names(buf, size);
|
err = parse_names(buf, size, namesp);
|
||||||
if (!*namesp) {
|
|
||||||
err = REFTABLE_OUT_OF_MEMORY_ERROR;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
reftable_free(buf);
|
reftable_free(buf);
|
||||||
return err;
|
return err;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ https://developers.google.com/open-source/licenses/bsd
|
|||||||
#include "unit-test.h"
|
#include "unit-test.h"
|
||||||
#include "lib-reftable.h"
|
#include "lib-reftable.h"
|
||||||
#include "reftable/basics.h"
|
#include "reftable/basics.h"
|
||||||
|
#include "reftable/reftable-error.h"
|
||||||
|
|
||||||
struct integer_needle_lesseq_args {
|
struct integer_needle_lesseq_args {
|
||||||
int needle;
|
int needle;
|
||||||
@@ -79,14 +80,18 @@ void test_reftable_basics__names_equal(void)
|
|||||||
void test_reftable_basics__parse_names(void)
|
void test_reftable_basics__parse_names(void)
|
||||||
{
|
{
|
||||||
char in1[] = "line\n";
|
char in1[] = "line\n";
|
||||||
char in2[] = "a\nb\nc";
|
char in2[] = "a\nb\nc\n";
|
||||||
char **out = parse_names(in1, strlen(in1));
|
char **out = NULL;
|
||||||
|
int err = parse_names(in1, strlen(in1), &out);
|
||||||
|
cl_assert(err == 0);
|
||||||
cl_assert(out != NULL);
|
cl_assert(out != NULL);
|
||||||
cl_assert_equal_s(out[0], "line");
|
cl_assert_equal_s(out[0], "line");
|
||||||
cl_assert(!out[1]);
|
cl_assert(!out[1]);
|
||||||
free_names(out);
|
free_names(out);
|
||||||
|
|
||||||
out = parse_names(in2, strlen(in2));
|
out = NULL;
|
||||||
|
err = parse_names(in2, strlen(in2), &out);
|
||||||
|
cl_assert(err == 0);
|
||||||
cl_assert(out != NULL);
|
cl_assert(out != NULL);
|
||||||
cl_assert_equal_s(out[0], "a");
|
cl_assert_equal_s(out[0], "a");
|
||||||
cl_assert_equal_s(out[1], "b");
|
cl_assert_equal_s(out[1], "b");
|
||||||
@@ -95,10 +100,21 @@ void test_reftable_basics__parse_names(void)
|
|||||||
free_names(out);
|
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)
|
void test_reftable_basics__parse_names_drop_empty_string(void)
|
||||||
{
|
{
|
||||||
char in[] = "a\n\nb\n";
|
char in[] = "a\n\nb\n";
|
||||||
char **out = parse_names(in, strlen(in));
|
char **out = NULL;
|
||||||
|
int err = parse_names(in, strlen(in), &out);
|
||||||
|
cl_assert(err == 0);
|
||||||
cl_assert(out != NULL);
|
cl_assert(out != NULL);
|
||||||
cl_assert_equal_s(out[0], "a");
|
cl_assert_equal_s(out[0], "a");
|
||||||
/* simply '\n' should be dropped as empty string */
|
/* simply '\n' should be dropped as empty string */
|
||||||
|
|||||||
Reference in New Issue
Block a user