How to fix StackOverFlowException in .NET
Asked Answered
S

3

0

ASP .NET 4.6 MVC controller creates Razor Template at runtime and runs it using RazorEngine.
One big template causes Stack Overflow exception when running from Visual Studio or Method CompiledRazorTemplates.Dynamic.dbcfcaeeb:Execute () is too complex. when runing from Mono.

If large number of divs are removed from template, it compiles and runs OK.

How to fix this ? How to increase net stack size or any other idea ?

Razor template which causes this has 2880 lines. It contains 228 variables and lot of divs:

@inherits Reporting.ReportTemplateBase<MYApp.ViewModels.RazorViewModel>

<!DOCTYPE html>
<html>
....
<body>
    @{
    dynamic Vrapopref=ko.Keel;
dynamic Vymardada=Iif(Ko.Ymardus==1,2,Iif(Ko.Ymardus==2,0,1));
dynamic Vjag=Iif(Ko.Ymardus!=3,1,1000);
dynamic V4gr= true ;
dynamic Vs41gr=0;
dynamic Vs42gr=0;
...
dynamic _calculated229=Round(Vs52gr/Vjag*Iif(Core.Left(r.BilskeemKontoklass,1)=="K",-1,1),Vymardada);
_calculated229=SetDefault(_calculated229);

    }


<div class='row' style='min-height:0.45cm'>
<div class='field' style='@TextBox(0.00,0.66,7.37,0.45);font-family:"Arial";font-weight:bold;'>@{try{WriteLiteral(Out(Eeva.Business.Prpalk.GetSfirmanimi()));} catch (Exception ex) {LogiVormiViga("Out(Eeva.Business.Prpalk.GetSfirmanimi())",ex);} }</div>

</div>
<div class='row' style='min-height:0.03cm'>
<div class='field' style='@TextBox(0.00,1.87,2.39,0.45);font-family:"Arial";font-size:9pt;'>@{try{WriteLiteral(Out(Ise.Regnr));} catch (Exception ex) {LogiVormiViga("Out(Ise.Regnr)",ex);} }</div>

</div>
<div class='row' style='min-height:0.42cm'>
<div class='field' style='left:0.66cm;font-family:"Arial";font-size:9pt;'>@Raw(IR("Reg nr"))</div>

</div>
<div class='row' style='min-height:0.71cm'>
<div class='field' style='@TextBox(0.00,0.66,7.74,0.55);font-family:"Arial";font-size:9pt;'>@{try{WriteLiteral(Out(RTrim(Ise.Tanav)+" "+RTrim(Ise.Piirkond)+" "+RTrim(Ise.Postiindek)));} catch (Exception ex) {LogiVormiViga("Out(RTrim(Ise.Tanav)+\" \"+RTrim(Ise.Piirkond)+\" \"+RTrim(Ise.Postiindek))",ex);} }</div>

</div>
<div class='row' style='min-height:0.71cm'>
<div class='field' style='left:0.66cm;font-family:"Arial";font-size:16pt;font-weight:bold;'>@Raw(IR("TULEMIARUANNE KUUDE KAUPA"))</div>

</div>
<div class='row' style='min-height:0.39cm'>
<div class='field' style='@TextBox(0.00,0.66,4.00,0.42);font-family:"Arial";font-size:9pt;font-weight:bold;'>@{try{WriteLiteral(Out(Format(Ko.Akuupaev,"-",Ko.Lkuupaev, "d")));} catch (Exception ex) {LogiVormiViga("Out(Format(Ko.Akuupaev,\"-\",Ko.Lkuupaev, \"d\"))",ex);} }</div>

...
</body>
</html>

Whole template is in http://wikisend.com/download/177922/stackoverflow.TXT

Results:

.NET:

enter image description here

exception details contains only

{<Internal Error evaluating expression>}

Mono:

System.InvalidProgramException]: Method CompiledRazorTemplates.Dynamic.dbcfcaeeb:Execute () is too complex.
  at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run (RazorEngine.Templating.ExecuteContext context) <0x42194120 + 0x001b9> in <filename unknown>:0 
  at RazorEngine.Templating.TemplateService.Run (ITemplate template, RazorEngine.Templating.DynamicViewBag viewBag) <0x42193d10 + 0x0005b> in <filename unknown>:0 
  at (wrapper remoting-invoke-with-check) RazorEngine.Templating.TemplateService:Run (RazorEngine.Templating.ITemplate,RazorEngine.Templating.DynamicViewBag)
  at RazorEngine.Templating.TemplateService.Parse (System.String razorTemplate, System.Object model, RazorEngine.Templating.DynamicViewBag viewBag, System.String cacheName) <0x4218ac70 + 0x00077> in <filename unknown>:0 
  at RazorEngine.Razor.Parse[T] (System.String razorTemplate, RazorEngine.T model, System.String cacheName) <0x4218ab00 + 0x0003f> in <filename unknown>:0 
