Blob
- Date:
- Message:
- sam: avoid out-of-bounds read in rterm Usually r->nused < r->nalloc and the read is in bounds. But it could in theory be right on the line and reading past the end of the allocation. Make it safe but preserve as much of the old semantics as possible. This use of rterm appears to be only for optimization purposes so the result does not matter for correctness.
- Actions:
- History | Blame | Raw File
1 #include "sam.h"2 /*3 * GROWDATASIZE must be big enough that all errors go out as Hgrowdata's,4 * so they will be scrolled into visibility in the ~~sam~~ window (yuck!).5 */6 #define GROWDATASIZE 50 /* if size is <= this, send data with grow */8 void rcut(List*, Posn, Posn);9 int rterm(List*, Posn);10 void rgrow(List*, Posn, Posn);12 static Posn growpos;13 static Posn grown;14 static Posn shrinkpos;15 static Posn shrunk;17 /*18 * rasp routines inform the terminal of changes to the file.19 *20 * a rasp is a list of spans within the file, and an indication21 * of whether the terminal knows about the span.22 *23 * optimize by coalescing multiple updates to the same span24 * if it is not known by the terminal.25 *26 * other possible optimizations: flush terminal's rasp by cut everything,27 * insert everything if rasp gets too large.28 */30 /*31 * only called for initial load of file32 */33 void34 raspload(File *f)35 {36 if(f->rasp == nil)37 return;38 grown = f->b.nc;39 growpos = 0;40 if(f->b.nc)41 rgrow(f->rasp, 0, f->b.nc);42 raspdone(f, 1);43 }45 void46 raspstart(File *f)47 {48 if(f->rasp == nil)49 return;50 grown = 0;51 shrunk = 0;52 outbuffered = 1;53 }55 void56 raspdone(File *f, int toterm)57 {58 if(f->dot.r.p1 > f->b.nc)59 f->dot.r.p1 = f->b.nc;60 if(f->dot.r.p2 > f->b.nc)61 f->dot.r.p2 = f->b.nc;62 if(f->mark.p1 > f->b.nc)63 f->mark.p1 = f->b.nc;64 if(f->mark.p2 > f->b.nc)65 f->mark.p2 = f->b.nc;66 if(f->rasp == nil)67 return;68 if(grown)69 outTsll(Hgrow, f->tag, growpos, grown);70 else if(shrunk)71 outTsll(Hcut, f->tag, shrinkpos, shrunk);72 if(toterm)73 outTs(Hcheck0, f->tag);74 outflush();75 outbuffered = 0;76 if(f == cmd){77 cmdpt += cmdptadv;78 cmdptadv = 0;79 }80 }82 void83 raspflush(File *f)84 {85 if(grown){86 outTsll(Hgrow, f->tag, growpos, grown);87 grown = 0;88 }89 else if(shrunk){90 outTsll(Hcut, f->tag, shrinkpos, shrunk);91 shrunk = 0;92 }93 outflush();94 }96 void97 raspdelete(File *f, uint p1, uint p2, int toterm)98 {99 long n;101 n = p2 - p1;102 if(n == 0)103 return;105 if(p2 <= f->dot.r.p1){106 f->dot.r.p1 -= n;107 f->dot.r.p2 -= n;108 }109 if(p2 <= f->mark.p1){110 f->mark.p1 -= n;111 f->mark.p2 -= n;112 }114 if(f->rasp == nil)115 return;117 if(f==cmd && p1<cmdpt){118 if(p2 <= cmdpt)119 cmdpt -= n;120 else121 cmdpt = p1;122 }123 if(toterm){124 if(grown){125 outTsll(Hgrow, f->tag, growpos, grown);126 grown = 0;127 }else if(shrunk && shrinkpos!=p1 && shrinkpos!=p2){128 outTsll(Hcut, f->tag, shrinkpos, shrunk);129 shrunk = 0;130 }131 if(!shrunk || shrinkpos==p2)132 shrinkpos = p1;133 shrunk += n;134 }135 rcut(f->rasp, p1, p2);136 }138 void139 raspinsert(File *f, uint p1, Rune *buf, uint n, int toterm)140 {141 Range r;143 if(n == 0)144 return;146 if(p1 < f->dot.r.p1){147 f->dot.r.p1 += n;148 f->dot.r.p2 += n;149 }150 if(p1 < f->mark.p1){151 f->mark.p1 += n;152 f->mark.p2 += n;153 }156 if(f->rasp == nil)157 return;158 if(f==cmd && p1<cmdpt)159 cmdpt += n;160 if(toterm){161 if(shrunk){162 outTsll(Hcut, f->tag, shrinkpos, shrunk);163 shrunk = 0;164 }165 if(n>GROWDATASIZE || !rterm(f->rasp, p1)){166 rgrow(f->rasp, p1, n);167 if(grown && growpos+grown!=p1 && growpos!=p1){168 outTsll(Hgrow, f->tag, growpos, grown);169 grown = 0;170 }171 if(!grown)172 growpos = p1;173 grown += n;174 }else{175 if(grown){176 outTsll(Hgrow, f->tag, growpos, grown);177 grown = 0;178 }179 rgrow(f->rasp, p1, n);180 r = rdata(f->rasp, p1, n);181 if(r.p1!=p1 || r.p2!=p1+n)182 panic("rdata in toterminal");183 outTsllS(Hgrowdata, f->tag, p1, n, tmprstr(buf, n));184 }185 }else{186 rgrow(f->rasp, p1, n);187 r = rdata(f->rasp, p1, n);188 if(r.p1!=p1 || r.p2!=p1+n)189 panic("rdata in toterminal");190 }191 }193 #define M 0x80000000L194 #define P(i) r->posnptr[i]195 #define T(i) (P(i)&M) /* in terminal */196 #define L(i) (P(i)&~M) /* length of this piece */198 void199 rcut(List *r, Posn p1, Posn p2)200 {201 Posn p, x;202 int i;204 if(p1 == p2)205 panic("rcut 0");206 for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))207 ;208 if(i == r->nused)209 panic("rcut 1");210 if(p < p1){ /* chop this piece */211 if(p+L(i) < p2){212 x = p1-p;213 p += L(i);214 }else{215 x = L(i)-(p2-p1);216 p = p2;217 }218 if(T(i))219 P(i) = x|M;220 else221 P(i) = x;222 i++;223 }224 while(i<r->nused && p+L(i)<=p2){225 p += L(i);226 dellist(r, i);227 }228 if(p < p2){229 if(i == r->nused)230 panic("rcut 2");231 x = L(i)-(p2-p);232 if(T(i))233 P(i) = x|M;234 else235 P(i) = x;236 }237 /* can we merge i and i-1 ? */238 if(i>0 && i<r->nused && T(i-1)==T(i)){239 x = L(i-1)+L(i);240 dellist(r, i--);241 if(T(i))242 P(i)=x|M;243 else244 P(i)=x;245 }246 }248 void249 rgrow(List *r, Posn p1, Posn n)250 {251 Posn p;252 int i;254 if(n == 0)255 panic("rgrow 0");256 for(p=0,i=0; i<r->nused && p+L(i)<=p1; p+=L(i++))257 ;258 if(i == r->nused){ /* stick on end of file */259 if(p!=p1)260 panic("rgrow 1");261 if(i>0 && !T(i-1))262 P(i-1)+=n;263 else264 inslist(r, i, n);265 }else if(!T(i)) /* goes in this empty piece */266 P(i)+=n;267 else if(p==p1 && i>0 && !T(i-1)) /* special case; simplifies life */268 P(i-1)+=n;269 else if(p==p1)270 inslist(r, i, n);271 else{ /* must break piece in terminal */272 inslist(r, i+1, (L(i)-(p1-p))|M);273 inslist(r, i+1, n);274 P(i) = (p1-p)|M;275 }276 }278 int279 rterm(List *r, Posn p1)280 {281 Posn p;282 int i;284 for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++))285 ;286 if(i==r->nused)287 return i > 0 && T(i-1);288 return T(i);289 }291 Range292 rdata(List *r, Posn p1, Posn n)293 {294 Posn p;295 int i;296 Range rg;298 if(n==0)299 panic("rdata 0");300 for(p = 0,i = 0; i<r->nused && p+L(i)<=p1; p+=L(i++))301 ;302 if(i==r->nused)303 panic("rdata 1");304 if(T(i)){305 n-=L(i)-(p1-p);306 if(n<=0){307 rg.p1 = rg.p2 = p1;308 return rg;309 }310 p+=L(i++);311 p1 = p;312 }313 if(T(i) || i==r->nused)314 panic("rdata 2");315 if(p+L(i)<p1+n)316 n = L(i)-(p1-p);317 rg.p1 = p1;318 rg.p2 = p1+n;319 if(p!=p1){320 inslist(r, i+1, L(i)-(p1-p));321 P(i)=p1-p;322 i++;323 }324 if(L(i)!=n){325 inslist(r, i+1, L(i)-n);326 P(i)=n;327 }328 P(i)|=M;329 /* now i is set; can we merge? */330 if(i<r->nused-1 && T(i+1)){331 P(i)=(n+=L(i+1))|M;332 dellist(r, i+1);333 }334 if(i>0 && T(i-1)){335 P(i)=(n+L(i-1))|M;336 dellist(r, i-1);337 }338 return rg;339 }