ref: 95fac5e87304a50f7e93de94f0f682ec06565006
parent: cca9a1b52381fe2c839350226eceeb1cc987c27f
author: cinap_lenrek <[email protected]>
date: Wed Sep 4 20:55:58 EDT 2013
libhtml: fix potential linked list corruption the difficulty is freeing items while parsing because items might already be linked into various linked lists like in docinfo.images or form.fiels. so we link images, tables and formfields to the docinfo as the final step of getitems() pass using the new recursive function linkitems(). as only reachable items get linked theres no danger of dangeling pointers.
--- a/sys/include/html.h
+++ b/sys/include/html.h
@@ -253,7 +253,6 @@
int y; /* y coord of top */
uchar side; /* margin it floats to: ALleft or ALright */
uchar infloats; /* true if this has been added to a lay.floats */
- Ifloat* nextfloat; /* in list of floats */
};
--- a/sys/src/libhtml/build.c
+++ b/sys/src/libhtml/build.c
@@ -54,6 +54,7 @@
int ntables;
int nanchors;
int nframes;
+ Formfield* curfield;
Form* curform;
Map* curmap;
Table* tabstk;
@@ -358,6 +359,7 @@
is->ntables = 0;
is->nanchors = 0;
is->nframes = 0;
+ is->curfield = nil;
is->curform = nil;
is->curmap = nil;
is->tabstk = nil;
@@ -365,6 +367,62 @@
return is;
}
+static void
+linkitems(Docinfo *di, Item *it)
+{
+ Formfield *ff;
+ Tablecell *c;
+ Table *tt;
+
+ while(it != nil){
+ switch(it->tag) {
+ case Iimagetag:
+ /* link image to docinfo */
+ ((Iimage*)it)->nextimage = di->images;
+ di->images = (Iimage*)it;
+ break;
+ case Iformfieldtag:
+ /* link formfield to form */
+ ff = ((Iformfield*)it)->formfield;
+ if(ff != nil && ff->form != nil){
+ for(ff = ff->form->fields; ff != nil; ff = ff->next){
+ if(ff == ((Iformfield*)it)->formfield)
+ goto Next;
+ if(ff->next == nil)
+ break;
+ }
+ ((Iformfield*)it)->formfield->next = nil;
+ if(ff != nil){
+ ff->next = ((Iformfield*)it)->formfield;
+ ff = ff->next;
+ } else {
+ ff = ((Iformfield*)it)->formfield;
+ ff->form->fields = ff;
+ }
+ linkitems(di, ff->image);
+ }
+ break;
+ case Itabletag:
+ /* link table to docinfo */
+ tt = ((Itable*)it)->table;
+ if(tt == nil)
+ break;
+ tt->tabletok = nil;
+ tt->next = di->tables;
+ di->tables = tt;
+ linkitems(di, tt->caption);
+ for(c = tt->cells; c != nil; c = c->next)
+ linkitems(di, c->content);
+ break;
+ case Ifloattag:
+ linkitems(di, ((Ifloat*)it)->item);
+ break;
+ }
+ Next:
+ it = it->next;
+ }
+}
+
static Item *getitems(ItemSource* is, uchar* data, int datalen);
// Parse an html document and create a list of layout items.
@@ -453,7 +511,6 @@
Rune* script;
Map* map;
Form* frm;
- Iimage* ii;
Kidinfo* kd;
Kidinfo* ks;
Kidinfo* pks;
@@ -693,19 +750,9 @@
bg = makebackground(nil, acolorval(tok, Abgcolor, di->background.color));
bgurl = aurlval(tok, Abackground, nil, di->base);
if(bgurl != nil) {
- if(di->backgrounditem != nil){
- Iimage **ii;
- for(ii=&di->images; *ii != nil; ii = &((*ii)->nextimage)){
- if(*ii == di->backgrounditem){
- *ii = di->backgrounditem->nextimage;
- break;
- }
- }
+ if(di->backgrounditem != nil)
freeitem(di->backgrounditem);
- }
di->backgrounditem = (Iimage*)newiimage(bgurl, nil, ALnone, 0, 0, 0, 0, 0, 0, nil);
- di->backgrounditem->nextimage = di->images;
- di->images = di->backgrounditem;
}
ps->curbg = bg;
di->background = bg;
@@ -902,8 +949,6 @@
fprint(2, "warning: unexpected </FORM>\n");
continue;
}
- // put fields back in input order
- is->curform->fields = (Formfield*)_revlist((List*)is->curform->fields);
is->curform = nil;
break;
@@ -1092,10 +1137,6 @@
ps->skipwhite = 0;
additem(ps, img, tok);
}
- if(!ps->skipping) {
- ((Iimage*)img)->nextimage = di->images;
- di->images = (Iimage*)img;
- }
ps->curanchor = oldcuranchor;
break;
@@ -1107,7 +1148,7 @@
fprint(2, "<INPUT> not inside <FORM>\n");
continue;
}
- is->curform->fields = field = newformfield(
+ field = newformfield(
atabval(tok, Atype, input_tab, NINPUTTAB, Ftext),
++is->curform->nfields,
is->curform,
@@ -1115,7 +1156,7 @@
aval(tok, Avalue),
auintval(tok, Asize, 0),
auintval(tok, Amaxlength, 1000),
- is->curform->fields);
+ nil);
if(aflagval(tok, Achecked))
field->flags = FFchecked;
@@ -1167,9 +1208,6 @@
atabval(tok, Aalign, align_tab, NALIGNTAB, ALbottom),
auintval(tok, Awidth, 0), auintval(tok, Aheight, 0),
0, 0, 0, 0, nil);
- ii = (Iimage*)field->image;
- ii->nextimage = di->images;
- di->images = ii;
break;
case Freset:
@@ -1202,7 +1240,7 @@
di->forms);
di->forms = frm;
ff = newformfield(Ftext,
- 1,
+ ++frm->nfields,
frm,
_Strdup(L"_ISINDEX_"),
nil,
@@ -1209,8 +1247,6 @@
50,
1000,
nil);
- frm->fields = ff;
- frm->nfields = 1;
additem(ps, newiformfield(ff), tok);
addbrk(ps, 1, 0);
break;
@@ -1407,7 +1443,7 @@
fprint(2, "<SELECT> not inside <FORM>\n");
continue;
}
- field = newformfield(Fselect,
+ is->curfield = field = newformfield(Fselect,
++is->curform->nfields,
is->curform,
aval(tok, Aname),
@@ -1414,8 +1450,7 @@
nil,
auintval(tok, Asize, 0),
0,
- is->curform->fields);
- is->curform->fields = field;
+ nil);
if(aflagval(tok, Amultiple))
field->flags = FFmultiple;
ffit = newiformfield(field);
@@ -1429,16 +1464,17 @@
break;
case Tselect+RBRA:
- if(is->curform == nil || is->curform->fields == nil) {
+ if(is->curform == nil || is->curfield == nil) {
if(warn)
fprint(2, "warning: unexpected </SELECT>\n");
continue;
}
- field = is->curform->fields;
+ field = is->curfield;
if(field->ftype != Fselect)
continue;
// put options back in input order
field->options = (Option*)_revlist((List*)field->options);
+ is->curfield = nil;
break;
// <!ELEMENT (STRIKE|U) - - (%text)*>
@@ -1553,8 +1589,6 @@
}
else
is->tabstk = is->tabstk->next;
- curtab->next = di->tables;
- di->tables = curtab;
curtab = is->tabstk;
if(!isempty)
addbrk(ps, 0, 0);
@@ -1649,8 +1683,7 @@
nil,
0,
0,
- is->curform->fields);
- is->curform->fields = field;
+ nil);
field->rows = auintval(tok, Arows, 3);
field->cols = auintval(tok, Acols, 50);
field->value = getpcdata(toks, tokslen, &toki);
@@ -1803,8 +1836,6 @@
}
if(is->tabstk != nil)
is->tabstk = is->tabstk->next;
- curtab->next = di->tables;
- di->tables = curtab;
curtab = is->tabstk;
}
outerps = lastps(ps);
@@ -1828,6 +1859,7 @@
else
printitems(ans, "getitems returning:");
}
+ linkitems(di, ans);
_freetokens(toks, tokslen);
return ans;
}
@@ -3738,7 +3770,6 @@
t->caption_place = ALbottom;
t->caption_lay = nil;
t->tabletok = tok;
- t->tabletok = nil;
t->next = link;
return t;
}