99e615846246a19fdb5d01fcea5dce49179dd2ba braney Tue Sep 22 10:52:28 2026 -0700 htmlPage: parse valueless tag attributes such as SELECTED The attribute name scanner read everything up to the next equals sign, so <OPTION SELECTED value='any'> became a single attribute named "SELECTED value". A lookup for SELECTED then found nothing and the SELECT fell back to its first option. The same happened to CHECKED on a checkbox, and to the src in <script async src=...>. A name now ends at white space as well, with a look-ahead so that spaces around the equals sign still work. This is what put 21 soft errors in every hgNearTest robot run since v495. refs #38413 diff --git src/lib/htmlPage.c src/lib/htmlPage.c index d1f28e491b3..6a8ec4e1414 100644 --- src/lib/htmlPage.c +++ src/lib/htmlPage.c @@ -568,41 +568,54 @@ for (;;) { char *name, *val; boolean gotEnd = FALSE; /* Check for end tag. */ s = skipLeadingSpaces(s); if (s[0] == '>' || s[0] == 0) { tag->end = html + (s - dupe); if (s[0] == '>') tag->end += 1; break; } - /* Get name - everything up to equals. */ + /* Get name - everything up to equals, white space or tag end. + * A name that ends at white space belongs to a valueless + * attribute such as the SELECTED in <OPTION SELECTED value='x'>, + * unless the equals is merely separated from it by spaces. */ e = s; for (;;) { c = *e; if (c == '=') break; else if (c == '>') break; else if (c == 0) break; + else if (isspace(c)) + { + char *afterSpaces = skipLeadingSpaces(e); + if (*afterSpaces == '=') + { + e = afterSpaces; + c = *e; + } + break; + } e += 1; } if (c == 0) { warn("End of file in tag"); break; } name = s; *e++ = 0; eraseTrailingSpaces(name); if (c == '>') { val = ""; gotEnd = TRUE; tag->end = html + (e - dupe);