varint: use explicit width for integers
The varint subsystem currently uses implicit widths for integers. On the one hand we use `uintmax_t` for the actual value. On the other hand, we use `int` for the length of the encoded varint. Both of these have known maximum values, as we only support at most 16 bytes when encoding varints. Thus, we know that we won't ever exceed `uint64_t` for the actual value and `uint8_t` for the prefix length. Refactor the code to use explicit widths. Besides making the logic platform-independent, it also makes our life a bit easier in the next commit, where we reimplement "varint.c" in Rust. Suggested-by: Ezekiel Newren <ezekielnewren@gmail.com> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Oct 2, 2025 at 09:29 UTC
f366bfe16b350240c70c487d180c76ddcb8a1b2d
4 files changed
+19
-15
dir.c
+10
-8
@@ -3579,7 +3579,8 @@ static void write_one_dir(struct untracked_cache_dir *untracked,
3579
struct stat_data stat_data;
3580
struct strbuf *out = &wd->out;
3581
unsigned char intbuf[16];
3582
- unsigned int intlen, value;
3582
+ unsigned int value;
3583
+ uint8_t intlen;
3584
int i = wd->index++;
3585
3586
/*
@@ -3632,7 +3633,7 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra
3633
struct ondisk_untracked_cache *ouc;
3634
struct write_data wd;
3635
unsigned char varbuf[16];
3635
- int varint_len;
3636
+ uint8_t varint_len;
3637
const unsigned hashsz = the_hash_algo->rawsz;
3638
3639
CALLOC_ARRAY(ouc, 1);
@@ -3738,7 +3739,7 @@ static int read_one_dir(struct untracked_cache_dir **untracked_,
3739
struct untracked_cache_dir ud, *untracked;
3740
const unsigned char *data = rd->data, *end = rd->end;
3741
const unsigned char *eos;
3741
- unsigned int value;
3742
+ uint64_t value;
3743
int i;
3744
3745
memset(&ud, 0, sizeof(ud));
@@ -3830,7 +3831,8 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
3831
struct read_data rd;
3832
const unsigned char *next = data, *end = (const unsigned char *)data + sz;
3833
const char *ident;
3833
- int ident_len;
3834
+ uint64_t ident_len;
3835
+ uint64_t varint_len;
3836
ssize_t len;
3837
const char *exclude_per_dir;
3838
const unsigned hashsz = the_hash_algo->rawsz;
@@ -3867,8 +3869,8 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
3869
if (next >= end)
3870
goto done2;
3871
3870
- len = decode_varint(&next);
3871
- if (next > end || len == 0)
3872
+ varint_len = decode_varint(&next);
3873
+ if (next > end || varint_len == 0)
3874
goto done2;
3875
3876
rd.valid = ewah_new();
@@ -3877,9 +3879,9 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
3879
rd.data = next;
3880
rd.end = end;
3881
rd.index = 0;
3880
- ALLOC_ARRAY(rd.ucd, len);
3882
+ ALLOC_ARRAY(rd.ucd, varint_len);
3883
3882
- if (read_one_dir(&uc->root, &rd) || rd.index != len)
3884
+ if (read_one_dir(&uc->root, &rd) || rd.index != varint_len)
3885
goto done;
3886
3887
next = rd.data;
read-cache.c
+4
-2
@@ -1807,7 +1807,7 @@ static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
1807
1808
if (expand_name_field) {
1809
const unsigned char *cp = (const unsigned char *)name;
1810
- size_t strip_len, previous_len;
1810
+ uint64_t strip_len, previous_len;
1811
1812
/* If we're at the beginning of a block, ignore the previous name */
1813
strip_len = decode_varint(&cp);
@@ -2655,8 +2655,10 @@ static int ce_write_entry(struct hashfile *f, struct cache_entry *ce,
2655
hashwrite(f, ce->name, len);
2656
hashwrite(f, padding, align_padding_size(size, len));
2657
} else {
2658
- int common, to_remove, prefix_size;
2658
+ int common, to_remove;
2659
+ uint8_t prefix_size;
2660
unsigned char to_remove_vi[16];
2661
+
2662
for (common = 0;
2663
(common < previous_name->len &&
2664
ce->name[common] &&
varint.c
+3
-3
@@ -1,11 +1,11 @@
1
#include "git-compat-util.h"
2
#include "varint.h"
3
4
-uintmax_t decode_varint(const unsigned char **bufp)
4
+uint64_t decode_varint(const unsigned char **bufp)
5
{
6
const unsigned char *buf = *bufp;
7
unsigned char c = *buf++;
8
- uintmax_t val = c & 127;
8
+ uint64_t val = c & 127;
9
while (c & 128) {
10
val += 1;
11
if (!val || MSB(val, 7))
@@ -17,7 +17,7 @@ uintmax_t decode_varint(const unsigned char **bufp)
17
return val;
18
}
19
20
-int encode_varint(uintmax_t value, unsigned char *buf)
20
+uint8_t encode_varint(uint64_t value, unsigned char *buf)
21
{
22
unsigned char varint[16];
23
unsigned pos = sizeof(varint) - 1;
varint.h
+2
-2
@@ -1,7 +1,7 @@
1
#ifndef VARINT_H
2
#define VARINT_H
3
4
-int encode_varint(uintmax_t, unsigned char *);
5
-uintmax_t decode_varint(const unsigned char **);
4
+uint8_t encode_varint(uint64_t, unsigned char *);
5
+uint64_t decode_varint(const unsigned char **);
6
7
#endif /* VARINT_H */