Skip to content

Commit

Permalink
Fix a potential stack overflow in InTable
Browse files Browse the repository at this point in the history
Fixes #1577

When in InTable state, make sure resetInsertionMode actually broke out of InTable before trying to reprocess the token. Otherwise, insert directly
  • Loading branch information
jhy committed Jul 12, 2021
1 parent 32d9878 commit 6b04287
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 13 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Expand Up @@ -17,6 +17,9 @@ jsoup changelog
* Bugfiz [Fuzz]: malformed HTML could result in null elements on stack
<https://github.com/jhy/jsoup/issues/1579>

* Bugfix [Fuzz]: malformed deeply nested table elements could create a stack overflow.
<https://github.com/jhy/jsoup/issues/1577>

*** Release 1.14.1 [2021-Jul-10]
* Change: updated the minimum supported Java version from Java 7 to Java 8.

Expand Down
4 changes: 4 additions & 0 deletions pom.xml
Expand Up @@ -166,6 +166,10 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<!-- smaller stack to find stack overflows -->
<argLine>-Xss256k</argLine>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
Expand Down
32 changes: 19 additions & 13 deletions src/main/java/org/jsoup/parser/HtmlTreeBuilderState.java
Expand Up @@ -903,7 +903,7 @@ boolean process(Token t, HtmlTreeBuilder tb) {
},
InTable {
boolean process(Token t, HtmlTreeBuilder tb) {
if (t.isCharacter()) {
if (t.isCharacter() && inSorted(tb.currentElement().normalName(), InTableFoster)) {
tb.newPendingTableCharacters();
tb.markInsertionMode();
tb.transition(InTableText);
Expand All @@ -927,20 +927,31 @@ boolean process(Token t, HtmlTreeBuilder tb) {
tb.insert(startTag);
tb.transition(InColumnGroup);
} else if (name.equals("col")) {
tb.clearStackToTableContext();
tb.processStartTag("colgroup");
return tb.process(t);
} else if (inSorted(name, InTableToBody)) {
tb.clearStackToTableContext();
tb.insert(startTag);
tb.transition(InTableBody);
} else if (inSorted(name, InTableAddBody)) {
tb.clearStackToTableContext();
tb.processStartTag("tbody");
return tb.process(t);
} else if (name.equals("table")) {
tb.error(this);
boolean processed = tb.processEndTag("table");
if (processed) // only ignored if in fragment
if (!tb.inTableScope(name)) { // ignore it
return false;
} else {
tb.popStackToClose(name);
tb.resetInsertionMode();
if (tb.state() == InTable) {
// not per spec - but haven't transitioned out of table. so try something else
tb.insert(startTag);
return true;
}
return tb.process(t);
}
} else if (inSorted(name, InTableToHead)) {
return tb.process(t, InHead);
} else if (name.equals("input")) {
Expand Down Expand Up @@ -970,8 +981,8 @@ boolean process(Token t, HtmlTreeBuilder tb) {
return false;
} else {
tb.popStackToClose("table");
tb.resetInsertionMode();
}
tb.resetInsertionMode();
} else if (inSorted(name, InTableEndErr)) {
tb.error(this);
return false;
Expand All @@ -989,15 +1000,10 @@ boolean process(Token t, HtmlTreeBuilder tb) {

boolean anythingElse(Token t, HtmlTreeBuilder tb) {
tb.error(this);
boolean processed;
if (inSorted(tb.currentElement().normalName(), InTableFoster)) {
tb.setFosterInserts(true);
processed = tb.process(t, InBody);
tb.setFosterInserts(false);
} else {
processed = tb.process(t, InBody);
}
return processed;
tb.setFosterInserts(true);
tb.process(t, InBody);
tb.setFosterInserts(false);
return true;
}
},
InTableText {
Expand Down

0 comments on commit 6b04287

Please sign in to comment.