Commit 5cf17e0f by Patrick Steinhardt

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.
parent 5988cf34
...@@ -114,8 +114,14 @@ static int commit_quick_parse( ...@@ -114,8 +114,14 @@ static int commit_quick_parse(
return error; return error;
} }
if (!git__is_uint16(git_array_size(commit->parent_ids))) {
git__free(commit);
git_error_set(GIT_ERROR_INVALID, "commit has more than 2^16 parents");
return -1;
}
node->time = commit->committer->when.time; node->time = commit->committer->when.time;
node->out_degree = git_array_size(commit->parent_ids); node->out_degree = (uint16_t) git_array_size(commit->parent_ids);
node->parents = alloc_parents(walk, node, node->out_degree); node->parents = alloc_parents(walk, node, node->out_degree);
GIT_ERROR_CHECK_ALLOC(node->parents); GIT_ERROR_CHECK_ALLOC(node->parents);
......
...@@ -33,8 +33,8 @@ typedef struct git_commit_list_node { ...@@ -33,8 +33,8 @@ typedef struct git_commit_list_node {
added:1, added:1,
flags : FLAG_BITS; flags : FLAG_BITS;
unsigned short in_degree; uint16_t in_degree;
unsigned short out_degree; uint16_t out_degree;
struct git_commit_list_node **parents; struct git_commit_list_node **parents;
} git_commit_list_node; } git_commit_list_node;
......
...@@ -21,6 +21,13 @@ GIT_INLINE(int) git__is_ssizet(size_t p) ...@@ -21,6 +21,13 @@ GIT_INLINE(int) git__is_ssizet(size_t p)
return p == (size_t)r; return p == (size_t)r;
} }
/** @return true if p fits into the range of a uint16_t */
GIT_INLINE(int) git__is_uint16(size_t p)
{
uint16_t r = (uint16_t)p;
return p == (size_t)r;
}
/** @return true if p fits into the range of a uint32_t */ /** @return true if p fits into the range of a uint32_t */
GIT_INLINE(int) git__is_uint32(size_t p) GIT_INLINE(int) git__is_uint32(size_t p)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment