Rethrowing does not work?

  • Thread starter valentin tihomirov
  • Start date
V

valentin tihomirov

I do not understand something. A caught exception stack points to an
argument-free 'throw' in a catch block. Meantime, it is widely known that
these statements re-throw the original exceptions. I expected, therefore,
that the stack points to the original 'throw e' code line.
 
N

Nicholas Paldino [.NET/C# MVP]

valentin,

Nope, it does not. If you rethrow the original exception with "throw
e", then the point from which you threw the exception changed, resetting the
call stack on the exception.
 
V

valentin tihomirov

Oh, excuse me. I had rewise my data. It seems that both 'throw' and 'throw
e' rethrow
http://msdn2.microsoft.com/en-us/library/0yd65esw(VS.71).aspx But my
previous data told that 'throw', given a throwable object, raises a new
exception. And that is the difference. The 2nd google match on "c# rethrow"
affirms this http://bartdesmet.net/blogs/bart/archive/2006/03/12/3815.aspx

Anyway, I do not understand why re-throw overwrites the line of code where
exception was raised by the line where it was re-thrown. My rationale is
that the call stack makes value pointing to the cause of the exception
rather than the last place where it was handeled.
 
J

Jon Skeet [C# MVP]

valentin tihomirov said:
I do not understand something. A caught exception stack points to an
argument-free 'throw' in a catch block. Meantime, it is widely known that
these statements re-throw the original exceptions. I expected, therefore,
that the stack points to the original 'throw e' code line.

Could you post a short but complete program which demonstrates the
problem?

See http://www.pobox.com/~skeet/csharp/complete.html for details of
what I mean by that.
 
V

valentin tihomirov

I'm sure it is pretty obvious. But if you like

using System; // line 1

class Rerise {

public static void Main(string[] args) {

try {
throw new Exception("Can I escape?"); // line 8
} catch (Exception e) {
Console.WriteLine("Logged error: " + e.Message);
throw e; // line 11
}
}


}

Compile it with /debug key and see that stack trace will point to 'line 11'
where it is rethrown rather than to 'line 8' where it originates.
 
N

Nicholas Paldino [.NET/C# MVP]

As it should be. The spec is pretty clear on this, when you throw an
exception, the stack trace originates from the point of where it is thrown,
except when there is no exception stated with the throw statement, in which
case, the original exception is allowed to bubble up without having its
stack trace modified.
 
B

Ben Voigt [C++ MVP]

valentin tihomirov said:
I'm sure it is pretty obvious. But if you like

using System; // line 1

class Rerise {

public static void Main(string[] args) {

try {
throw new Exception("Can I escape?"); // line 8
} catch (Exception e) {
Console.WriteLine("Logged error: " + e.Message);
throw e; // line 11
}
}


}

Compile it with /debug key and see that stack trace will point to 'line
11' where it is rethrown rather than to 'line 8' where it originates.

That is a throw, not a rethrow.

Change the line to "throw;" if you want the call stack preserved.
 
V

valentin tihomirov

As it should be. The spec is pretty clear on this, when you throw an
exception, the stack trace originates from the point of where it is
thrown, except when there is no exception stated with the throw statement,
in which case, the original exception is allowed to bubble up without
having its stack trace modified.

Why then it should not "bubble up without having its stack trace modified"
if it is allowed? Why it overwirtes the stack with the rethrow location?
Hiding the exception reason from user defeats the whole value of stack
trace.
 
B

Ben Voigt [C++ MVP]

valentin tihomirov said:
Why then it should not "bubble up without having its stack trace modified"
if it is allowed? Why it overwirtes the stack with the rethrow location?
Hiding the exception reason from user defeats the whole value of stack
trace.

"throw e" performs certain steps, including setting up a stack trace.
Doesn't matter if e was thrown before, it makes a new stack trace. This
allows you to do things like preallocate or reuse exception objects.

Also, some libraries might want to hide where an exception actually
occurred, because the programmers feel that threatens their intellectual
property. Seems ridiculous to you and me, but some people think that way.
 
V

valentin tihomirov

That is a throw, not a rethrow.
Change the line to "throw;" if you want the call stack preserved.

Excuse me, I've tried both before posting here. This was the 2nd, so you see
it. But the result is the same line11. The compiler used is csc.exe from
..Net2 Try yourself.
 
B

Ben Voigt [C++ MVP]

valentin tihomirov said:
Excuse me, I've tried both before posting here. This was the 2nd, so you
see it. But the result is the same line11. The compiler used is csc.exe
from .Net2 Try yourself.
It appears that one stack level is lost, to wit, the call from the handling
function toward the function(s) that caused the exception.

Nevertheless, "throw;" maintains the complete call stack, while "throw e;"
starts a new call stack.

Code:

using System; // line 1

class Rerise
{
static void Layer2()
{
throw new Exception("Can I escape?");
}

static void Layer1()
{
Layer2();
}

static void Layer0()
{
try
{
Layer1();
}
catch (Exception e)
{
Console.WriteLine("Logged error: " + e.Message);
throw e; // if replaced by "throw;", then Layer1 and Layer2
appear in the trace
}
}

public static void Main(string[] args)
{
try
{
Layer0();
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
}
}
}
 
J

Jon Skeet [C# MVP]

valentin tihomirov said:
I'm sure it is pretty obvious. But if you like

using System; // line 1

class Rerise {

public static void Main(string[] args) {

try {
throw new Exception("Can I escape?"); // line 8
} catch (Exception e) {
Console.WriteLine("Logged error: " + e.Message);
throw e; // line 11
}
}
}

Compile it with /debug key and see that stack trace will point to 'line 11'
where it is rethrown rather than to 'line 8' where it originates.

Ah, but your original post said: "A caught exception stack points to an
argument-free 'throw' in a catch block."

I therefore thought you'd written:

throw;

instead of

throw e;

Now, in every case I've seen before, that's enough to get the original
stack trace. I've no idea at the moment why it's not enough in this
case.

If you move the throw new Exception(...) to a new method, and call that
method from the "try" then you *do* see the complete stack trace. I
don't know why it doesn't happen when it's thrown within the same
method.

In general though, if you want to preserve the stack trace, use
"throw" instead of "throw e".
 
C

Christof Nordiek

valentin tihomirov said:
I'm sure it is pretty obvious. But if you like

using System; // line 1

class Rerise {

public static void Main(string[] args) {

try {
throw new Exception("Can I escape?"); // line 8
} catch (Exception e) {
Console.WriteLine("Logged error: " + e.Message);
throw e; // line 11
}
}


}

Compile it with /debug key and see that stack trace will point to 'line
11' where it is rethrown rather than to 'line 8' where it originates.

It doesn't build a new stacktrace, it only changes the line reported for the
method where ther throw; occurs.
You can chack it with following programm:

<code>
using System;

class A
{
static void Main()
{
try
{
ThrowException(); //line 9
}
catch (Exception e)
{
throw; //line 13
}
}

static void ThrowException()
{
throw new Exception(); //line 19
}

}
</code>

stacktrace looks like:
A.ThrowException() .... line 19
A.Main ... line 13

If you change catch(Exception e) to catch (SystemException e), wich prevents
the exception from being caught, the trck trace looks like following:

A.ThrowException() ... line 19
A.Main ... line 9

So, the methods in the stacktrace remain the same, but the line reported is
changed.

Christof
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top