Skip to content

Commit 826d9a4

Browse files
authored
Merge pull request libgit2#4858 from tiennou/fix/index-ext-read
index: preserve extension parsing errors
2 parents 859d922 + 0bf7e04 commit 826d9a4

File tree

10 files changed

+54
-14
lines changed

10 files changed

+54
-14
lines changed

docs/changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ v0.27 + 1
7171
* Revision walks are now more efficient when the output is unsorted;
7272
we now avoid walking all the way to the beginning of history unnecessarily.
7373

74+
* Error-handling around index extension loading has been fixed. We were
75+
previously always misreporting a truncated index (#4858).
76+
7477
### API additions
7578

7679
* The index may now be iterated atomically using `git_index_iterator`.

src/index.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ struct reuc_entry_internal {
138138
bool git_index__enforce_unsaved_safety = false;
139139

140140
/* local declarations */
141-
static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size);
141+
static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size);
142142
static int read_header(struct index_header *dest, const void *buffer);
143143

144144
static int parse_index(git_index *index, const char *buffer, size_t buffer_size);
@@ -2526,7 +2526,7 @@ static int read_header(struct index_header *dest, const void *buffer)
25262526
return 0;
25272527
}
25282528

2529-
static size_t read_extension(git_index *index, const char *buffer, size_t buffer_size)
2529+
static int read_extension(size_t *read_len, git_index *index, const char *buffer, size_t buffer_size)
25302530
{
25312531
struct index_extension dest;
25322532
size_t total_size;
@@ -2539,31 +2539,36 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer
25392539

25402540
if (dest.extension_size > total_size ||
25412541
buffer_size < total_size ||
2542-
buffer_size - total_size < INDEX_FOOTER_SIZE)
2543-
return 0;
2542+
buffer_size - total_size < INDEX_FOOTER_SIZE) {
2543+
index_error_invalid("extension is truncated");
2544+
return -1;
2545+
}
25442546

25452547
/* optional extension */
25462548
if (dest.signature[0] >= 'A' && dest.signature[0] <= 'Z') {
25472549
/* tree cache */
25482550
if (memcmp(dest.signature, INDEX_EXT_TREECACHE_SIG, 4) == 0) {
25492551
if (git_tree_cache_read(&index->tree, buffer + 8, dest.extension_size, &index->tree_pool) < 0)
2550-
return 0;
2552+
return -1;
25512553
} else if (memcmp(dest.signature, INDEX_EXT_UNMERGED_SIG, 4) == 0) {
25522554
if (read_reuc(index, buffer + 8, dest.extension_size) < 0)
2553-
return 0;
2555+
return -1;
25542556
} else if (memcmp(dest.signature, INDEX_EXT_CONFLICT_NAME_SIG, 4) == 0) {
25552557
if (read_conflict_names(index, buffer + 8, dest.extension_size) < 0)
2556-
return 0;
2558+
return -1;
25572559
}
25582560
/* else, unsupported extension. We cannot parse this, but we can skip
25592561
* it by returning `total_size */
25602562
} else {
25612563
/* we cannot handle non-ignorable extensions;
25622564
* in fact they aren't even defined in the standard */
2563-
return 0;
2565+
git_error_set(GIT_ERROR_INDEX, "unsupported mandatory extension: '%.4s'", dest.signature);
2566+
return -1;
25642567
}
25652568

2566-
return total_size;
2569+
*read_len = total_size;
2570+
2571+
return 0;
25672572
}
25682573

25692574
static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
@@ -2645,11 +2650,7 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size)
26452650
while (buffer_size > INDEX_FOOTER_SIZE) {
26462651
size_t extension_size;
26472652

2648-
extension_size = read_extension(index, buffer, buffer_size);
2649-
2650-
/* see if we have read any bytes from the extension */
2651-
if (extension_size == 0) {
2652-
error = index_error_invalid("extension is truncated");
2653+
if ((error = read_extension(&extension_size, index, buffer, buffer_size)) < 0) {
26532654
goto done;
26542655
}
26552656

tests/index/splitindex.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include "clar_libgit2.h"
2+
#include "index.h"
3+
4+
static git_repository *g_repo;
5+
6+
void test_index_splitindex__initialize(void)
7+
{
8+
g_repo = cl_git_sandbox_init("splitindex");
9+
}
10+
11+
void test_index_splitindex__cleanup(void)
12+
{
13+
cl_git_sandbox_cleanup();
14+
}
15+
16+
void test_index_splitindex__fail_on_open(void)
17+
{
18+
git_index *idx;
19+
cl_git_fail_with(-1, git_repository_index(&idx, g_repo));
20+
cl_assert_equal_s(git_error_last()->message, "unsupported mandatory extension: 'link'");
21+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ref: refs/heads/master
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[core]
2+
repositoryformatversion = 0
3+
filemode = true
4+
bare = false
5+
logallrefupdates = true
6+
ignorecase = true
7+
precomposeunicode = true
8+
splitIndex = true
100 Bytes
Binary file not shown.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# git ls-files --others --exclude-from=.git/info/exclude
2+
# Lines that start with '#' are comments.
3+
# For a project mostly in C, the following would be a good set of
4+
# exclude patterns (uncomment them if you want to use them):
5+
# *.[oa]
6+
# *~

tests/resources/splitindex/.gitted/objects/.gitkeep

Whitespace-only changes.

tests/resources/splitindex/.gitted/refs/.gitkeep

Whitespace-only changes.
Binary file not shown.

0 commit comments

Comments
 (0)