Original article address: ASP. NET crash-crazy looping in a sitemap
Release date: Tuesday, October 10,200
Prepared by: Tess one day, I received an email about my blog and asked the following questions:
I want to quickly create a site map, so I overwrite the buildsitemap () method and write a loop in it to add some counterfeited sitemap nodes.
Public override sitemapnode buildsitemap (){
For (INT I = 0; I <5; I ++)
Myroot. childnodes. Add (New sitemapnode (this, I. tostring (), I. tostring (), I. tostring ()));
Return myroot;
}RunProgramStack Overflow occurs, and the server crashes. I used the debugger for single-step debugging and found it really strange:
1) int I = 0
2) I <5
3) myroot...
4) int I = 0
5) I <5
etc.
The I value seems to have never been increased, unless I call sitemapnode (access a property, call a method), it seems that this loop is correct.
what makes this cycle uncertain? It may be a bug in the compiler or CLR. (when I get this question, I really don't know ASP. website navigation in net2.0, but I found these articles ... the http://weblogs.asp.net/scottgu/archive/2005/11/20/431019.aspx and http://aspnet.4guysfromrolla.com/articles/111605-1.aspx are really nice .)
Initial ideas
The most important thing about this problem is that it always starts again, which means that on-site debugging can be performed. But we are not so far away. Let's look back and see what's happening now... 1. stack Overflow 2. I have discussed stack overflow in my previous blog posts. Repeat it now... the cause of stack overflow is that too many function pointers, variable pointers, and parameters are allocated, so that the amount of memory applied in the stack is insufficient. So far, the most common cause of stack overflow is non-terminating recursion. In other words, function a calls function B, and function B calls function a... So callstack looks a bit like this .......
Functionb ()
Functiona ()
Functionb ()
Functiona () is good. Everything is good, but it only explains stack overflow. So what is the crazy loop? Well... imagine there is such a function (there is a breakpoint at -->) void myrecursivefunction (){
For (INT I = 0; I <5; I ++ ){
--> Myrecursivefunction ();
}
} When you stop at the breakpoint for the first time, the I value should be 0, and callstack looks like this... myrecursivefunction ()
...
Now we call the myrecrusive function. Every time we call this function, I = 0 will appear again (although we are not really in the same loop ). If you call the myrecrusive function several times back and forth, and use the actually executed Code Instead, it will execute code similar to the following: for (INT I = 0; I <5; I ++ ){
For (INT I2 = 0; I2 <5; I2 ++ ){
For (INT I3 = 0; I3 <5; I3 ++ ){
For (INT I4 = 0; I4 <5; I4 ++ ){
For (INT I5 = 0; I5 <5; I5 ++ ){
For (INT I6 = 0; I6 <5; I6 ++ ){
For (INT i7 = 0; i7 <5; i7 ++ ){
...
}
}
}
}
}
}
}... View it in Visual Studio. It seems that the same loop is always run and the value of variable I is not changed. For the moment, you will not have a deep understanding of this until you actually see the stack call.
Let's take a look at callstack. Now callstack looks like this...
Myrecursivefunction ()
Myrecursivefunction ()
Myrecursivefunction ()
Myrecursivefunction ()
Myrecursivefunction ()
Myrecursivefunction ()
Myrecursivefunction ()
So the original idea is that we will undoubtedly look at some recursion... but where? The code in the example is myroot. childnodes. add (New sitemapnode (this, I. tostring (), I. tostring (), I. tostring (); it does not look so complicated... the most suspicious here are new sitemapnode () and myroot. childnodes. add (). If we use reflector to check it, it will not be so mysterious.
Debugging problems Last: a little bit more tongue, more windbg actions... because it is easy to re-render, I will re-present it on my machine. I just need to attach windbg (File/attach to process.exe to w3wp.exe, and click g to start. This problem occurs again. When the program is aborted, it prompts me that this is a stack overflow (we already know ).
(7e4. DDC): Stack Overflow-code c00000fd (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
Eax = 0fa4235c EBX = 02beca74 ECx = 02beca74 edX = 02becb54 ESI = 02becb54 EDI = 02beca74
EIP = 686b5cb4 ESP = 02163000 EBP = 02163004 iopl = 0 NV up ei pl Zr na PE NC
Cs = 0023 Ss = 002b DS = 002b es = 002b FS = 0053 GS = 002b EFL = 00210246
System_web_ni + 0xf5cb4: 686b5cb4 56 push ESI
Let's check the stack and use it! Clrstack command to see how to abort, but we can only see ....0: 016>! Clrstack
OS thread ID: 0 xddc (16)
ESP EIPs 02163000 686b5cb4 system. Web. staticsitemapprovider. getchildnodes (system. Web. sitemapnode)
... This is not very helpful to us. Sometimes when we encounter stack overflow, use! The clrstack command has some such problems. So we still need to use it! Run the dumpstack command to view the raw stack.0: 016>! Dumpstack
OS thread ID: 0 xddc (16)
Current frame: (methoddesc 0x68b03720 + 0x4 system. Web. staticsitemapprovider. getchildnodes (system. Web. sitemapnode ))
Childebp retaddr caller, callee
02163004 686b1fc4 (methoddesc 0x68aeff30 + 0x18 system. Web. sitemapnode. get_childnodes ())
0216300c 0f765641 (methoddesc 0xfa42328 + 0x59 viewsitemapprovider. buildsitemap ())
0216303c 686b5cdf (methoddesc 0x68b03720 + 0x2f system. Web. staticsitemapprovider. getchildnodes (system. Web. sitemapnode ))
02163074 686b1fc4 (methoddesc 0x68aeff30 + 0x18 system. Web. sitemapnode. get_childnodes ())
0216307c 0f765641 (methoddesc 0xfa42328 + 0x59 viewsitemapprovider. buildsitemap ())
021630ac 686b5cdf (methoddesc 0x68b03720 + 0x2f system. Web. staticsitemapprovider. getchildnodes (system. Web. sitemapnode ))
021630e4 686b1fc4 (methoddesc 0x68aeff30 + 0x18 system. Web. sitemapnode. get_childnodes ())
021630ec 0f765641 (methoddesc 0xfa42328 + 0x59 viewsitemapprovider. buildsitemap ())
0216311c 686b5cdf (methoddesc 0x68b03720 + 0x2f system. Web. staticsitemapprovider. getchildnodes (system. Web. sitemapnode ))
02163154 686b1fc4 (methoddesc 0x68aeff30 + 0x18 system. Web. sitemapnode. get_childnodes ())
0216315c 0f765641 (methoddesc 0xfa42328 + 0x59 viewsitemapprovider. buildsitemap ())
...
Okay, it seems that the problem comes from the childnodes attribute. When this attribute is used, the getchildnodes function will be called. This function will call the buildsitemap function again, so that it calls the childnodes attribute again. This keeps going, leading to stack overflow.
Conclusion
In the document buildsitemap, you can find the following section:
BuildsitemapMethodFindsitemapnode,GetchildnodesAndGetparentnodeCall the method by default. If you override the buildsitemap method in a derived class, make sure that it loads site map data only once and returns it in subsequent calls. To avoid recursion and stack overflow, it is best to avoid calling this method, as shown inBuildsitemapIn this example, we can use the addnode method to add subnodes. This is also worth reading in this article archived in site map providers.Buildsitemap generally does not call the methods or Attributes provided by other site maps, because many methods and attributes implement buildsitemap calls by default. For example, rootnode in buildsitemap causes recursion to terminate a stack overflow.