none
.Net 3.5 SP1 changes to xslcompiled transform

    Question

  •  

    We have been using XslCompiledTransform objects to translate xml documents to html for quite awhile (since .net 2.0).  We have started recently to upgrade our systems to have .net 3.5 sp1 on them.  This upgrade has started causing the load of an XSLT to stack overflow.

     

    We tested to make sure it was this by loading the same stylesheet on a system with and without sp1 on it.  It works on the one without, and doesn't on the one with.

     

    What changed?  Is there anything we can do about it?

     

    chad

    Thursday, September 04, 2008 3:04 PM

Answers

  • As pAwel noted we're not aware of anything we changed causing StackOverlows in general. On the other hand we did change pieces of the code, and we might have increased frame size of some functions (adding local variables and such). Also CLR itself might have change some of this. As a result a stylesheer which used to load just below the limits might now fail.

    I wonder, could you maybe send us an "Example" stylesheet - not the original one, but simething "like" that so that we can take a deeper look and hopefully try to avoid this problem in the next release.

     

    Thanks,

    Thursday, September 04, 2008 9:26 PM
    Moderator
  • I was able to reproduce the StackOverflowException using files provided by Russ (Thanks Russ!). First of all - the StackOverflowException is not caused here by a bug where the XsltProcessor enters an infinite recursion loop which is a good thing. I tried loading the stylesheet in an offline scenario (i.e. using a command line application) and the stylesheet works just fine (btw. this is probably the reason why we could not repro this earlier - you need to try loading the stylesheet on a webserver (IIS) to repro the issue easier). Having said that - it does not mean that you will never hit this issue when running a non-web app. It means that it is much harder to hit.

    What is the difference between off-line scenario and on-line scenario?
    By default stack size of a .NET thread is 1 MB, however IIS limits it to 256 KB (see this KB article: http://support.microsoft.com/kb/932909, and this blog entry http://blogs.msdn.com/tom/archive/2008/03/31/stack-sizes-in-iis-affects-asp-net.aspx). So, it is much easier to hit the issue when running a web app than when running a non-web app.

    Why it suddenly starts happening after installing .NET Framework 3.5?
    It appears that there have been some optimization improvements in the Just-In-Time compiler (JITter), trading off better speed for some increase in stack usage.

    Why XslCompiledTransform needed to build such a deep stack?
    The stylesheet provided by Russ contains a lot of templates that match a lot of attributes. Something like this:

    <xsl:template match="@attr1|@attr2|@attr2|{...}|@attr1000">  
    ...  
    </xsl:template> 

    Compiler builds a pretty deep tree to compile a thing like this. If you have a few templates like the above one then for each mode and each type of a node in the match expression of all these templates a COMMON tree is being build.

    What are workarounds?

    There are several work-arounds:

    1) Compile your stylesheet with xsltc and use already compiled transform in your web app. (The additional benefit is that you will not have to compile the stylesheet at runtime which should increase preformance of your application). See here for more details:

    http://blogs.msdn.com/antosha/archive/2007/05/28/xsltc-compile-xslt-to-.net-assembly.aspx
    http://msdn.microsoft.com/en-us/library/bb399405.aspx
    http://msdn.microsoft.com/en-us/library/bb399419.aspx

    2) Rewrite your stylesheet so that you don't have a lot of matches of the same type  
     a) use modes for same templates
     b) try rewriting a template like this (for the above template):

    <xsl:template match="@*">     
       <xsl:if test="local-name()='attr1' or local-name()='attr2' or local-name()='attr2' or {...} or local-name()='@attr1000'">  
          ...  
       </xsl:if> 
    </xsl:template>    
     

    3. Increase the stack size (but be carefull it was limited for a reason). This blog entry shows how to do it:
    http://blogs.msdn.com/tom/archive/2008/03/31/stack-sizes-in-iis-affects-asp-net.aspx

    Pawel

    Monday, February 16, 2009 8:52 PM
    Moderator
  • Russ, in your case I replaced this code:

      <!--format text - strip whitespace - fixes informix trailing spaces--> 
      <xsl:template match="@tkfirst|@tkfirstb|@tkfirsts|@tkfirsto|@tklast|@tklastb|@tklasts|@tklasto|@cmtmask|@cclmask|@ctkmask|@codesc|@codesc1|@nbdesc|@uaccgroup|@dindex|@iindex|@findex|@sindex|@fmatter|@smatter|@fsubnumber|@subnumber|@fdesc1|@wtrqop|@wtdecode|@wtprior|@seqindex|@item|@tfindex|@ftmkpr|@flocation|@iname|@dname|@idesc1|@idesc2|ddesc1|@subdesc1|@subdesc2|@desc1|@wtindex|wttype|@wtparent|@wtfindex|@number|@period|@dinout|@iinout|@chparent|@subprac|@fstatuas|@fbox|@foffnum|@fbarcode|@ldesc|@lcdesc|@lccode|@fdesc|@fdesc|@flang|@mmatter|@evmatter|@mclient|@ivalue|@thtk|@mttk|@mtmatter|@clnum|@clcity|@clcountry|@pccount|@phop|@phstatus|@evclient|@evchar2| @pccode|@pcmatter|@pcphone|@tktydesc|@mdesc1|@mdesc2|@mdesc3|@mcurrency|@tktitle|@head1|@tsectdes|@pevalue|@minstr1|@minstr2|@maddr1|@maddr2|@maddr3|@maddr4|@maddr5|@maddr6|@claddr1|@claddr2|@claddr3|@claddr4|@claddr5|@claddr6|@bdesc|@ptdesc|@prname|@tklocation|@tratype|@tradesc|@tracct|@mjnum|@evdesc1|@ptnum|@btemp|@pcdcity|@pcrcity|@pcsupplier|@pcloc|@pcguest|@mdesc|@clname|@mtktype|@mbillaty|@msupaty|@morgaty|@head|@pdesc|@mstatus|@clind|@pccurrt|@clsort|@pageno|@codesc|@ldocumnt|@llcode|@linvoice|@pcgnum|@pcgfile|@l|matternum|clientnum|@tmatter|@tcode|@tledger|@acode|excluded|@cmtmask|@tindex|cmsg|@pcgcurr|@mname|@cudef1|@cudef2|@cudef3|@cudef4|@cudef5|@cocode|tkinit|UserDef1|UserDef2|UserDef3|UserDef4|UserDef5|@tudef1|@tudef2|@tudef3|@tudef4|@tudef5|@tstatus|timecard_tstatus|@bnumber">  
        <xsl:value-of select="wv:wv_Trim(.)"/>  
      </xsl:template> 
     

    with this code:

      <!--format text - strip whitespace - fixes informix trailing spaces--> 
       <xsl:template match="@*">  
         <xsl:if test="local-name() = 'mdesc1' or local-name() = 'mdesc2' or local-name() = 'mdesc3' or local-name() = 'mcurrency' or local-name() = 'tktitle' or local-name() = 'head1' or local-name() = 'tsectdes' or local-name() = 'pevalue' or local-name() = 'minstr1' or local-name() = 'minstr2' or local-name() = 'maddr1' or local-name() = 'maddr2' or local-name() = 'maddr3' or local-name() = 'maddr4' or local-name() = 'maddr5' or local-name() = 'maddr6' or local-name() = 'claddr1' or local-name() = 'claddr2' or local-name() = 'claddr3' or local-name() = 'claddr4' or local-name() = 'claddr5' or local-name() = 'claddr6' or local-name() = 'bdesc' or local-name() = 'ptdesc' or local-name() = 'prname' or local-name() = 'tklocation' or local-name() = 'tratype' or local-name() = 'tradesc' or local-name() = 'tracct' or local-name() = 'mjnum' or local-name() = 'evdesc1' or local-name() = 'ptnum' or local-name() = 'btemp' or local-name() = 'pcdcity' or local-name() = 'pcrcity' or local-name() = 'pcsupplier' or local-name() = 'pcloc' or local-name() = 'pcguest' or local-name() = 'mdesc' or local-name() = 'clname' or local-name() = 'mtktype' or local-name() = 'mbillaty' or local-name() = 'msupaty' or local-name() = 'morgaty' or local-name() = 'head' or local-name() = 'pdesc' or local-name() = 'mstatus' or local-name() = 'clind' or local-name() = 'pccurrt' or local-name() = 'clsort' or local-name() = 'pageno' or local-name() = 'codesc' or local-name() = 'ldocumnt' or local-name() = 'llcode' or local-name() = 'linvoice' or local-name() = 'pcgnum' or local-name() = 'pcgfile' or local-name() = 'l' or local-name() = 'tmatter' or local-name() = 'tcode' or local-name() = 'tledger' or local-name() = 'acode' or local-name() = 'cmtmask' or local-name() = 'tindex' or local-name() = 'pcgcurr' or local-name() = 'mname' or local-name() = 'cudef1' or local-name() = 'cudef2' or local-name() = 'cudef3' or local-name() = 'cudef4' or local-name() = 'cudef5' or local-name() = 'cocode' or local-name() = 'tudef1' or local-name() = 'tudef2' or local-name() = 'tudef3' or local-name() = 'tudef4' or local-name() = 'tudef5' or local-name() = 'tstatus' or local-name() = 'bnumber'">  
           <xsl:value-of select="wv:wv_Trim(.)"/>    
         </xsl:if>      
      </xsl:template> 
     
      <xsl:template match="matternum|clientnum|cmsg|tkinit|UserDef1|UserDef2|UserDef3|UserDef4|UserDef5|timecard_tstatus|excluded">  
        <xsl:value-of select="wv:wv_Trim(.)"/>  
      </xsl:template> 
     
     

    to make it work.

    This change decreases the number of attributes in the defualt mode to be matched and as a result decreases stack size required to compile the stylesheet. When processor is trying to find a match the template I created will have the lowest priority (unless you set a priority manually) so it will not harm other matches. I created another template for elements.

    You may also want to take a look at the other options I enumerated in my previous post - using xsltc is especially interesting...

    Thanks
    Pawel
    Monday, February 16, 2009 8:59 PM
    Moderator

