mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Bug 698: Keep forms contiguous and non-overlapping and start from 0.
In document.forms, each struct form has form_num and form_end members that reserve a subrange of [0, INT_MAX] to that form. Previously, multiple forms in the list could have form_end == INT_MAX and thus overlap each other. Prevent that by adjusting form_end of each form newly added to the list. Revert438f039bda
, "check_html_form_hierarchy: Old code was buggy.", which made check_html_form_hierarchy attach controls to the wrong forms. Instead, construct the dummy form ("for those Flying Dutchmans") at form_num == 0 always before adding any real forms to the list. This prevents the assertion failure by ensuring that every possible form_control.position is covered by some form, if there are any forms. Add a function assert_forms_list_ok, which checks that the set of forms actually covers the [0, INT_MAX] range without overlapping, as intended. Call that from check_html_form_hierarchy to detect any corruption. I have tested this code (before any cherry-picking) with: - bug 613 attachment 210: didn't crash - bug 714 attachment 471: didn't crash - bug 961 attachment 382: didn't crash - bug 698 attachment 239: all the submit buttons showed the right URLs - bug 698 attachment 470: the submit button showed the right URL (cherry picked from commit386a5d517b
, with conflicts)
This commit is contained in:
parent
295c7760f7
commit
fd7968e638
2
NEWS
2
NEWS
@ -15,6 +15,8 @@ To be released as 0.11.5.
|
|||||||
* critical bug 1030: an assertion used to fail in the search dialog
|
* critical bug 1030: an assertion used to fail in the search dialog
|
||||||
on systems that lack a usable <regex.h>
|
on systems that lack a usable <regex.h>
|
||||||
* major bug 503: various fixes in parsing and updating of elinks.conf
|
* major bug 503: various fixes in parsing and updating of elinks.conf
|
||||||
|
* bug 698: Attach controls to the intended form even if it is
|
||||||
|
incorrectly nested in a table. (Was broken in 0.11.4.)
|
||||||
* build bug 1021: fixed uninitialized variable in http_got_header
|
* build bug 1021: fixed uninitialized variable in http_got_header
|
||||||
|
|
||||||
ELinks 0.11.4:
|
ELinks 0.11.4:
|
||||||
|
@ -1468,7 +1468,11 @@ end:
|
|||||||
static void
|
static void
|
||||||
html_special_form(struct part *part, struct form *form)
|
html_special_form(struct part *part, struct form *form)
|
||||||
{
|
{
|
||||||
|
struct form *nform;
|
||||||
|
|
||||||
assert(part && form);
|
assert(part && form);
|
||||||
|
assert(form->form_num > 0);
|
||||||
|
assert(form->form_end == INT_MAX);
|
||||||
if_assert_failed return;
|
if_assert_failed return;
|
||||||
|
|
||||||
if (!part->document) {
|
if (!part->document) {
|
||||||
@ -1476,50 +1480,60 @@ html_special_form(struct part *part, struct form *form)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!list_empty(part->document->forms)) {
|
/* Make a fake form with form_num == 0 so that there is
|
||||||
struct form *nform;
|
* something to use if form controls appear above the first
|
||||||
|
* actual FORM element. There can never be a real form with
|
||||||
/* Make sure the new form ``claims'' its slice of the form range
|
* form_num == 0 because the form_num is the position after the
|
||||||
* maintained in the form_num and form_end variables. */
|
* "<form" characters and that's already five characters. The
|
||||||
foreach (nform, part->document->forms) {
|
* fake form does not have a name, and it gets a form_view and
|
||||||
if (form->form_num < nform->form_num
|
* becomes visible to ECMAScript only if it actually has
|
||||||
|| nform->form_end < form->form_num)
|
* controls in it. */
|
||||||
continue;
|
if (list_empty(part->document->forms)) {
|
||||||
|
nform = init_form();
|
||||||
/* First check if the form has identical form numbers.
|
if (!nform) {
|
||||||
* That should only be the case when the form being
|
done_form(form);
|
||||||
* added is in fact the same form in which case it
|
return;
|
||||||
* should be dropped. The fact that this can happen
|
|
||||||
* suggests that the table renderering can be confused.
|
|
||||||
* See bug 647 for a test case. */
|
|
||||||
if (nform->form_num == form->form_num
|
|
||||||
&& nform->form_end == form->form_end) {
|
|
||||||
done_form(form);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The form start is inside an already added form, so
|
|
||||||
* partition the space of the existing form and get
|
|
||||||
* |old|new|. */
|
|
||||||
nform->form_end = form->form_num - 1;
|
|
||||||
assertm(nform->form_num <= nform->form_end,
|
|
||||||
"[%d:%d] [%d:%d]", nform->form_num, nform->form_end,
|
|
||||||
form->form_num, form->form_end);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} else {
|
nform->form_num = 0;
|
||||||
/* If it is the first form make sure it eats the whole form
|
add_to_list(part->document->forms, nform);
|
||||||
* range. */
|
|
||||||
#if 0
|
|
||||||
/* Disabled because in tables the parse order may lead to a
|
|
||||||
* later form being parsed before a preceeding one causing the
|
|
||||||
* wrong order if we set it to zero. Let's hope it doesn't break
|
|
||||||
* anything else. */
|
|
||||||
form->form_num = 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_to_list(part->document->forms, form);
|
/* Make sure the new form ``claims'' its slice of the form range
|
||||||
|
* maintained in the form_num and form_end variables. */
|
||||||
|
foreach (nform, part->document->forms) {
|
||||||
|
if (form->form_num < nform->form_num
|
||||||
|
|| nform->form_end < form->form_num)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* First check if the form has identical form numbers.
|
||||||
|
* That should only be the case when the form being
|
||||||
|
* added is in fact the same form in which case it
|
||||||
|
* should be dropped. The fact that this can happen
|
||||||
|
* suggests that the table renderering can be confused.
|
||||||
|
* See bug 647 for a test case.
|
||||||
|
* Do not compare form->form_end here because it is
|
||||||
|
* normally set by this function and that has obviously
|
||||||
|
* not yet been done. */
|
||||||
|
if (nform->form_num == form->form_num) {
|
||||||
|
done_form(form);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The form start is inside an already added form, so
|
||||||
|
* partition the space of the existing form and get
|
||||||
|
* |old|new|. */
|
||||||
|
form->form_end = nform->form_end;
|
||||||
|
nform->form_end = form->form_num - 1;
|
||||||
|
assertm(nform->form_num <= nform->form_end,
|
||||||
|
"[%d:%d] [%d:%d]", nform->form_num, nform->form_end,
|
||||||
|
form->form_num, form->form_end);
|
||||||
|
add_to_list(part->document->forms, form);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERROR("hole between forms");
|
||||||
|
done_form(form);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1564,6 +1578,51 @@ html_special_form_control(struct part *part, struct form_control *fc)
|
|||||||
add_to_list(form->items, fc);
|
add_to_list(form->items, fc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG
|
||||||
|
/** Assert that each form in the list has a different form.form_num
|
||||||
|
* ... form.form_end range and that the ranges are contiguous and
|
||||||
|
* together cover all numbers from 0 to INT_MAX. Alternatively, the
|
||||||
|
* whole list may be empty. This function can be called from a
|
||||||
|
* debugger, or automatically from some places.
|
||||||
|
*
|
||||||
|
* This function may leave assert_failed = 1; the caller must use
|
||||||
|
* if_assert_failed. */
|
||||||
|
static void
|
||||||
|
assert_forms_list_ok(struct list_head *forms)
|
||||||
|
{
|
||||||
|
int saw_form_num_0 = 0;
|
||||||
|
struct form *outer;
|
||||||
|
|
||||||
|
if (list_empty(*forms)) return;
|
||||||
|
|
||||||
|
/* O(n^2) algorithm, but it's only for debugging. */
|
||||||
|
foreach (outer, *forms) {
|
||||||
|
int followers = 0;
|
||||||
|
struct form *inner;
|
||||||
|
|
||||||
|
if (outer->form_num == 0)
|
||||||
|
saw_form_num_0++;
|
||||||
|
|
||||||
|
foreach (inner, *forms) {
|
||||||
|
assert(inner == outer
|
||||||
|
|| inner->form_num > outer->form_end
|
||||||
|
|| outer->form_num > inner->form_end);
|
||||||
|
if (outer->form_end == inner->form_num - 1)
|
||||||
|
followers++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outer->form_end == INT_MAX)
|
||||||
|
assert(followers == 0);
|
||||||
|
else
|
||||||
|
assert(followers == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(saw_form_num_0 == 1);
|
||||||
|
}
|
||||||
|
#else /* !CONFIG_DEBUG */
|
||||||
|
# define assert_forms_list_ok(forms) ((void) 0)
|
||||||
|
#endif /* !CONFIG_DEBUG */
|
||||||
|
|
||||||
/* Reparents form items based on position in the source. */
|
/* Reparents form items based on position in the source. */
|
||||||
void
|
void
|
||||||
check_html_form_hierarchy(struct part *part)
|
check_html_form_hierarchy(struct part *part)
|
||||||
@ -1576,6 +1635,9 @@ check_html_form_hierarchy(struct part *part)
|
|||||||
if (list_empty(document->forms))
|
if (list_empty(document->forms))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
assert_forms_list_ok(&document->forms);
|
||||||
|
if_assert_failed {}
|
||||||
|
|
||||||
/* Take out all badly placed form items. */
|
/* Take out all badly placed form items. */
|
||||||
|
|
||||||
foreach (form, document->forms) {
|
foreach (form, document->forms) {
|
||||||
@ -1597,8 +1659,8 @@ check_html_form_hierarchy(struct part *part)
|
|||||||
foreachsafe (fc, next, form_controls) {
|
foreachsafe (fc, next, form_controls) {
|
||||||
|
|
||||||
foreach (form, document->forms) {
|
foreach (form, document->forms) {
|
||||||
if (form->form_num <= fc->position
|
if (fc->position < form->form_num
|
||||||
&& fc->position <= form->form_end)
|
|| form->form_end < fc->position)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
fc->form = form;
|
fc->form = form;
|
||||||
|
Loading…
Reference in New Issue
Block a user