Why doesn't the C # compiler even warn of infinite recursion?

The legacy application is in an infinite loop at startup; I don’t know why and how else (candidate for participation in the obfuscation program), but regarding the method that is called again and again (which is called from several other methods), I thought: “I wonder if one of the methods that calls this also calls another method that also calls it? "

I thought: “No, the compiler can understand this and not allow it, or at least give a warning!”

So, I created a simple application to prove that it will be like this:

public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { method1(); } private void button2_Click(object sender, EventArgs e) { method2(); } private void method1() { MessageBox.Show("method1 called, which will now call method2"); method2(); } private void method2() { MessageBox.Show("method2 called, which will now call method1"); // Note to self: Write an article entitled, "Copy-and-Paste Considered Harmful" method1(); } } 

... but no! It compiles just fine. Why would the compiler not put this code doubtful at best? If any button is jammed, you will never land!

Well, sometimes you may need an endless loop (pacemaker, etc.), but nonetheless, I think the warning should be emitted.

+6
source share
5 answers

This is not an infinite loop, but infinite recursion. And this is much worse, as they can lead to a stack overflow. Endless recursions are undesirable in most languages ​​unless you program malware. However, endless loops are often deliberate. Services typically run in infinite loops.

To detect this situation, the compiler will have to analyze the code following the method calls; however, the C # compiler restricts this process to immediate code in the current method. Here you can track uninitialized or unused variables, and, for example, unreachable code can be detected. There is a tradeoff between compilation speed and the depth of static analysis and optimization.

It is also hardly possible to find out the real intention of the programmer.

Imagine that you wrote a method that is completely legal. Suddenly, because you are calling this method from another place, your compiler complains and tells you that your method is no longer legal. I can already see the message flow on SO like: "My method compiled yesterday. Today it no longer compiles, but I did not change it."

+9
source
  • As you said, sometimes people need endless cycles. And the .net jit compiler supports tailcall optimization, so you might not even get a stack overflow for infinite recursion like you did.

  • In the general case, predicting whether a program will end at some point or is stuck in an infinite loop is impossible in a finite time. He caused a stopting problem. All the compiler can find are some special cases where they are easy to solve.

+12
source

Simply put: this is not a compiler job to question your coding patterns .

You could very well write a Main method that does nothing but throw Exception . This is a much simpler pattern to detect and a much more stupid thing to do; but the compiler will gladly allow your program to compile, run, crash and write.

With that said, since the technically infinite loop / recursion is completely legal with respect to the compiler, there is no reason why it should complain about it.

In fact, at compile time it would be very difficult to understand that a loop cannot be broken at runtime. An exception may be thrown, a user interaction may occur, the state may change somewhere in a certain thread, to the port you are monitoring, etc ... there are too many possibilities for any code analysis tool there to establish, without a doubt, that a certain segment of the recursive code will inevitably cause an overflow at runtime.

I think the right way to prevent these situations is through organizing unit testing. The more codes you cover in your tests, the less likely you will ever come across such a scenario.

+7
source

Because it is almost impossible to detect!

In the example you pointed out, it’s obvious (to us) that the code will loop forever. But the compiler just sees the function call; at that time, it does not always know what calls this function, what conditional logic can change the behavior of the loop, etc.

For example, with this small change, you are no longer in an infinite loop:

 private bool method1called = false; private void method1() { MessageBox.Show("method1 called, which will now call method2"); if (!method1called) method2(); method1called = true; } private void method2() { MessageBox.Show("method2 called, which will now call method1"); method1(); } 

Without actually starting the program, how do you know that this is not a cycle? I might see a warning for while (true) , but this has enough valid use cases, which also makes sense not to enter a warning for it.

The compiler simply parses the code and translates to IL (for .NET anyway). You can get limited information, such as variables that are not assigned at the same time (especially because they must generate a character table anyway), but advanced detection like this is usually provided to code analysis tools.

+3
source

I found this on the infinite loop wiki page found here: http://en.wikipedia.org/wiki/Infinite_loop#Intentional_looping

There are several situations where this is the desired behavior. For example, games on cartridge-based game consoles usually do not have exit conditions in their main cycle, since there is no operating system for the program to exit; the loop runs until the console shuts down.

An antique punch card reader literally stopped as soon as the job to process the card was completed, since there was no need to continue the hardware until a new stack of software cards was loaded.

In contrast, modern interactive computers require that the computer constantly monitor user input or device activity, so at some fundamental level there is an endless cycle of processing downtime that must continue until the device is turned off or reset. For example, in the Apollo Guidance Computer this external loop was contained in the Exec program, and if the computer did not perform absolutely no other work, it would launch a dummy that would simply turn off the “computer activity” indicator.

Modern computers also, as a rule, do not stop the processor or motherboards to control the circuit when they fail. Instead, they return to the error condition, displaying messages for the operator, and enter an infinite loop, waiting for the user to either respond to the invitation to continue or to reset the device.

Hope this helps.

+2
source

All Articles