From 1e2c2c5c5f27c027f76cbce3a151d30e48f22006 From: Michael Forney Date: Sun, 21 Feb 2021 00:24:41 +0000 Subject: libaml: fix IndexField access when multiple reads/writes are needed Previously, accessing an IndexField would set the index field to a fixed value, and then read from the region associated with the data field (incorporating its offset). However if the read/write length is larger than the data field, it would just read past the end. Instead, the index needs to be updated for each access. To fix this, introduce a function rwfieldunit, which does one access of the region/index-data/bank, and use this in rwfield instead of rwreg directly. diff e7f36397ace2aaaf16a643080dcc439c5b061613 1e2c2c5c5f27c027f76cbce3a151d30e48f22006 --- a/sys/src/libaml/aml.c Thu Feb 18 00:58:35 2021 +++ b/sys/src/libaml/aml.c Sat Feb 20 16:24:41 2021 @@ -72,6 +72,7 @@ struct Field { void *reg; /* Buffer or Region */ Field *index; + Field *data; void *indexv; int flags; int bitoff; @@ -219,6 +220,7 @@ gcmark(f->reg); gcmark(f->index); gcmark(f->indexv); + gcmark(f->data); break; } } @@ -608,17 +610,41 @@ } } +static void *rwfield(Field *f, void *v, int write); + +static uvlong +rwfieldunit(Field *f, int off, int len, uvlong v, int write) +{ + void *b, *reg; + + if(f->reg){ + if((reg = deref(f->reg)) == nil) + return 0; + v = rwreg(reg, off, len, v, write); + }else if(f->index && f->data){ + rwfield(f->index, mki(off), 1); + if(write){ + b = mk('b', len); + putle(b, len, v); + rwfield(f->data, b, 1); + }else{ + b = rwfield(f->data, nil, 0); + v = getle(b, len); + } + } + return v; +} + static void* rwfield(Field *f, void *v, int write) { int boff, blen, wo, ws, wl, wa, wd, i; uvlong w, m; - void *reg; uchar *b; - if(f == nil || (reg = deref(f->reg)) == nil) + if(f == nil) return nil; - if(f->index) + if(f->indexv) store(f->indexv, f->index); blen = f->bitlen; if(write){ @@ -649,11 +675,11 @@ w <<= ws; if(wl != wd){ m = ((1ULL<> ws; + w = rwfieldunit(f, wo*wa, wa, 0, 0) >> ws; for(i = 0; i < wl; i++, boff++){ b[boff/8] |= (w&1)<<(boff%8); w >>= 1; @@ -937,9 +963,12 @@ /* no break */ case 'f': l = p; - if(l->index) + if(l->data) return fmtprint(f, "IndexField(%x, %x, %x) @ %V[%V]", - l->flags, l->bitoff, l->bitlen, l->index, l->indexv); + l->flags, l->bitoff, l->bitlen, l->data, l->index); + else if(l->indexv) + return fmtprint(f, "BankField(%x, %x, %x, %V=%V) @ %V", + l->flags, l->bitoff, l->bitlen, l->index, l->indexv, l->reg); return fmtprint(f, "Field(%x, %x, %x) @ %V", l->flags, l->bitoff, l->bitlen, l->reg); default: @@ -1374,11 +1403,12 @@ static void* evalfield(void) { - int flags, bitoff, wa, n; - Field *f, *df; + int flags, bitoff, n; + Field *f, *xf, *df; Name *d; uchar *p; + xf = nil; df = nil; flags = 0; bitoff = 0; @@ -1387,6 +1417,9 @@ flags = ival(FP->arg[1]); break; case Oxfld: + xf = deref(FP->arg[0]); + if(xf == nil || TAG(xf) != 'f') + goto Out; df = deref(FP->arg[1]); if(df == nil || TAG(df) != 'f') goto Out; @@ -1425,21 +1458,17 @@ f = mk('f', sizeof(Field)); f->flags = flags; f->bitlen = n; + f->bitoff = bitoff; switch(FP->op - optab){ case Ofld: f->reg = FP->arg[0]; - f->bitoff = bitoff; break; case Oxfld: - wa = fieldalign(df->flags); - f->reg = df->reg; - f->bitoff = df->bitoff + (bitoff % (wa*8)); - f->indexv = mki((bitoff/(wa*8))*wa); - f->index = FP->arg[0]; + f->data = df; + f->index = xf; break; case Obfld: f->reg = FP->arg[0]; - f->bitoff = bitoff; f->indexv = FP->arg[2]; f->index = df; break;