diff options
author | Jorge Arellano Cid <jcid@dillo.org> | 2013-08-07 11:25:56 -0400 |
---|---|---|
committer | Jorge Arellano Cid <jcid@dillo.org> | 2013-08-07 11:25:56 -0400 |
commit | a29350364b3b340dfa74382f7b61e33f446ddf4d (patch) | |
tree | 1550f016e33e99a3c64dca9ec896227baa864986 /src/html.cc | |
parent | 0d0e61f454008dc27d49a3b6a5f1a97f9f81297a (diff) |
Add nested inputs cleanup and handling.
This patch avoids a family of problems that arise from handling nested inputs.
from invalid memory access up to crashes.
e.g. details in bof-read-47_attachView.html.asan.
This patch is much wider than the above referred instance.
Diffstat (limited to 'src/html.cc')
-rw-r--r-- | src/html.cc | 60 |
1 files changed, 58 insertions, 2 deletions
diff --git a/src/html.cc b/src/html.cc index 1023e4aa..eb6f3909 100644 --- a/src/html.cc +++ b/src/html.cc @@ -1329,6 +1329,9 @@ static void Html_tag_cleanup_to_idx(DilloHtml *html, int idx) */ static void Html_tag_cleanup_at_close(DilloHtml *html, int new_idx) { + static int i_BUTTON = a_Html_tag_index("button"), + i_SELECT = a_Html_tag_index("select"), + i_TEXTAREA = a_Html_tag_index("textarea"); int w3c_mode = !prefs.w3c_plus_heuristics; int stack_idx, tag_idx, matched = 0, expected = 0; TagInfo new_tag = Tags[new_idx]; @@ -1344,6 +1347,11 @@ static void Html_tag_cleanup_at_close(DilloHtml *html, int new_idx) } else if (Tags[tag_idx].EndTag == 'O') { /* skip an optional tag */ continue; + } else if ((new_idx == i_BUTTON && html->InFlags & IN_BUTTON) || + (new_idx == i_SELECT && html->InFlags & IN_SELECT) || + (new_idx == i_TEXTAREA && html->InFlags & IN_TEXTAREA)) { + /* let these elements close tags inside them */ + continue; } else if (w3c_mode || Tags[tag_idx].TagLevel >= new_tag.TagLevel) { /* this is the tag that should have been closed */ expected = 1; @@ -1362,6 +1370,50 @@ static void Html_tag_cleanup_at_close(DilloHtml *html, int new_idx) } /* + * Avoid nesting and inter-nesting of BUTTON, SELECT and TEXTAREA, + * by closing them before opening another. + * This is not an HTML SPEC restriction , but it avoids lots of trouble + * inside dillo (concurrent inputs), and makes almost no sense to have. + */ +static void Html_tag_cleanup_nested_inputs(DilloHtml *html, int new_idx) +{ + static int i_BUTTON = a_Html_tag_index("button"), + i_SELECT = a_Html_tag_index("select"), + i_TEXTAREA = a_Html_tag_index("textarea"); + int stack_idx, u_idx, matched = 0; + + dReturn_if_fail(html->InFlags & (IN_BUTTON | IN_SELECT | IN_TEXTAREA)); + dReturn_if_fail(new_idx == i_BUTTON || new_idx == i_SELECT || + new_idx == i_TEXTAREA); + + /* Get the unclosed tag index */ + u_idx = (html->InFlags & IN_BUTTON) ? i_BUTTON : + (html->InFlags & IN_SELECT) ? i_SELECT : i_TEXTAREA; + + /* Look for it inside the stack */ + stack_idx = html->stack->size(); + while (--stack_idx) { + if (html->stack->getRef(stack_idx)->tag_idx == u_idx) { + /* matching tag found */ + matched = 1; + break; + } + } + + if (matched) { + BUG_MSG("attempt to nest <%s> element inside <%s> -- closing <%s>\n", + Tags[new_idx].name, Tags[u_idx].name, Tags[u_idx].name); + Html_tag_cleanup_to_idx(html, stack_idx); + } else { + MSG_WARN("Inconsistent parser state, flag is SET but no '%s' element" + "was found in the stack\n", Tags[u_idx].name); + } + + html->InFlags &= ~(IN_BUTTON | IN_SELECT | IN_TEXTAREA); +} + + +/* * Some parsing routines. */ @@ -3569,6 +3621,10 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize) if ((html->InFlags & IN_PRE) && Html_tag_pre_excludes(ni)) BUG_MSG("<pre> is not allowed to contain <%s>\n", Tags[ni].name); + /* Make sure these elements don't nest each other */ + if (html->InFlags & (IN_BUTTON | IN_SELECT | IN_TEXTAREA)) + Html_tag_cleanup_nested_inputs(html, ni); + /* Push the tag into the stack */ Html_push_tag(html, ni); @@ -3579,7 +3635,7 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize) Html_parse_common_attrs(html, tag, tagsize); /* Call the open function for this tag */ - _MSG("Open : %s\n", Tags[ni].name); + _MSG("Html_process_tag Open : %s\n", Tags[ni].name); Tags[ni].open (html, tag, tagsize); if (! S_TOP(html)->display_none) { @@ -3636,7 +3692,7 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize) (strchr(" \"'", tag[tagsize-3]) || /* [ "']/> */ (size_t)tagsize == strlen(Tags[ni].name) + 3))) { /* <x/> */ - _MSG("Close: %s\n", Tags[ni].name); + _MSG("Html_process_tag Close: %s\n", Tags[ni].name); Html_tag_cleanup_at_close(html, ni); /* This was a close tag */ html->ReqTagClose = false; |