Uploaded image for project: 'XWiki Platform'
  1. XWiki Platform
  2. XWIKI-19838

Parsing deeply nested syntax causes a StackOverflowError

    XMLWordPrintable

Details

    • Unit
    • High
    • Unknown
    • N/A
    • N/A
    • Pull Request accepted

    Description

      Steps to reproduce:

      1. Create and login with an unprivileged account (no edit or script rights necessary)
      2. Edit the user profile with the wiki editor and change its content to 32768 lines with "(((", a line "Hello" and 32768 lines with ")))". You can create the string in the browser's console using:
      {
        let result = "(((\nHello\n)))";
        for (let i = 0; i < 15; ++i) {
          result = result.replace("Hello", result);
        }
        console.log(result);
      }
      

      and then copy it by right-clicking on the result and copying the object. Save the user profile.

      1. Open the user profile

      Expected result

      The user profile is displayed and all other features of the wiki still work.

      Actual result

      The user profile isn't displayed, instead a notice "A problem occurred while trying to process your request. Please contact the webmaster if this happens again." with a long stack trace is displayed, here truncated, the last two lines are repeated many more times:

      Detailed information:
      
          Error number 0 in 11: Uncaught exception
      com.xpn.xwiki.XWikiException: Error number 0 in 11: Uncaught exception
      	at com.xpn.xwiki.web.XWikiAction.execute(XWikiAction.java:612)
      	at com.xpn.xwiki.web.XWikiAction.execute(XWikiAction.java:289)
      	at com.xpn.xwiki.web.LegacyActionServlet.service(LegacyActionServlet.java:114)
      	at javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
      	at org.eclipse.jetty.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1419)
      	at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:764)
      	at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1624)
      	at com.xpn.xwiki.web.ActionFilter.doFilter(ActionFilter.java:122)
      	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202)
      	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1594)
      	at org.xwiki.wysiwyg.filter.ConversionFilter.doFilter(ConversionFilter.java:61)
      	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202)
      	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1594)
      	at org.xwiki.container.servlet.filters.internal.SetHTTPHeaderFilter.doFilter(SetHTTPHeaderFilter.java:63)
      	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202)
      	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1594)
      	at org.xwiki.container.servlet.filters.internal.SavedRequestRestorerFilter.doFilter(SavedRequestRestorerFilter.java:208)
      	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202)
      	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1594)
      	at org.xwiki.container.servlet.filters.internal.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:111)
      	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202)
      	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1594)
      	at org.xwiki.resource.servlet.RoutingFilter.doFilter(RoutingFilter.java:132)
      	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:210)
      	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1594)
      	at org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:164)
      	at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:202)
      	at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1594)
      	at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:506)
      	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:131)
      	at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:578)
      	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
      	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:223)
      	at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1571)
      	at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:221)
      	at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1378)
      	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:176)
      	at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:463)
      	at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1544)
      	at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:174)
      	at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1300)
      	at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:129)
      	at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:192)
      	at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:51)
      	at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:122)
      	at org.eclipse.jetty.server.Server.handle(Server.java:562)
      	at org.eclipse.jetty.server.HttpChannel.lambda$handle$0(HttpChannel.java:418)
      	at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:675)
      	at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:410)
      	at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:282)
      	at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:319)
      	at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:100)
      	at org.eclipse.jetty.io.SocketChannelEndPoint$1.run(SocketChannelEndPoint.java:101)
      	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:412)
      	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:381)
      	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:268)
      	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.lambda$new$0(AdaptiveExecutionStrategy.java:138)
      	at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:407)
      	at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:894)
      	at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1038)
      	at java.base/java.lang.Thread.run(Thread.java:829)
      Caused by: java.lang.StackOverflowError
      	at org.xwiki.rendering.internal.parser.wikimodel.DefaultXWikiGeneratorListener.beginDocument(DefaultXWikiGeneratorListener.java:419)
      	at org.xwiki.rendering.wikimodel.impl.WikiScannerContext$DefaultSectionListener.beginDocument(WikiScannerContext.java:50)
      	at org.xwiki.rendering.wikimodel.util.SectionBuilder$1.onBeginTree(SectionBuilder.java:114)
      	at org.xwiki.rendering.wikimodel.util.SectionBuilder$1.onBeginTree(SectionBuilder.java:98)
      	at org.xwiki.rendering.wikimodel.util.TreeBuilder.addTail(TreeBuilder.java:76)
      	at org.xwiki.rendering.wikimodel.util.TreeBuilder.doAlign(TreeBuilder.java:111)
      	at org.xwiki.rendering.wikimodel.util.TreeBuilder.align(TreeBuilder.java:153)
      	at org.xwiki.rendering.wikimodel.util.SectionBuilder.align(SectionBuilder.java:148)
      	at org.xwiki.rendering.wikimodel.util.SectionBuilder.beginDocument(SectionBuilder.java:157)
      	at org.xwiki.rendering.wikimodel.impl.InternalWikiScannerContext.beginDocument(InternalWikiScannerContext.java:149)
      	at org.xwiki.rendering.wikimodel.impl.WikiScannerContext.beginDocument(WikiScannerContext.java:129)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.embeddedDocument(XWikiScanner.java:1270)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.docElements(XWikiScanner.java:319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.embeddedDocument(XWikiScanner.java:1319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.docElements(XWikiScanner.java:319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.embeddedDocument(XWikiScanner.java:1319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.docElements(XWikiScanner.java:319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.embeddedDocument(XWikiScanner.java:1319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.docElements(XWikiScanner.java:319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.embeddedDocument(XWikiScanner.java:1319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.docElements(XWikiScanner.java:319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.embeddedDocument(XWikiScanner.java:1319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.docElements(XWikiScanner.java:319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.embeddedDocument(XWikiScanner.java:1319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.docElements(XWikiScanner.java:319)
      	at org.xwiki.rendering.wikimodel.internal.xwiki.xwiki21.javacc.XWikiScanner.embeddedDocument(XWikiScanner.java:1319)
      

      Also, all other places that would display the user's name are broken, this includes the user index and the page index if the user would be included in the list. Note that on the page with the syntax the normal UI is completely missing and it is not possible to open the editor directly to revert the change as the stack overflow is already triggered while getting the title of the document. This means that it is quite difficult to remove this content again, this is probably also an issue in comments.

      The cause of this issue is that the parser is recursive and with this syntax, we're hitting a java.lang.StackOverflowError due to this. The affects version is just the version where I reproduced the problem, this is most likely as old as the use of WikiModel or even older (not sure if there are other places where recursion would also cause a stack overflow).

      I think a fix would be to introduce a nesting limit that is enforced in WikiModel but also somewhere in the XDOM rendering to avoid the stack overflow, or alternatively, to re-write the rendering code to be non-recursive, but this seems much harder. Apart from that, rendering-calls in XWiki platform should be protected such that an exception during rendering doesn't fail the whole UI (e.g., just use an error message as rendered content if rendering fails).

      Attachments

        Issue Links

          Activity

            People

              mleduc Manuel Leduc
              MichaelHamann Michael Hamann
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: