Skip to content

Commit c7ab0ba

Browse files
peffgitster
authored andcommitted
avoid sprintf and strcpy with flex arrays
When we are allocating a struct with a FLEX_ARRAY member, we generally compute the size of the array and then sprintf or strcpy into it. Normally we could improve a dynamic allocation like this by using xstrfmt, but it doesn't work here; we have to account for the size of the rest of the struct. But we can improve things a bit by storing the length that we use for the allocation, and then feeding it to xsnprintf or memcpy, which makes it more obvious that we are not writing more than the allocated number of bytes. It would be nice if we had some kind of helper for allocating generic flex arrays, but it doesn't work that well: - the call signature is a little bit unwieldy: d = flex_struct(sizeof(*d), offsetof(d, path), fmt, ...); You need offsetof here instead of just writing to the end of the base size, because we don't know how the struct is packed (partially this is because FLEX_ARRAY might not be zero, though we can account for that; but the size of the struct may actually be rounded up for alignment, and we can't know that). - some sites do clever things, like over-allocating because they know they will write larger things into the buffer later (e.g., struct packed_git here). So we're better off to just write out each allocation (or add type-specific helpers, though many of these are one-off allocations anyway). Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6f687c2 commit c7ab0ba

File tree

6 files changed

+21
-14
lines changed

6 files changed

+21
-14
lines changed

archive.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,13 +171,14 @@ static void queue_directory(const unsigned char *sha1,
171171
unsigned mode, int stage, struct archiver_context *c)
172172
{
173173
struct directory *d;
174-
d = xmallocz(sizeof(*d) + base->len + 1 + strlen(filename));
174+
size_t len = base->len + 1 + strlen(filename) + 1;
175+
d = xmalloc(sizeof(*d) + len);
175176
d->up = c->bottom;
176177
d->baselen = base->len;
177178
d->mode = mode;
178179
d->stage = stage;
179180
c->bottom = d;
180-
d->len = sprintf(d->path, "%.*s%s/", (int)base->len, base->buf, filename);
181+
d->len = xsnprintf(d->path, len, "%.*s%s/", (int)base->len, base->buf, filename);
181182
hashcpy(d->oid.hash, sha1);
182183
}
183184

builtin/blame.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,12 +459,13 @@ static void queue_blames(struct scoreboard *sb, struct origin *porigin,
459459
static struct origin *make_origin(struct commit *commit, const char *path)
460460
{
461461
struct origin *o;
462-
o = xcalloc(1, sizeof(*o) + strlen(path) + 1);
462+
size_t pathlen = strlen(path) + 1;
463+
o = xcalloc(1, sizeof(*o) + pathlen);
463464
o->commit = commit;
464465
o->refcnt = 1;
465466
o->next = commit->util;
466467
commit->util = o;
467-
strcpy(o->path, path);
468+
memcpy(o->path, path, pathlen); /* includes NUL */
468469
return o;
469470
}
470471

fast-import.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -863,13 +863,15 @@ static void start_packfile(void)
863863
{
864864
static char tmp_file[PATH_MAX];
865865
struct packed_git *p;
866+
int namelen;
866867
struct pack_header hdr;
867868
int pack_fd;
868869

869870
pack_fd = odb_mkstemp(tmp_file, sizeof(tmp_file),
870871
"pack/tmp_pack_XXXXXX");
871-
p = xcalloc(1, sizeof(*p) + strlen(tmp_file) + 2);
872-
strcpy(p->pack_name, tmp_file);
872+
namelen = strlen(tmp_file) + 2;
873+
p = xcalloc(1, sizeof(*p) + namelen);
874+
xsnprintf(p->pack_name, namelen, "%s", tmp_file);
873875
p->pack_fd = pack_fd;
874876
p->do_not_close = 1;
875877
pack_file = sha1fd(pack_fd, p->pack_name);

refs.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,7 +2695,7 @@ static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data)
26952695
int namelen = strlen(entry->name) + 1;
26962696
struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
26972697
hashcpy(n->sha1, entry->u.value.oid.hash);
2698-
strcpy(n->name, entry->name);
2698+
memcpy(n->name, entry->name, namelen); /* includes NUL */
26992699
n->next = cb->ref_to_prune;
27002700
cb->ref_to_prune = n;
27012701
}
@@ -3984,10 +3984,10 @@ void ref_transaction_free(struct ref_transaction *transaction)
39843984
static struct ref_update *add_update(struct ref_transaction *transaction,
39853985
const char *refname)
39863986
{
3987-
size_t len = strlen(refname);
3988-
struct ref_update *update = xcalloc(1, sizeof(*update) + len + 1);
3987+
size_t len = strlen(refname) + 1;
3988+
struct ref_update *update = xcalloc(1, sizeof(*update) + len);
39893989

3990-
strcpy((char *)update->refname, refname);
3990+
memcpy((char *)update->refname, refname, len); /* includes NUL */
39913991
ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);
39923992
transaction->updates[transaction->nr++] = update;
39933993
return update;

sha1_file.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,9 +1180,10 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local)
11801180
struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path)
11811181
{
11821182
const char *path = sha1_pack_name(sha1);
1183-
struct packed_git *p = alloc_packed_git(strlen(path) + 1);
1183+
int alloc = strlen(path) + 1;
1184+
struct packed_git *p = alloc_packed_git(alloc);
11841185

1185-
strcpy(p->pack_name, path);
1186+
memcpy(p->pack_name, path, alloc); /* includes NUL */
11861187
hashcpy(p->sha1, sha1);
11871188
if (check_packed_git_idx(idx_path, p)) {
11881189
free(p);

submodule.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static int add_submodule_odb(const char *path)
122122
struct strbuf objects_directory = STRBUF_INIT;
123123
struct alternate_object_database *alt_odb;
124124
int ret = 0;
125+
int alloc;
125126
const char *git_dir;
126127

127128
strbuf_addf(&objects_directory, "%s/.git", path);
@@ -142,9 +143,10 @@ static int add_submodule_odb(const char *path)
142143
objects_directory.len))
143144
goto done;
144145

145-
alt_odb = xmalloc(objects_directory.len + 42 + sizeof(*alt_odb));
146+
alloc = objects_directory.len + 42; /* for "12/345..." sha1 */
147+
alt_odb = xmalloc(sizeof(*alt_odb) + alloc);
146148
alt_odb->next = alt_odb_list;
147-
strcpy(alt_odb->base, objects_directory.buf);
149+
xsnprintf(alt_odb->base, alloc, "%s", objects_directory.buf);
148150
alt_odb->name = alt_odb->base + objects_directory.len;
149151
alt_odb->name[2] = '/';
150152
alt_odb->name[40] = '\0';

0 commit comments

Comments
 (0)