All replies

  • Hello Chad,

     

    Can you post stack trace? Also is the stylesheet causing the problem in any way special (e.g. very big or deeply nested or including/importing many other stylesheets)? Have you tried to identify the part of the stylesheet which is causing the problem and to create a simplified repro?

     

    Thanks

    Pawel

    Thursday, September 04, 2008 4:26 PM
    Moderator
  • I can't post the stylesheet (it has proprietary data, lawyers...)  However, I know it is because the stylesheet is big.  I was just wondering if there were known changes in SP1 that would change the compiling stack to cause a stackoverflow.  We have been trying to shrink the template matches, but no luck yet.

     

    We have already made workarounds to our Load() call when we are running in x64.  For some reason, the stack is either a lot smaller in x64, or (because the addresses are 64-bit) each call takes up more space, and it is not compensated for.  We have 100s of stylesheets that were causing a stack overflow in x64.

     

    The workaround is the load these on a seperate thread where we have given a custom stack size.  I don't like this as the question is "How big a stack do we ask for?"  If it is too big, we may have memory issues, too small, stack overflow.

     

    If anyone knows if there were changes to SP1 that make the call stack deeper, this would help.

     

    chad

    Thursday, September 04, 2008 4:47 PM
  • I am not aware of any changes in SP1 that could cause Stack Overflow but if you send the stack trace from your stack overflow exception it may give some hints.

     

    Thanks

    Pawel

    Thursday, September 04, 2008 4:52 PM
    Moderator
  • As pAwel noted we're not aware of anything we changed causing StackOverlows in general. On the other hand we did change pieces of the code, and we might have increased frame size of some functions (adding local variables and such). Also CLR itself might have change some of this. As a result a stylesheer which used to load just below the limits might now fail.

    I wonder, could you maybe send us an "Example" stylesheet - not the original one, but simething "like" that so that we can take a deeper look and hopefully try to avoid this problem in the next release.

     

    Thanks,

    Thursday, September 04, 2008 9:26 PM
    Moderator
  • Any updates on this problem?

     

    We have the exact same situation. Same error and only with Windows Server 2003 and .Net framework 3.5 SP1.

    Another major problem (as I see it), is that it doesn't help if you uninstall the service pack. The error remains. So

    the uninstall program must miss a file or an update of an file.

     

    Below is the stacktrace when the error occurrs:

    at System.Xml.Xsl.Xslt.XsltLoader.LoadStylesheet(XmlReader reader, Boolean include)
       at System.Xml.Xsl.Xslt.XsltLoader.Load(Compiler compiler, Object stylesheet, XmlResolver xmlResolver)
       at System.Xml.Xsl.Xslt.Compiler.Compile(Object stylesheet, XmlResolver xmlResolver, QilExpression& qil)
       at System.Xml.Xsl.XslCompiledTransform.CompileXsltToQil(Object stylesheet, XsltSettings settings, XmlResolver stylesheetResolver)
       at System.Xml.Xsl.XslCompiledTransform.LoadInternal(Object stylesheet, XsltSettings settings, XmlResolver stylesheetResolver)
       at System.Xml.Xsl.XslCompiledTransform.Load(XmlReader stylesheet, XsltSettings settings, XmlResolver stylesheetResolver)
       at MyClass.XSLTransformBackgroundThread(Object o)
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart(Object obj)

     

    I've tried to put the execution in a separate thread and to raise the stack size. But that didn't help either.

     

    Monday, December 01, 2008 11:45 AM
  • Hi,

     

    Could you please try to attach a debugger to the failing process and set it to catch exceptions when they are thrown?

    The LoadStylesheet method is catching and rethrowing exceptions (Wrapping them) so the callstack like above doesn't have much information in it.

    Or if you could post a dump of the exception (or at least the callstacks of all the exceptions) as you can see it in the debugger, that should have the original failing callstack in it as well.

     

    Thanks,

    Monday, December 01, 2008 2:11 PM
    Moderator
  • I have reached a couple of conclusions during my testings the last couple of hours, and mainly it seems to be a problem with IIS in some way.

     

    The xsltcompiledtransform is invoked from a asp page on a iis6 server. The xslt is in a sql 2005 database and we have a custom resolver for any includes. Which works fine.

     

    But, when I go to the page in IE (to the page in IIS) it seems like it first connects to the database as the user logged in to the computer (we have integrated security and impersonate = true, and this is the behaviour we want). But then a couple of seconds later it tries to logon using the AppPool user (in this case Network Service).

     

    This behaviour did not occurr before the .net 3.5 sp1 was applied. So for some reason, it looks like the iis session is lost and then a new one is created with the app pool user.

     

    If I add the network service account as db_owner to the database, everything works as it did before.

    (The inner exception was Login failed for user 'NT AUTHORITY\NETWORK SERVICE')

     

    Any ideas on what this might be? There is no external links, images or references in the xslt-files.

    Monday, December 01, 2008 2:50 PM
  • I have an XSLT that causes stack overflow when loading on a x64 machine (with .net 3.5 SP). The problem is the size. If the xslt is reduced in size by removing arbitrary sections, it will load.

    The other problem is that it is too large (38K but more than 60000 chroma-coded) to submit on this forum. Error "There was an error processing the request."
    Thursday, January 08, 2009 11:46 PM
  • I'm having the same problem.  When Visual Studio breaks at the exception  all you get is 'Stack Overflow', there's no inner exception as it seems it has been caught internally and rethrown.

    I attached the MS debugging diagnostic tool to wp3 and noticed this in the dump that resulted, hope it helps, let me know if there's any else i can supply - will try to get you a sample xsl that dies too(had to truncate the dump as ms site wouldn't let me post more than 60000 characters, there are 1922 lines in total, but you get the picture), cheers Russ;

    Thread 20 - System ID 7312
    Entry point   mscorwks!ThreadpoolMgr::intermediateThreadProc
    Create time   5/02/2009 2:58:39 p.m.
    Time spent in user mode   0 Days 00:00:07.203
    Time spent in kernel mode   0 Days 00:00:00.265

    This thread is not fully resolved and may or may not be a problem. Further analysis of these threads may be required.

    Function   Source
    kernel32!TerminateProcess   
    mscorwks!EEPolicy::HandleFatalStackOverflow+f2   
    mscorwks!EEPolicy::HandleStackOverflow+173   
    mscorwks!COMPlusFrameHandler+10b   
    ntdll!ExecuteHandler2+26   
    ntdll!ExecuteHandler+24   
    ntdll!KiUserExceptionDispatcher+e   
    kernel32!RaiseException+53   
    mscorwks!ReportStackOverflow+61   
    mscorwks!Alloc+3b   
    mscorwks!FastAllocateObject+38   
    mscorwks!JIT_NewFast+9e   
    0x0f553741   
    0x0f555d8b   
    0x0f5534e9   
    0x114ca3aa   
    0x114ca015   
    0x11f3e145   
    0x11f98d00   
    0x11f989cd   
    0x11f98943   
    0x11f91d2a   
    0x11f948d1   
    0x11f9449b   
    0x11ec67e3   
    0x11f91d2a   
    0x11f91419   
    0x11f91c8d   
    0x11f986cf   
    0x11f94679   
    0x11ec67e3   
    0x11f91d2a   
    0x11f91419   
    0x11f91c8d   
    0x11f986cf   
    0x11f94679   
    0x11ec67e3   
    0x11f91d2a   
    0x11f91419   
    0x11f91c8d   
    0x11f986cf   
    0x11f94679   
    0x11ec67e3   
    0x11f91d2a   
    0x11f91419   
    0x11f91c8d
    mscorwks!SVR::gc_heap::balance_heaps+67   
    0x11f91d2a   
    mscorwks!SVR::gc_heap::balance_heaps+67   
    0x11f91c8d   
    mscorwks!SVR::gc_heap::balance_heaps+67  

    ---[Russ]  -- more lines

    mscorwks!JIT_NewArr1+186   
    0x11f91d2a   
    mscorwks!JIT_NewArr1+186   
    0x11f91c8d   
    mscorwks!JIT_NewArr1+186   

    ---[Russ]  -- more lines


    mscorwks!SVR::gc_heap::balance_heaps+67   
    0x11f91d2a   
    mscorwks!SVR::gc_heap::balance_heaps+67   
    0x11f91c8d   
    mscorwks!SVR::gc_heap::balance_heaps+67

    ---[Russ]  -- more lines

     
    mscorwks!SVR::gc_heap::balance_heaps+67   
    0x11f91d2a   
    mscorwks!SVR::gc_heap::balance_heaps+67   
    0x11f91c8d   
    mscorwks!SVR::gc_heap::balance_heaps+67

    ---[Russ]  -- more lines


    mscorwks!SVR::gc_heap::balance_heaps+67   
    0x11f91d2a   
    mscorwks!SVR::gc_heap::balance_heaps+67   
    0x11f91c8d   
    mscorwks!SVR::gc_heap::balance_heaps+67 

    ---[Russ]  -- more lines


    0x11f986cf   
    0x11f94679   
    mscorwks!JIT_MonExitWorker+b   
    0x02ad017c   
    Thursday, February 05, 2009 2:19 AM
  • Do you have a consistent repro (e.g. a stylesheet that is causing this problem)? If so - are you able to post the stylesheet so that we could investigate the issue?
    If not, can you somehow put the dump file online so that we could download it and do the further investigation?

    Thanks
    Pawel
    Thursday, February 05, 2009 2:42 AM
    Moderator
  • ok, 3 files in www.redmoki.com/XSL/

    transform.xsl
    xslTransformError.aspx.vb.txt
    xslTransformError.aspx.txt

    Remove the .txt extensions, put them in a virdir
    Navigate to xslTransformError.aspx
    in the text box enter the full path the transform.xsl e.g. C:/inetpub/wwwroot/virdir/transform.xsl
    Click the button and see if it blows up

    I have a feeling its something to do with large number of template matches, there's a template at the end of the xsl that matches about 40 different attributes
    eg
    <xsl:template match="@hrwkdw
    |@unb_hours
    |@sumbillhrs
    |@sumtbillhrs
    |@sumtbilldol
    |@sumbilldol
    |@sumwkhrs
    |@sumwkdol
    |@dowkdw
    etc
    etc

    Let me know when you're done so I can remove the files from the net
    Thanks
    Russ
    Thursday, February 05, 2009 7:33 AM
  • btw I have my virdir set to use asp.net 2.50727

    It stopped working today after installing .Net 3.5 sp1

    Thursday, February 05, 2009 7:45 AM
  • Hi Russ,

    I downloaded the files. The issue does not repro when running as a desktop/console application. However when I put it on a web server (II7 on a Win7, 64-bit machine with .NET Framework 3.5 installed) the web server crashed indeed.
    Your feeling seems to be right. If I comment out this template:

    <!-- format text - strip whitespace - fixes informix trailing spaces -->   
    <xsl:template match="@tkfirst|@tkfirstb|@tkfirsts|@tkfirsto|@tklast|@tklastb|@tklasts|@tklasto|@cmtmask|@cclmask|@ctkmask|@codesc|@codesc1|@nbdesc|@uaccgroup|@dindex|@iindex|@findex|@sindex|@fmatter  
    ... 

    the web server does not crash anymore. I have not had a chance to take a look what caused the crash (it does not plainly say StackOverFlow but I see "Application Error" in event viewer and I never receive any result). I was not able to try it on a machine with only .NET Framework 2.0 installed yet.

    I will keep you updated.

    Thanks
    Pawel
    Thursday, February 05, 2009 9:02 PM
    Moderator
  • Hi Pawel,
    Any update on this one?
    Thanks
    Russ
    Monday, February 09, 2009 9:40 PM
  • I have not had a chance to take a deeper look yet but I am planning to do that this week.

    Thanks
    Pawel
    Tuesday, February 10, 2009 12:35 AM
    Moderator
  • Just to let you know - I found why the exception started to be thrown after upgrading to 3.5. Now I am looking for a good workaround. Hopefully I will manage to post more details and the solution over the weekend or at the begining of the next week.

    Thanks
    Pawel
    Saturday, February 14, 2009 12:46 AM
    Moderator
  • Great, thanks Pawel, look forward to the fix :)
    Monday, February 16, 2009 8:41 PM
  • I was able to reproduce the StackOverflowException using files provided by Russ (Thanks Russ!). First of all - the StackOverflowException is not caused here by a bug where the XsltProcessor enters an infinite recursion loop which is a good thing. I tried loading the stylesheet in an offline scenario (i.e. using a command line application) and the stylesheet works just fine (btw. this is probably the reason why we could not repro this earlier - you need to try loading the stylesheet on a webserver (IIS) to repro the issue easier). Having said that - it does not mean that you will never hit this issue when running a non-web app. It means that it is much harder to hit.

    What is the difference between off-line scenario and on-line scenario?
    By default stack size of a .NET thread is 1 MB, however IIS limits it to 256 KB (see this KB article: http://support.microsoft.com/kb/932909, and this blog entry http://blogs.msdn.com/tom/archive/2008/03/31/stack-sizes-in-iis-affects-asp-net.aspx). So, it is much easier to hit the issue when running a web app than when running a non-web app.

    Why it suddenly starts happening after installing .NET Framework 3.5?
    It appears that there have been some optimization improvements in the Just-In-Time compiler (JITter), trading off better speed for some increase in stack usage.

    Why XslCompiledTransform needed to build such a deep stack?
    The stylesheet provided by Russ contains a lot of templates that match a lot of attributes. Something like this:

    <xsl:template match="@attr1|@attr2|@attr2|{...}|@attr1000">  
    ...  
    </xsl:template> 

    Compiler builds a pretty deep tree to compile a thing like this. If you have a few templates like the above one then for each mode and each type of a node in the match expression of all these templates a COMMON tree is being build.

    What are workarounds?

    There are several work-arounds:

    1) Compile your stylesheet with xsltc and use already compiled transform in your web app. (The additional benefit is that you will not have to compile the stylesheet at runtime which should increase preformance of your application). See here for more details:

    http://blogs.msdn.com/antosha/archive/2007/05/28/xsltc-compile-xslt-to-.net-assembly.aspx
    http://msdn.microsoft.com/en-us/library/bb399405.aspx
    http://msdn.microsoft.com/en-us/library/bb399419.aspx

    2) Rewrite your stylesheet so that you don't have a lot of matches of the same type  
     a) use modes for same templates
     b) try rewriting a template like this (for the above template):

    <xsl:template match="@*">     
       <xsl:if test="local-name()='attr1' or local-name()='attr2' or local-name()='attr2' or {...} or local-name()='@attr1000'">  
          ...  
       </xsl:if> 
    </xsl:template>    
     

    3. Increase the stack size (but be carefull it was limited for a reason). This blog entry shows how to do it:
    http://blogs.msdn.com/tom/archive/2008/03/31/stack-sizes-in-iis-affects-asp-net.aspx

    Pawel

    Monday, February 16, 2009 8:52 PM
    Moderator
  • Russ, in your case I replaced this code:

      <!--format text - strip whitespace - fixes informix trailing spaces--> 
      <xsl:template match="@tkfirst|@tkfirstb|@tkfirsts|@tkfirsto|@tklast|@tklastb|@tklasts|@tklasto|@cmtmask|@cclmask|@ctkmask|@codesc|@codesc1|@nbdesc|@uaccgroup|@dindex|@iindex|@findex|@sindex|@fmatter|@smatter|@fsubnumber|@subnumber|@fdesc1|@wtrqop|@wtdecode|@wtprior|@seqindex|@item|@tfindex|@ftmkpr|@flocation|@iname|@dname|@idesc1|@idesc2|ddesc1|@subdesc1|@subdesc2|@desc1|@wtindex|wttype|@wtparent|@wtfindex|@number|@period|@dinout|@iinout|@chparent|@subprac|@fstatuas|@fbox|@foffnum|@fbarcode|@ldesc|@lcdesc|@lccode|@fdesc|@fdesc|@flang|@mmatter|@evmatter|@mclient|@ivalue|@thtk|@mttk|@mtmatter|@clnum|@clcity|@clcountry|@pccount|@phop|@phstatus|@evclient|@evchar2| @pccode|@pcmatter|@pcphone|@tktydesc|@mdesc1|@mdesc2|@mdesc3|@mcurrency|@tktitle|@head1|@tsectdes|@pevalue|@minstr1|@minstr2|@maddr1|@maddr2|@maddr3|@maddr4|@maddr5|@maddr6|@claddr1|@claddr2|@claddr3|@claddr4|@claddr5|@claddr6|@bdesc|@ptdesc|@prname|@tklocation|@tratype|@tradesc|@tracct|@mjnum|@evdesc1|@ptnum|@btemp|@pcdcity|@pcrcity|@pcsupplier|@pcloc|@pcguest|@mdesc|@clname|@mtktype|@mbillaty|@msupaty|@morgaty|@head|@pdesc|@mstatus|@clind|@pccurrt|@clsort|@pageno|@codesc|@ldocumnt|@llcode|@linvoice|@pcgnum|@pcgfile|@l|matternum|clientnum|@tmatter|@tcode|@tledger|@acode|excluded|@cmtmask|@tindex|cmsg|@pcgcurr|@mname|@cudef1|@cudef2|@cudef3|@cudef4|@cudef5|@cocode|tkinit|UserDef1|UserDef2|UserDef3|UserDef4|UserDef5|@tudef1|@tudef2|@tudef3|@tudef4|@tudef5|@tstatus|timecard_tstatus|@bnumber">  
        <xsl:value-of select="wv:wv_Trim(.)"/>  
      </xsl:template> 
     

    with this code:

      <!--format text - strip whitespace - fixes informix trailing spaces--> 
       <xsl:template match="@*">  
         <xsl:if test="local-name() = 'mdesc1' or local-name() = 'mdesc2' or local-name() = 'mdesc3' or local-name() = 'mcurrency' or local-name() = 'tktitle' or local-name() = 'head1' or local-name() = 'tsectdes' or local-name() = 'pevalue' or local-name() = 'minstr1' or local-name() = 'minstr2' or local-name() = 'maddr1' or local-name() = 'maddr2' or local-name() = 'maddr3' or local-name() = 'maddr4' or local-name() = 'maddr5' or local-name() = 'maddr6' or local-name() = 'claddr1' or local-name() = 'claddr2' or local-name() = 'claddr3' or local-name() = 'claddr4' or local-name() = 'claddr5' or local-name() = 'claddr6' or local-name() = 'bdesc' or local-name() = 'ptdesc' or local-name() = 'prname' or local-name() = 'tklocation' or local-name() = 'tratype' or local-name() = 'tradesc' or local-name() = 'tracct' or local-name() = 'mjnum' or local-name() = 'evdesc1' or local-name() = 'ptnum' or local-name() = 'btemp' or local-name() = 'pcdcity' or local-name() = 'pcrcity' or local-name() = 'pcsupplier' or local-name() = 'pcloc' or local-name() = 'pcguest' or local-name() = 'mdesc' or local-name() = 'clname' or local-name() = 'mtktype' or local-name() = 'mbillaty' or local-name() = 'msupaty' or local-name() = 'morgaty' or local-name() = 'head' or local-name() = 'pdesc' or local-name() = 'mstatus' or local-name() = 'clind' or local-name() = 'pccurrt' or local-name() = 'clsort' or local-name() = 'pageno' or local-name() = 'codesc' or local-name() = 'ldocumnt' or local-name() = 'llcode' or local-name() = 'linvoice' or local-name() = 'pcgnum' or local-name() = 'pcgfile' or local-name() = 'l' or local-name() = 'tmatter' or local-name() = 'tcode' or local-name() = 'tledger' or local-name() = 'acode' or local-name() = 'cmtmask' or local-name() = 'tindex' or local-name() = 'pcgcurr' or local-name() = 'mname' or local-name() = 'cudef1' or local-name() = 'cudef2' or local-name() = 'cudef3' or local-name() = 'cudef4' or local-name() = 'cudef5' or local-name() = 'cocode' or local-name() = 'tudef1' or local-name() = 'tudef2' or local-name() = 'tudef3' or local-name() = 'tudef4' or local-name() = 'tudef5' or local-name() = 'tstatus' or local-name() = 'bnumber'">  
           <xsl:value-of select="wv:wv_Trim(.)"/>    
         </xsl:if>      
      </xsl:template> 
     
      <xsl:template match="matternum|clientnum|cmsg|tkinit|UserDef1|UserDef2|UserDef3|UserDef4|UserDef5|timecard_tstatus|excluded">  
        <xsl:value-of select="wv:wv_Trim(.)"/>  
      </xsl:template> 
     
     

    to make it work.

    This change decreases the number of attributes in the defualt mode to be matched and as a result decreases stack size required to compile the stylesheet. When processor is trying to find a match the template I created will have the lowest priority (unless you set a priority manually) so it will not harm other matches. I created another template for elements.

    You may also want to take a look at the other options I enumerated in my previous post - using xsltc is especially interesting...

    Thanks
    Pawel
    Monday, February 16, 2009 8:59 PM
    Moderator
  • Sweet, thanks Pawel, pretty comprehensive answer :-)

    Monday, February 16, 2009 10:51 PM
  • Hi Pawel

    I came across this post because I have a very similar story - I manage a web app that is deployed to about 100 different intranet sites that performs some XSL transforms, and it has suddenly started to hang at certain points on a few installations - we traced it down to a large xlst, and now are unsure what to do.  The easiest approach might be to up the IIS stack size, but reading the article describing this makes it clear that this is a short term solution that could easily be overwritten by Windows File Protection or any MS update.

    since the xslt files are often customised by our customers I don't see the xsltc route as being an option.

    This leaves a rewrite as our only option.  Our xslt is relatively small - roughly 370 lines, of which the majority is simple xslt, the only exception being a 300 line choose block partially reproduced below:
    <xsl:choose>
    <xsl:when test='number($inValue) != number($inValue)'></xsl:when>
    <xsl:when test='number($inValue) &gt;= 4.426'>1.00544</xsl:when>
    <xsl:when test='number($inValue) &gt;= 4.368'>0.99754</xsl:when>
    ....
    roughly 295 lines snipped here!
    ....
    <xsl:when test='number($inValue) &gt;= -0.3786'>0.31479</xsl:when>
    <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>

    is there an obvious way to optimise this to avoid the stackoverflowexception?

    We are a Gold Certified Partner - is it likely to be any use raising this as one of our support incidents, or will we just be told what has already been discussed here?
    Monday, June 29, 2009 3:35 PM
  • The big xsl:choose smells like a potentiall stack overflow cause. Fortunately in your case it is pretty simple to remove the xsl:choose construct. You just need to put all the data (range boundaries) in a variable and then use it as if it was an array. I prepared small example to show how to do that. Take a look at the stylesheet below (you can try it out on any valid xml document).

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
      
       <xsl:template match="/">
        inValue NaN (no output expected): 
        <xsl:call-template name="example" />
        inValue less than min: 
        <xsl:call-template name="example">
          <xsl:with-param name="inValue" select="-9" />
        </xsl:call-template>
        inValue greater than max:
        <xsl:call-template name="example">
          <xsl:with-param name="inValue" select="100" />
        </xsl:call-template>
        inValue in range:
        <xsl:call-template name="example">
          <xsl:with-param name="inValue" select="2.490" />
        </xsl:call-template>
      </xsl:template>
    
      <xsl:template name="example">
        <xsl:param name="inValue" />
        <xsl:variable name="values">
          <value from="5">10</value>
          <value from="3" to="5">4.5</value>
          <value from="2" to="3">3.68</value>
          <value from="1.5" to="2">2.70</value>
          <value from="-1" to="1.5">1.15</value>
          <value from="-3" to="-1">0.7</value>
          <value from="-7" to="-3">0.1</value>
          <value to="-7">0.1</value>
        </xsl:variable>
    
        <xsl:if test="number($inValue) = $inValue">
          <xsl:value-of select="msxsl:node-set($values)/value[
                        ($inValue &gt;= @from and $inValue &lt; @to) or 
                        ($inValue &gt;= @from and not(@to)) or 
                        ($inValue &lt; @to and not(@from))]"/>
        </xsl:if>
      </xsl:template>
      
    </xsl:stylesheet>
    

    You just need to custmize the above stylesheet by putting your range boundaries and corresponding values in the xml fragment for $values variable.

    Try it out and check if the issue you are seeing is gone (hopefully it will be). If it is not then contacting support is not a bad idea. Alternatively you may try sending more details to the forum.

    Hope this helps.
    Pawel

    Monday, June 29, 2009 4:18 PM
    Moderator
  • this problem is going come in all version of .Net framework later than .Net 2.0 + SP1.
    inclusing .Net 2.0+sp2, .Net 3.5, .Net 3.5+ sp1
    not sure about .Net 4.0.
    Friday, November 27, 2009 12:03 PM
  • As for .NET 4.0: we didn't make any substential changes to the XSLT processor. Given some changes in the XSLT as well as some changes in the JIT/CLR did happen I would expect the behavior to be a bit different but nothing significant. We definitely didn't try to "fix" this issue.
    Although there are certain cases where the XSLT compiler could generate better code for sure, there are still other places where it has no choice (other than complete redesign/rewrite). One must remember that XSLT is basically just another programming language with its own compiler into IL. So you can cause all the same problems as with other languages. You can cause stack overflows in C# for sure, same as in XSLT. Given the nature of XSLT and its heavy use of recursuin it's more likely to hit this though.

    Thanks,


    Vitek Karas [MSFT]
    Friday, November 27, 2009 1:46 PM
    Moderator