Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unreachable code, but reachable with an exception

This code is part of an application that reads from and writes to an ODBC connected database. It creates a record in the database and then checks if a record has been successfully created, then returning true.

My understanding of control flow is as follows:

command.ExecuteNonQuery() is documented to throw an Invalid​Operation​Exception when "a method call is invalid for the object's current state". Therefore, if that would happen, execution of the try block would stop, the finally block would be executed, then would execute the return false; at the bottom.

However, my IDE claims that the return false; is unreachable code. And it seems to be true, I can remove it and it compiles without any complaints. However, for me it looks as if there would be no return value for the code path where the mentioned exception is thrown.

private static bool createRecord(String table,                                  IDictionary<String,String> data,                                  System.Data.IDbConnection conn,                                  OdbcTransaction trans) {      [... some other code ...]      int returnValue = 0;     try {         command.CommandText = sb.ToString();         returnValue = command.ExecuteNonQuery();          return returnValue == 1;     } finally {         command.Dispose();     }      return false; } 

What is my error of understanding here?

like image 858
0xCAFEBABE Avatar asked Mar 12 '19 08:03

0xCAFEBABE


People also ask

Why does it say my code is unreachable?

In computer programming, unreachable code is part of the source code of a program which can never be executed because there exists no control flow path to the code from the rest of the program.

How do you solve an unreachable statement?

1(a) is compiled, line 12 raises an unreachable statement error because the break statement exits the for loop and the successive statement cannot be executed. To address this issue, the control flow needs to be restructured and the unreachable statement removed, or moved outside the enclosing block, as shown in Fig.

How do I fix unreachable code in C++?

To fix it, remove the unreachable code. Error C4702 can occur in some versions of the compiler when you compile using the /GX , /EHc , /EHsc , or /EHac options, and use extern "C" functions. Because the compiler assumes extern "C" functions don't throw, the catch block isn't reachable.


2 Answers

Compiler Warning (level 2) CS0162

Unreachable code detected

The compiler detected code that will never be executed.

Which is just saying, the Compiler understands enough through Static Analysis that it can't be reached and completely omits it from the compiled IL (hence your warning).

Note : You can prove this fact to your self by trying to Step on to the Unreachable Code with the debugger, or using an IL Explorer.

The finally may run on an Exception, (though that aside) it doesn't change the fact (in this case) it will still be an Uncaught Exception. Ergo, the last return will never get hit regardless.

  • If you want the code to continue onto the last return, your only option is to Catch the Exception;

  • If you don't, just leave it the way it is and remove the return.

Example

try  {     command.CommandText = sb.ToString();     returnValue = command.ExecuteNonQuery();      return returnValue == 1; } catch(<some exception>) {    // do something } finally  {     command.Dispose(); }  return false; 

To quote the documentation

try-finally (C# Reference)

By using a finally block, you can clean up any resources that are allocated in a try block, and you can run code even if an exception occurs in the try block. Typically, the statements of a finally block run when control leaves a try statement. The transfer of control can occur as a result of normal execution, of execution of a break, continue, goto, or return statement, or of propagation of an exception out of the try statement.

Within a handled exception, the associated finally block is guaranteed to be run. However, if the exception is unhandled, execution of the finally block is dependent on how the exception unwind operation is triggered. That, in turn, is dependent on how your computer is set up.

Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important. However, if you have statements in a finally block that must be run even in that situation, one solution is to add a catch block to the try-finally statement. Alternatively, you can catch the exception that might be thrown in the try block of a try-finally statement higher up the call stack. That is, you can catch the exception in the method that calls the method that contains the try-finally statement, or in the method that calls that method, or in any method in the call stack. If the exception is not caught, execution of the finally block depends on whether the operating system chooses to trigger an exception unwind operation.

Lastly

When using anything that supports the IDisposable interface (which is designed to release unmanaged resources), you can wrap it in a using statement. The compiler will generate a try {} finally {} and internally call Dispose() on the object.

like image 58
TheGeneral Avatar answered Sep 21 '22 13:09

TheGeneral


the finally block would be executed, then would execute the return false; at the bottom.

Wrong. finally doesn't swallow the exception. It honors it and the exception will be thrown as normal. It will only execute the code in the finally before the block ends (with or without an exception).

If you want the exception to be swallowed, you should use a catch block with no throw in it.

like image 28
Patrick Hofman Avatar answered Sep 20 '22 13:09

Patrick Hofman