ref: 6f767f2ae82dee8cbcfdf39c95a7a952c0e0565a
parent: f205736514bcfbbab5dc17a7db5d5a89b7961cc5
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Dec 4 10:57:40 EST 2020
all: convenience api for checking overflow we were using emalloc and erealloc to allocate or grow arrays, often without checking for overflow. This code adds a check for overflow, using a uvlong and capping to 2 gigabytes of array -- which ought to be enough for our uses. If bigger arrays end up needed, we can tweak the overflow checks in one place.
--- a/delta.c
+++ b/delta.c
@@ -36,7 +36,7 @@
db = dt->b;
dt->sz *= 2;
dt->nb = 0;
- dt->b = emalloc(dt->sz * sizeof(Dblock));
+ dt->b = eamalloc(dt->sz, sizeof(Dblock));
for(i = 0; i < sz; i++)
if(db[i].buf != nil)
addblk(dt, db[i].buf, db[i].len, db[i].off, db[i].rhash);
@@ -112,7 +112,7 @@
rh = 0;
dt->nb = 0;
dt->sz = 128;
- dt->b = emalloc(dt->sz*sizeof(Dblock));
+ dt->b = eamalloc(dt->sz, sizeof(Dblock));
while(e != bp + nbase){
e += nextblk(s, bp + nbase, &rh);
addblk(dt, s, e - s, s - bp, rh);
--- a/fetch.c
+++ b/fetch.c
@@ -175,8 +175,8 @@
nref = 0;
refsz = 16;
first = 1;
- have = emalloc(refsz * sizeof(have[0]));
- want = emalloc(refsz * sizeof(want[0]));
+ have = eamalloc(refsz, sizeof(have[0]));
+ want = eamalloc(refsz, sizeof(want[0]));
while(1){
n = readpkt(c, buf, sizeof(buf));
if(n == -1)
--- a/fs.c
+++ b/fs.c
@@ -669,7 +669,7 @@
oaux = o->aux;
aux = emalloc(sizeof(Gitaux));
aux->ncrumb = oaux->ncrumb;
- aux->crumb = emalloc(oaux->ncrumb * sizeof(Crumb));
+ aux->crumb = eamalloc(oaux->ncrumb, sizeof(Crumb));
for(i = 0; i < aux->ncrumb; i++){
aux->crumb[i] = oaux->crumb[i];
aux->crumb[i].name = estrdup(oaux->crumb[i].name);
--- a/git.h
+++ b/git.h
@@ -269,7 +269,9 @@
/* util functions */
void dprint(int, char *, ...);
+void *eamalloc(ulong, ulong);
void *emalloc(ulong);
+void *earealloc(void *, ulong, ulong);
void *erealloc(void *, ulong);
char *estrdup(char *);
int slurpdir(char *, Dir **);
--- a/objset.c
+++ b/objset.c
@@ -8,7 +8,7 @@
{
s->sz = 16;
s->nobj = 0;
- s->obj = emalloc(s->sz * sizeof(Hash));
+ s->obj = eamalloc(s->sz, sizeof(Hash));
}
void
@@ -41,7 +41,7 @@
s->sz *= 2;
s->nobj = 0;
- s->obj = emalloc(s->sz * sizeof(Hash));
+ s->obj = eamalloc(s->sz, sizeof(Hash));
for(i = 0; i < sz; i++)
if(obj[i])
osadd(s, obj[i]);
--- a/ref.c
+++ b/ref.c
@@ -335,7 +335,7 @@
free(q);
q = n;
}
- *res = emalloc(keep.nobj*sizeof(Object*));
+ *res = eamalloc(keep.nobj, sizeof(Object*));
*nres = 0;
for(i = 0; i < keep.sz; i++){
if(keep.obj[i] != nil && !oshas(&drop, keep.obj[i]->hash)){
@@ -568,7 +568,7 @@
free(ev.stk);
return -1;
}
- h = emalloc(ev.nstk*sizeof(Hash));
+ h = eamalloc(ev.nstk, sizeof(Hash));
for(i = 0; i < ev.nstk; i++)
h[i] = ev.stk[i]->hash;
*r = h;
--- a/save.c
+++ b/save.c
@@ -240,8 +240,8 @@
r = -1;
nsub = 0;
nent = t->tree->nent;
- ent = emalloc(nent * sizeof(*ent));
- sub = emalloc((epath - path)*sizeof(Object*));
+ ent = eamalloc(nent, sizeof(*ent));
+ sub = eamalloc((epath - path), sizeof(Object*));
memcpy(ent, t->tree->ent, nent*sizeof(*ent));
for(p = path; p != epath; p = ep){
ne = pathelt(elt, sizeof(elt), *p + off, &isdir);
--- a/send.c
+++ b/send.c
@@ -41,8 +41,8 @@
if(sendall)
return listrefs(tailp, refp);
nu = 0;
- tail = emalloc((nremoved + nbranch)*sizeof(Hash));
- ref = emalloc((nremoved + nbranch)*sizeof(char*));
+ tail = eamalloc((nremoved + nbranch), sizeof(Hash));
+ ref = eamalloc((nremoved + nbranch), sizeof(char*));
for(i = 0; i < nbranch; i++){
ref[nu] = estrdup(branch[i]);
if(resolveref(&tail[nu], branch[i]) == -1)
@@ -108,7 +108,7 @@
first = 1;
nupd = readours(&ours, &refs);
- theirs = emalloc(nupd*sizeof(Hash));
+ theirs = eamalloc(nupd, sizeof(Hash));
while(1){
n = readpkt(c, buf, sizeof(buf));
if(n == -1)
--- a/util.c
+++ b/util.c
@@ -8,6 +8,7 @@
Hash Zhash;
int chattygit;
+int hidepct;
Object*
emptydir(void)
@@ -61,11 +62,41 @@
}
void *
+eamalloc(ulong n, ulong sz)
+{
+ uvlong na;
+ void *v;
+
+ if((na = (uvlong)n*(uvlong)sz) >= (1ULL<<30))
+ sysfatal("alloc: overflow");
+ v = mallocz(na, 1);
+ if(v == nil)
+ sysfatal("malloc: %r");
+ setmalloctag(v, getcallerpc(&n));
+ return v;
+}
+
+void *
erealloc(void *p, ulong n)
{
void *v;
v = realloc(p, n);
+ if(v == nil)
+ sysfatal("realloc: %r");
+ setmalloctag(v, getcallerpc(&p));
+ return v;
+}
+
+void *
+earealloc(void *p, ulong n, ulong sz)
+{
+ uvlong na;
+ void *v;
+
+ if((na = (uvlong)n*(uvlong)sz) >= (1ULL<<30))
+ sysfatal("alloc: overflow");
+ v = realloc(p, na);
if(v == nil)
sysfatal("realloc: %r");
setmalloctag(v, getcallerpc(&p));