Skip to content

Commit 5cf17e0

Browse files
committed
commit_list: store in/out-degrees as uint16_t
The commit list's in- and out-degrees are currently stored as `unsigned short`. When assigning it the value of `git_array_size`, which returns an `size_t`, this generates a warning on some Win32 platforms due to loosing precision. We could just cast the returned value of `git_array_size`, which would work fine for 99.99% of all cases as commits typically have less than 2^16 parents. For crafted commits though we might end up with a wrong value, and thus we should definitely check whether the array size actually fits into the field. To ease the check, let's convert the fields to store the degrees as `uint16_t`. We shouldn't rely on such unspecific types anyway, as it may lead to different behaviour across platforms. Furthermore, this commit introduces a new `git__is_uint16` function to check whether it actually fits -- if not, we return an error.
1 parent 5988cf3 commit 5cf17e0

File tree

3 files changed

+16
-3
lines changed

3 files changed

+16
-3
lines changed

src/commit_list.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,14 @@ static int commit_quick_parse(
114114
return error;
115115
}
116116

117+
if (!git__is_uint16(git_array_size(commit->parent_ids))) {
118+
git__free(commit);
119+
git_error_set(GIT_ERROR_INVALID, "commit has more than 2^16 parents");
120+
return -1;
121+
}
122+
117123
node->time = commit->committer->when.time;
118-
node->out_degree = git_array_size(commit->parent_ids);
124+
node->out_degree = (uint16_t) git_array_size(commit->parent_ids);
119125
node->parents = alloc_parents(walk, node, node->out_degree);
120126
GIT_ERROR_CHECK_ALLOC(node->parents);
121127

src/commit_list.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ typedef struct git_commit_list_node {
3333
added:1,
3434
flags : FLAG_BITS;
3535

36-
unsigned short in_degree;
37-
unsigned short out_degree;
36+
uint16_t in_degree;
37+
uint16_t out_degree;
3838

3939
struct git_commit_list_node **parents;
4040
} git_commit_list_node;

src/integer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ GIT_INLINE(int) git__is_ssizet(size_t p)
2121
return p == (size_t)r;
2222
}
2323

24+
/** @return true if p fits into the range of a uint16_t */
25+
GIT_INLINE(int) git__is_uint16(size_t p)
26+
{
27+
uint16_t r = (uint16_t)p;
28+
return p == (size_t)r;
29+
}
30+
2431
/** @return true if p fits into the range of a uint32_t */
2532
GIT_INLINE(int) git__is_uint32(size_t p)
2633
{

0 commit comments

Comments
 (0)