Schnell answered 17/8, 2016 at 18:59 Comment(23)
Recursive method calls are one cause for Stackoverflow exceptions. Look for those.Pristine
can you show the actual code and not a screen shot of the code.. it can be a number of things that are causing this but sure is hard to tell without seeing the full code in questionEndopeptidase
Quite likely, somewhere in there, a template is instantiating itself, probably not directly.Toul
@Pristine If template is created with smaller number of memory variables and divs, exception does not occur. Code does not make recursive calls.Schnell
@Endopeptidase Whole template which causes this exception is in wikisend.com/download/177922/stackoverflow.TXTSchnell
@EdPlunkett . Template is in wikisend.com/download/177922/stackoverflow.TXT If lot of divs and memory variables are removed, it runs OK. So I dont see any possibility of recursion.Schnell
@Schnell My rule of thumb is that when I disagree with the compiler, I'm usually wrong. And I've got some empirical backup on that one.Toul
@Schnell Did H.P. Lovecraft write that thing?Toul
I published whole template code. This is automatically generated by report generator from report layout in database. What is wrong with this template?Schnell
Sorry, I'm not going to download a file from some sketchy download site to answer a question that's unclear.Conoscenti
@MikeMcCaughan What should I do so you can answer to this question?Schnell
You've got a big image. We know what Visual Studio looks like when something blows up. The stack trace and the Execute() method would be sufficient. Something is calling itself.Malda
"If a ... number of <div>s are removed from the template, it executes okay" ...so add the <div>s back one by one until you see what blows up. And consider not putting C# in the middle of a Razor template.Malda
C# code in middle of template consists of if statements around divs which determine which divs will appear in result html. There are also assignments to variables to calculate subtotals. How to implement this without putting C# code in middle of template ?Schnell
You have a lot more than "if" statements in there. Re: How...?; Have you considered the MVP pattern? bradoncode.com/blog/2012/04/…Malda
@Schnell add you stack trace to the question.Linnealinnean
@GerardoGrignoli Stack trace is shown in image. It points to .NET razor Execute() method. Stack trace shown contains 10 lines, no recursion. I'm unable to find any other stack trace. In exception details window <internal error in evaluator> appears for stack trace value.Schnell
Is your template XML compliant? The template you posted does not look like it. It has a lot of <div> tags that are left open. It might confuse a parser.Ruthenian
@Ruthenian Template produces valid html5 page. All div tags are closed in posted template. Where you see open div tags ?Schnell
@ChaimEliyah First line in template code shows that it follows standard ASP.NET Razor MVC pattern. Controller creates viewmodel and passes it to template. Template calls viewmodel methods. MVP pattern is not available in ASP.NET MVC, MVC is its replacement.Schnell
@Schnell You will have to do manually search where the error is coming from: Delete half of the code and try again. If still fails, delete another 50%. If it works, then undelete the 50% and delete the other 50% and start again. Repeat until you have a better clue of where is the exception coming from.Linnealinnean
@Schnell Also, be sure that you have configured Visual Studio to break on all exceptions so that you catch your complete stack traceLinnealinnean
Tools Options Debugging General Enable Just My Code is not checked. StackOverFlowException is checked in Exception settings windowSchnell
A
0

That's some of the ugliest code I've seen for a while. You should refactor it to use arrays or move the calculations to the controller. It might be the Mono error is correct, that the page is too complex.

dynamic _calculated21=Round(r.Total/Vjag*Iif(Core.Left(r.BilskeemKontoklass,1)=="K",-1,1),Vymardada);
_calculated21=SetDefault(_calculated21);

// about 200 similar lines snipped
dynamic _calculated229=Round(Vs52gr/Vjag*Iif(Core.Left(r.BilskeemKontoklass,1)=="K",-1,1),Vymardada);
_calculated229=SetDefault(_calculated229);

And a bit later:

_calculated21=SetDefault(_calculated217);
// about 200 identical lines removed
_calculated229=SetDefault(_calculated229);
Armand answered 18/8, 2016 at 3:59 Comment(6)
This code is generated dynamically at runtime based on report users have created using report designer. Controller already contains common code for all reports. Calculations in template are different for every report. How to move this code to controller ? Should controller cs file also created and compiled at runtime? Using arrays will problably only change _calculated228 ot _calculated[228] Why this is better ?Schnell
How to refactor code to use arrays ? C# requires fixed array size on declaration. Array size is not know if template generation starts. During template generation if new variable is required, its name is created dynamically using "_calculated"+((i++).ToString()) It is only possible to limit max number of variables by declaring dynamic _calculated[10000] in template start. Is using hard coded array size instead of variables is reasonable?Schnell
Can you change the code generator? C# arrays are heap allocated. Variables are stack allocated. That might make a difference to the code generator, it might have limits on how many variables it can track.Armand
Code is generated from Razor cshtml view by .NET standard Razor view engine. Don't know any other engine which can generate html from similar template. Code which generates cshtml template can changed. It is probably possible to replace _calculated* variables with Dictionary<int,dynamic>. This will probably decrease report rendering speed so not sure is this reasonable. Development computer has 4 GB of RAM + swap file and there are only ~250 variables in template. How this small number of variables can cause stack overflow?Schnell
The entire page is basically one enormous method with 1000+ lines. I'd try simplifying. Easy win is calculate Iif(Core.Left(r.BilskeemKontoklass,1)=="K",-1,1) once. Otherwise consider moving blocks of the code into @helper methods or into an object. Do you need dynamic or can you use double or decimal? If your code generator created a class the page referenced with all those variables rather than dumping them directly on the page that might help, could be a lot of work though.Armand
I dont know how to call @helper methods from razon engine template. Code can moved to viewmodel and viewmodel method can called. User can create any reports without specifiyand it is not easy to eliminate common expressions or dynamic. Before refactoring it is desirable to find which limit is excatly exceeded. I posted related question in #39160877Schnell
B
0

