fix: harden small core containers
This commit is contained in:
11
dict.c
11
dict.c
@@ -64,13 +64,15 @@ dictopen(char *path)
|
||||
Biobuf *b;
|
||||
Str key;
|
||||
char *line, *tab;
|
||||
int len;
|
||||
int len, lineno;
|
||||
|
||||
b = Bopen(path, OREAD);
|
||||
if(b == nil)
|
||||
die("can't open: %s", path);
|
||||
h = hmapalloc(4096);
|
||||
lineno = 0;
|
||||
while((line = Brdstr(b, '\n', 1)) != nil){
|
||||
lineno++;
|
||||
len = strlen(line);
|
||||
if(len > 0 && line[len-1] == '\r')
|
||||
line[--len] = '\0';
|
||||
@@ -84,6 +86,8 @@ dictopen(char *path)
|
||||
continue;
|
||||
}
|
||||
*tab = '\0';
|
||||
if(utflen(line) > Maxrunes)
|
||||
die("dictionary key too long: %s:%d", path, lineno);
|
||||
sinit(&key, line, tab - line);
|
||||
hmapset(&h, &key, tab+1, len - (tab - line) - 1);
|
||||
free(line);
|
||||
@@ -101,7 +105,10 @@ dictinit(char *dir)
|
||||
for(i = 0; i < nlang; i++){
|
||||
if(langs[i].dictname == nil)
|
||||
continue;
|
||||
snprint(path, sizeof(path), "%s/%s.dict", dir, langs[i].dictname);
|
||||
if(snprint(path, sizeof(path), "%s/%s.dict", dir,
|
||||
langs[i].dictname) >= (int)sizeof path)
|
||||
die("dictionary path too long: %s/%s.dict",
|
||||
dir, langs[i].dictname);
|
||||
langs[i].dict = dictopen(path);
|
||||
}
|
||||
}
|
||||
|
||||
14
hash.c
14
hash.c
@@ -25,7 +25,7 @@ hmapalloc(int nbuckets)
|
||||
int nsz;
|
||||
|
||||
if(nbuckets < 1)
|
||||
die("hmapalloc: no buckets");
|
||||
return nil;
|
||||
nsz = Tagsize;
|
||||
store = emalloc(sizeof(*h) + nbuckets * nsz);
|
||||
h = store;
|
||||
@@ -54,6 +54,8 @@ hmapget(Hmap *h, Str *key)
|
||||
Hnode *n;
|
||||
uchar *v;
|
||||
|
||||
if(h == nil || key == nil || key->n < 0 || key->n > Maxrunes)
|
||||
return nil;
|
||||
v = h->nodes + (hash(key) % h->nbs) * h->nsz;
|
||||
for(;;){
|
||||
n = (Hnode*)v;
|
||||
@@ -67,7 +69,7 @@ hmapget(Hmap *h, Str *key)
|
||||
}
|
||||
|
||||
static char*
|
||||
sdup(Str *s)
|
||||
sdup(Str *s, int *len)
|
||||
{
|
||||
char buf[Maxutf];
|
||||
char *p;
|
||||
@@ -77,6 +79,7 @@ sdup(Str *s)
|
||||
p = emalloc(n + 1);
|
||||
memmove(p, buf, n);
|
||||
p[n] = '\0';
|
||||
*len = n;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -121,6 +124,10 @@ hmapset(Hmap **store, Str *key, const char *val, int vlen)
|
||||
int next;
|
||||
vlong diff;
|
||||
|
||||
if(store == nil || *store == nil || key == nil ||
|
||||
key->n < 0 || key->n > Maxrunes || vlen < 0 ||
|
||||
(vlen > 0 && val == nil))
|
||||
return;
|
||||
newval = memdup(val, vlen);
|
||||
h = *store;
|
||||
v = h->nodes + (hash(key) % h->nbs) * h->nsz;
|
||||
@@ -151,8 +158,7 @@ hmapset(Hmap **store, Str *key, const char *val, int vlen)
|
||||
n = (Hnode*)v;
|
||||
replace:
|
||||
if(n->filled == 0){
|
||||
n->key = sdup(key);
|
||||
n->klen = strlen(n->key);
|
||||
n->key = sdup(key, &n->klen);
|
||||
n->filled = 1;
|
||||
}
|
||||
n->next = next;
|
||||
|
||||
18
main.c
18
main.c
@@ -67,12 +67,18 @@ threadmain(int argc, char **argv)
|
||||
dictresc = chancreate(sizeof(Dictres), 0);
|
||||
mapinit(argv[1]);
|
||||
dictinit(argv[1]);
|
||||
proccreate(drawthread, nil, 16384);
|
||||
proccreate(srvthread, nil, 16384);
|
||||
proccreate(ibusthread, nil, 32768);
|
||||
proccreate(waylandthread, nil, 32768);
|
||||
threadcreate(dictthread, nil, 16384);
|
||||
threadcreate(imthread, nil, 16384);
|
||||
if(proccreate(drawthread, nil, 16384) < 0)
|
||||
die("can't create draw worker");
|
||||
if(proccreate(srvthread, nil, 16384) < 0)
|
||||
die("can't create server worker");
|
||||
if(proccreate(ibusthread, nil, 32768) < 0)
|
||||
die("can't create IBus worker");
|
||||
if(proccreate(waylandthread, nil, 32768) < 0)
|
||||
die("can't create Wayland worker");
|
||||
if(threadcreate(dictthread, nil, 16384) < 0)
|
||||
die("can't create dictionary worker");
|
||||
if(threadcreate(imthread, nil, 16384) < 0)
|
||||
die("can't create input worker");
|
||||
|
||||
threadexits(nil);
|
||||
}
|
||||
|
||||
5
str.c
5
str.c
@@ -7,6 +7,8 @@ sinit(Str *s, char *src, int n)
|
||||
int len;
|
||||
|
||||
s->n = 0;
|
||||
if(n < 0 || (n > 0 && src == nil))
|
||||
return;
|
||||
while(n > 0 && s->n < Maxrunes){
|
||||
if(!fullrune(src, n))
|
||||
break;
|
||||
@@ -28,8 +30,9 @@ sclear(Str *s)
|
||||
void
|
||||
sputr(Str *s, Rune r)
|
||||
{
|
||||
/* Str is a capped value; appends at capacity leave it unchanged. */
|
||||
if(s->n >= Maxrunes)
|
||||
die("sputr overflow");
|
||||
return;
|
||||
s->r[s->n++] = r;
|
||||
}
|
||||
|
||||
|
||||
10
strans.c
10
strans.c
@@ -724,6 +724,12 @@ keystroke(u32int ks, u32int mod, Str *com)
|
||||
}
|
||||
if(im.l->trans == nil)
|
||||
return 0;
|
||||
if(im.pre.n >= Maxrunes ||
|
||||
(isjp(&im) && im.pre.n + im.raw.n >= Maxrunes)){
|
||||
commit(com);
|
||||
reset();
|
||||
return 0;
|
||||
}
|
||||
if(im.l->lang == LangKO)
|
||||
ks = kokey(ks, mod);
|
||||
n = dotrans(ks, com);
|
||||
@@ -858,7 +864,9 @@ mapinit(char *dir)
|
||||
for(i = 0; i < nelem(langs); i++){
|
||||
if(langs[i].mapname == nil)
|
||||
continue;
|
||||
snprint(path, sizeof(path), "%s/%s.map", dir, langs[i].mapname);
|
||||
if(snprint(path, sizeof(path), "%s/%s.map", dir,
|
||||
langs[i].mapname) >= (int)sizeof path)
|
||||
die("map path too long: %s/%s.map", dir, langs[i].mapname);
|
||||
langs[i].map = trieopen(path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,3 +76,37 @@ hmap_long_utf8_keys(struct ct *t)
|
||||
cleanup:
|
||||
hmapfree(h);
|
||||
}
|
||||
|
||||
void
|
||||
hmap_binary_keys_and_invalid_lengths(struct ct *t)
|
||||
{
|
||||
Hmap *h;
|
||||
Hnode *n;
|
||||
Str key, other;
|
||||
|
||||
h = hmapalloc(1);
|
||||
CT_CHECK(t, h != nil);
|
||||
key.n = 3;
|
||||
key.r[0] = 'a';
|
||||
key.r[1] = 0;
|
||||
key.r[2] = 'b';
|
||||
other = key;
|
||||
other.r[2] = 'c';
|
||||
hmapset(&h, &key, "one", 3);
|
||||
hmapset(&h, &other, "two", 3);
|
||||
n = hmapget(h, &key);
|
||||
if(CT_CHECK(t, n != nil)){
|
||||
CT_EQ_INT(t, 3, n->klen);
|
||||
CT_EQ_MEM(t, "one", n->val, n->vlen);
|
||||
}
|
||||
n = hmapget(h, &other);
|
||||
if(CT_CHECK(t, n != nil))
|
||||
CT_EQ_MEM(t, "two", n->val, n->vlen);
|
||||
hmapset(&h, &key, "bad", -1);
|
||||
hmapset(&h, &key, nil, 1);
|
||||
n = hmapget(h, &key);
|
||||
if(CT_CHECK(t, n != nil))
|
||||
CT_EQ_MEM(t, "one", n->val, n->vlen);
|
||||
CT_EQ_PTR(t, nil, hmapalloc(0));
|
||||
hmapfree(h);
|
||||
}
|
||||
|
||||
@@ -82,3 +82,21 @@ str_utf8_capacity(struct ct *t)
|
||||
CT_EQ_STR(t, "😀", buf);
|
||||
CT_EQ_INT(t, 'Z', buf[5]);
|
||||
}
|
||||
|
||||
void
|
||||
str_invalid_and_full_appends(struct ct *t)
|
||||
{
|
||||
Str s;
|
||||
int i;
|
||||
|
||||
sinit(&s, nil, 1);
|
||||
CT_EQ_INT(t, 0, s.n);
|
||||
sinit(&s, "x", -1);
|
||||
CT_EQ_INT(t, 0, s.n);
|
||||
for(i = 0; i < Maxrunes; i++)
|
||||
s.r[i] = 'a';
|
||||
s.n = Maxrunes;
|
||||
sputr(&s, 'z');
|
||||
CT_EQ_INT(t, Maxrunes, s.n);
|
||||
CT_EQ_INT(t, 'a', s.r[Maxrunes-1]);
|
||||
}
|
||||
|
||||
@@ -17,9 +17,12 @@ Str shownpre(Im*);
|
||||
void str_init_utf8(struct ct*);
|
||||
void str_edit_and_alias(struct ct*);
|
||||
void str_utf8_capacity(struct ct*);
|
||||
void str_invalid_and_full_appends(struct ct*);
|
||||
void hmap_set_replace_and_grow(struct ct*);
|
||||
void hmap_long_utf8_keys(struct ct*);
|
||||
void hmap_binary_keys_and_invalid_lengths(struct ct*);
|
||||
void trie_exact_prefix_and_duplicate(struct ct*);
|
||||
void trie_optional_outputs_and_invalid_lengths(struct ct*);
|
||||
void production_maps_load(struct ct*);
|
||||
void transmap_states(struct ct*);
|
||||
void korean_sequences(struct ct*);
|
||||
|
||||
@@ -34,6 +34,29 @@ cleanup:
|
||||
trieclose(trie);
|
||||
}
|
||||
|
||||
void
|
||||
trie_optional_outputs_and_invalid_lengths(struct ct *t)
|
||||
{
|
||||
char *v;
|
||||
Trie *trie;
|
||||
int n;
|
||||
|
||||
trie = trieopen("data/trie.map");
|
||||
CT_CHECK(t, trieget(trie, "a", 1, nil) != nil);
|
||||
v = nil;
|
||||
CT_CHECK(t, trielookup(trie, "a", 1, &v, nil));
|
||||
CT_CHECK(t, v != nil);
|
||||
n = -1;
|
||||
CT_CHECK(t, trielookup(trie, "a", 1, nil, &n));
|
||||
CT_EQ_INT(t, 5, n);
|
||||
CT_CHECK(t, trielookup(trie, "dupli", 5, nil, nil));
|
||||
CT_EQ_PTR(t, nil, trieget(trie, nil, 1, &n));
|
||||
CT_EQ_PTR(t, nil, trieget(trie, "a", -1, &n));
|
||||
CT_CHECK(t, !trielookup(trie, nil, 1, &v, &n));
|
||||
CT_CHECK(t, !trielookup(trie, "a", -1, &v, &n));
|
||||
trieclose(trie);
|
||||
}
|
||||
|
||||
void
|
||||
production_maps_load(struct ct *t)
|
||||
{
|
||||
|
||||
@@ -66,9 +66,12 @@ static const struct ct_test tests[] = {
|
||||
{ "str/init-utf8", str_init_utf8 },
|
||||
{ "str/edit-and-alias", str_edit_and_alias },
|
||||
{ "str/utf8-capacity", str_utf8_capacity },
|
||||
{ "str/invalid-full-appends", str_invalid_and_full_appends },
|
||||
{ "hmap/set-replace-grow", hmap_set_replace_and_grow },
|
||||
{ "hmap/long-utf8-keys", hmap_long_utf8_keys },
|
||||
{ "hmap/binary-invalid-lengths", hmap_binary_keys_and_invalid_lengths },
|
||||
{ "trie/exact-prefix-duplicate", trie_exact_prefix_and_duplicate },
|
||||
{ "trie/optional-invalid-lengths", trie_optional_outputs_and_invalid_lengths },
|
||||
{ "map/production-lifecycle", production_maps_load },
|
||||
{ "transmap/states", transmap_states },
|
||||
{ "hangul/sequences", korean_sequences },
|
||||
|
||||
9
trie.c
9
trie.c
@@ -118,6 +118,8 @@ trieget(Trie *t, char *key, int klen, int *vlen)
|
||||
int ni;
|
||||
int i;
|
||||
|
||||
if(t == nil || klen < 0 || (klen > 0 && key == nil))
|
||||
return nil;
|
||||
ni = t->root;
|
||||
for(i = 0; i < klen; i++){
|
||||
ni = find(t, ni, key[i]);
|
||||
@@ -126,6 +128,7 @@ trieget(Trie *t, char *key, int klen, int *vlen)
|
||||
}
|
||||
if(t->nodes[ni].val == nil)
|
||||
return nil;
|
||||
if(vlen != nil)
|
||||
*vlen = t->nodes[ni].vlen;
|
||||
return t->nodes[ni].val;
|
||||
}
|
||||
@@ -136,14 +139,18 @@ trielookup(Trie *t, char *key, int klen, char **val, int *vlen)
|
||||
int ni;
|
||||
int i;
|
||||
|
||||
if(t == nil || klen < 0 || (klen > 0 && key == nil))
|
||||
return 0;
|
||||
ni = t->root;
|
||||
for(i = 0; i < klen; i++){
|
||||
ni = find(t, ni, key[i]);
|
||||
if(ni < 0)
|
||||
return 0;
|
||||
}
|
||||
if(val != nil && t->nodes[ni].val != nil){
|
||||
if(t->nodes[ni].val != nil){
|
||||
if(val != nil)
|
||||
*val = t->nodes[ni].val;
|
||||
if(vlen != nil)
|
||||
*vlen = t->nodes[ni].vlen;
|
||||
}
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user