0

I have this code, but there is an recursive function and i can't optimize it, that's why i always have StackOverFlow exception. Can you help me to optimize it? I use this void to get all info or to try again if some errors are found.

 public void Parse(byte[] data)
    {
        Socket skt = new Socket(SocketType.Dgram, ProtocolType.Udp);
        skt.ReceiveTimeout = 1000;

        skt.Connect(Encryptor.GetNextIP(), port);
        skt.Send(data);
        try
        {
         //a lot of actions to get the opcode
            switch (opCode)
            {
                case 0x01:
                    p = new Packet(opCode);
                    p.WriteArray(Encryptor.ClientData(answer, false));
                    Regex rgx = new Regex("\"(?<Name>.+?):");
                    string part = p.ReadAString();
                    string res;
                    if (part[part.Length - 1] != '}') part += '}';
                    if (rgx.Match(part).Groups["Name"].Value == "")
                    {
                        p = null;
                        Parse(data);
                        break;
                    }
                    else
                    { res = "ID=" + rgx.Match(part).Groups["Name"].Value; }
                    ParseInfo(rgx.Match(part).Groups["Name"].Value);
                    p = null;
                    Encryptor = null;
                    break;
                default: string ans = Encoding.ASCII.GetString(recv.Take(bytes).ToArray());
                    if (ans.Contains("EndOfStream") || ans.Contains("Begin"))
                    {
                        Failed();
                        Encryptor = null;
                        break;
                    }
                    else
                    {
                        p = null;
                        Parse(data);
                    }
                    break;
            }
        }
        catch
        {
            skt.Close();
            skt.Dispose();
            GC.Collect();
            Parse(data);
        }
    }

Thank you in advance.

9
  • What is the value of opCode? Commented Feb 25, 2014 at 20:11
  • 1
    Simple: don't use recursion. And last place to use it is in a general catch block. The Dispose() belongs in a finally block, the GC.Collect() behind a // Commented Feb 25, 2014 at 20:15
  • 1
    Using meaningful variable names is strongly suggested in C#, and abr dt cnt. Commented Feb 25, 2014 at 20:15
  • 3
    One thing that worries me is that you are calling the same method with the same data in the catch statement. Surely if you reach an exception this will just keep on going? Commented Feb 25, 2014 at 20:16
  • As Rob Aston pointed out and and selkathguy said in a solution, it's generally poor form to try calling the same method in a Catch block... Why would anything be different the next time you call it? Also you probably shouldn't catch and ignore EVERY exception like you are. Step through your code and see why it threw something, this is probably the problem. Commented Feb 25, 2014 at 20:18

4 Answers 4

1

All recursive functions must have and reach a terminating condition to rollback the stack. You left out how opCode value is derived, but if that one is ALWAYS 0x01 with regex evaluating to true, then function will never reach terminating condition. Same for default case and never seeing begin or EOS.

Another way of looking at it is that with every recursive call, it must take you one step closer to the end.

So examine your code logic to see why you never reach terminating condition.

also, blank catch that assumes memory fault that later starts recursion again is also possibly at fault... if socket returns some generic exception (no connectivity) then you'll recurse forever (until stack is blown)

Sign up to request clarification or add additional context in comments.

Comments

1

You appear to be calling Parse(data) without ever modifying the contents of data. It makes sense that it would call itself forever, especially considering the call to Parse(data) in your catch block. I don't see any base case in your code that would cause the recursion to stop.

Also, I really don't recommend calling GC.Collect(); Let the runtime handle memory management.

Comments

1

Your Try/Catch block is catching an exception from your code, then calling the same function that throws the exception before it has been popped from the execution stack. This is causing your StackOverflowException.

You have a Try/Catch block within a function, who's Catch segment calls the function containing it. This is generally very dangerous, and will hide the true exception of the program. For debugging purposes, try commenting out the try/catch and letting your debugger raise the exception to you so that you can get the source site of the error and track down what's going on.

Moving forward, if your program cannot handle a problem with the socket and is absolutely forced to throw an exception, don't try to shove the data back into the function. I recommend letting the socket die, clear your buffers, and resetting the connection. Then you can log the error to a file, or show a message to the user about the failure.

2 Comments

This should be a comment, not an answer, as it has no relevance to the question being asked (StackOverflowException)
Good catch, I was responding to the subject line and not the actual question (about optimization) in the OP. I assumed from the subject that the issue was the StackOverflowException. Thanks!
0

You cannot recurse forever, if you want to do something forever you need to change your logic from "i want to do this, and then i'll call this again and again" to some form of while(true) do this in a loop.

So change your logic into an infinite loop and instead of calling Parse within it, just don't (you will end up in the same place since your loop will get back in the same place and also have access to data)

Let's go with a minimalistic example instead of re typing all your code :

public void Parse(string data)
{
 var NewData = data + " again";
 Parse("test"); // this will call itself over and over resulting in a stackoverflow exception since the stack has to be preserved for the whole chain of functions
}

Change it to something like:

public void Parse(string data)
{
var NewData = data + " again";
while(true)
{
 NewData = data + " again"; // Will still run forever but within the same function, no stackoverflow
}
}

I suggest you read this thread for more info : What is tail recursion?

2 Comments

You don't understand. When i call ParseInfo process finished, when i call Failed() - too. But when i call again Parse(data) it means that we should retry.
It doesn't change anything at all, in either case you want to get out of recursion IF the recursion can be infinite, basically within the while true, add a check, if it failed, do nothing (the loop continues) else, brea out of the loop (and then call whatever you want to indicate things went well). This isn't an example of what you should do functionaly, it's a technical example, rewrite your code to get out of "run this, and if it failed, run this again" and instead write "as long as i failed (while) keep running (code of fail in the loop) then exit loop and continue with success code)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.