You have a loop like this in your code @do { } while (!endOfData); Make sure that endOfData becomes true at some point.

Bevus answered 17/8, 2016 at 20:12 Comment(1)
If lot of div and variables are removed, report runs OK with same data. Date is read from database using npgsqlreader and data is not infinite. Even for large number of rows stack overflow exception should not occur, there is no recursion.Schnell
L
0

How to debug a StackOverflow Exception has already been asked here:

Bassically, go to Debug -> exceptions and check the thrown checkbox at Common Language Runtime Exceptions. Now when you cause the stackoverflow exception, the debugger will stop. When that happens, ignore the exception's stacktrace and go to Visual Studio's Call Stack window and look at the call stack there.

That will indicate which method is generating the infinite recursion.

Linnealinnean answered 18/8, 2016 at 3:48 Comment(1)
I checked All checkboxes in Debug Windows Exception Settings Common Languale Runtime Exceptions. Additional breakpoints for CultureNotFound etc exception etc. occured. I removed Break of exception of this type is thrown checkbox from breakpoint dialogs for those exceptions. StackOverFlowException still occurs in same place as shown in question. Excepton details still contains only on line ` System.StackOverflowException {<Internal Error evaluating expression>}` How to get other stack trace ?Schnell
A
0

That's some of the ugliest code I've seen for a while. You should refactor it to use arrays or move the calculations to the controller. It might be the Mono error is correct, that the page is too complex.

dynamic _calculated21=Round(r.Total/Vjag*Iif(Core.Left(r.BilskeemKontoklass,1)=="K",-1,1),Vymardada);
_calculated21=SetDefault(_calculated21);

// about 200 similar lines snipped
dynamic _calculated229=Round(Vs52gr/Vjag*Iif(Core.Left(r.BilskeemKontoklass,1)=="K",-1,1),Vymardada);
_calculated229=SetDefault(_calculated229);

And a bit later:

_calculated21=SetDefault(_calculated217);
// about 200 identical lines removed
_calculated229=SetDefault(_calculated229);
Armand answered 18/8, 2016 at 3:59 Comment(6)
This code is generated dynamically at runtime based on report users have created using report designer. Controller already contains common code for all reports. Calculations in template are different for every report. How to move this code to controller ? Should controller cs file also created and compiled at runtime? Using arrays will problably only change _calculated228 ot _calculated[228] Why this is better ?Schnell
How to refactor code to use arrays ? C# requires fixed array size on declaration. Array size is not know if template generation starts. During template generation if new variable is required, its name is created dynamically using "_calculated"+((i++).ToString()) It is only possible to limit max number of variables by declaring dynamic _calculated[10000] in template start. Is using hard coded array size instead of variables is reasonable?Schnell
Can you change the code generator? C# arrays are heap allocated. Variables are stack allocated. That might make a difference to the code generator, it might have limits on how many variables it can track.Armand
Code is generated from Razor cshtml view by .NET standard Razor view engine. Don't know any other engine which can generate html from similar template. Code which generates cshtml template can changed. It is probably possible to replace _calculated* variables with Dictionary<int,dynamic>. This will probably decrease report rendering speed so not sure is this reasonable. Development computer has 4 GB of RAM + swap file and there are only ~250 variables in template. How this small number of variables can cause stack overflow?Schnell
The entire page is basically one enormous method with 1000+ lines. I'd try simplifying. Easy win is calculate Iif(Core.Left(r.BilskeemKontoklass,1)=="K",-1,1) once. Otherwise consider moving blocks of the code into @helper methods or into an object. Do you need dynamic or can you use double or decimal? If your code generator created a class the page referenced with all those variables rather than dumping them directly on the page that might help, could be a lot of work though.Armand
I dont know how to call @helper methods from razon engine template. Code can moved to viewmodel and viewmodel method can called. User can create any reports without specifiyand it is not easy to eliminate common expressions or dynamic. Before refactoring it is desirable to find which limit is excatly exceeded. I posted related question in #39160877Schnell

© 2022 - 2024 — McMap. All rights reserved.