Sunday, January 29, 2017

17 what is a traceback? run time environment: it could be the client side


I am posting this answer so the topmost answer (when sorted by activity) is not one that is just plain wrong.
http://stackoverflow.com/questions/3988788/what-is-a-stack-trace-and-how-can-i-use-it-to-debug-my-application-errors
What is a Stacktrace?
A stacktrace is a very helpful debugging tool. It shows the call stack (meaning, the stack of functions that were called up to that point) at the time an uncaught exception was thrown (or the time the stacktrace was generated manually). This is very useful because it doesn't only show you where the error happened, but also how the program ended up in that place of the code. This leads over to the next question:
What is an Exception?
An Exception is what the runtime environment uses to tell you that an error occurred. Popular examples are NullPointerException, IndexOutOfBoundsException or ArithmeticException. Each of these are caused when you try to do something that is not possible. For example, a NullPointerException will be thrown when you try to dereference a Null-object:
Object a = null;
a.toString();                 //this line throws a NullPointerException

Object[] b = new Object[5];
System.out.println(b[10]);    //this line throws an IndexOutOfBoundsException,
                              //because b is only 5 elements long
int ia = 5;
int ib = 0;
ia = ia/ib;                   //this line throws an  ArithmeticException with the 
                              //message "/ by 0", because you are trying to
                              //divide by 0, which is not possible.
How should I deal with Stacktraces/Exceptions?
At first, find out what is causing the Exception. Try googleing the name of the exception to find out, what is the cause of that exception. Most of the time it will be caused by incorrect code. In the given examples above, all of the exceptions are caused by incorrect code. So for the NullPointerException example you could make sure that a is never null at that time. You could, for example, initialise a or include a check like this one:
if (a!=null) {
    a.toString();
}
This way, the offending line is not executed if a==null. Same goes for the other examples.
Sometimes you can't make sure that you don't get an exception. For example, if you are using a network connection in your program, you cannot stop the computer from loosing it's internet connection (e.g. you can't stop the user from disconnecting the computer's network connection). In this case the network library will probably throw an exception. Now you should catch the exception and handle it. This means, in the example with the network connection, you should try to reopen the connection or notify the user or something like that. Also, whenever you use catch, always catch only the exception you want to catch, do not use broad catch statements like catch (Exception e)that would catch all exceptions. This is very important, because otherwise you might accidentally catch the wrong exception and react in the wrong way.
try {
    Socket x = new Socket("1.1.1.1", 6789);
    x.getInputStream().read()
} catch (IOException e) {
    System.err.println("Connection could not be established, please try again later!")
}
Why should I not use catch (Exception e)?
Let's use a small example to show why you should not just catch all exceptions:
int mult(Integer a,Integer b) {
    try {
        int result = a/b
        return result;
    } catch (Exception e) {
        System.err.println("Error: Division by zero!");
        return 0;
    }
}
What this code is trying to do is to catch the ArithmeticException caused by a possible division by 0. But it also catches a possible NullPointerException that is thrown if a or b are null. This means, you might get a NullPointerException but you'll treat it as an ArithmeticException and probably do the wrong thing. In the best case you still miss that there was a NullPointerException. Stuff like that makes debugging much harder, so don't do that.
TLDR
  1. Figure out what is the cause of the exception and fix it, so that it doesn't throw the exception at all.
  2. If 1. is not possible, catch the specific exception and handle it.
    • Never just add a try/catch and then just ignore the exception! Don't do that!
    • Never use catch (Exception e), always catch specific Exceptions. That will save you a lot of headaches.
shareedit
   
Thanks, this is a really helpful answer. Please can you fix the typo: "try to deference a Null-object". (You need fixes to edit a post unless you are the author) – Zach Smith Jan 19 '16 at 8:27
   
Thanks for the reply and the typo ;) – Dakkaron Jan 19 '16 at 9:30
   
@Dakkaron: Great answer, thank you! I suppose ia = ia/b; should be ia = ia/ib;? – Setily Sep 9 '16 at 12:53
   
@Setily: thanks, I fixed it – Dakkaron Sep 13 '16 at 14:17
1 
nice explanation for why we should avoid bug masking – Sudip Bhandari Dec 20 '16 at 10:07 

To add on to what Rob has mentioned. Setting break points in your application allows for the step-by-step processing of the stack. This enables the developer to use the debugger to see at what exact point the method is doing something that was unanticipated.
Since Rob has used the NullPointerException (NPE) to illustrate something common, we can help to remove this issue in the following manner:
if we have a method that takes parameters such as: void (String firstName)
In our code we would want to evaluate that firstName contains a value, we would do this like so: if(firstName == null || firstName.equals("")) return;
The above prevents us from using firstName as an unsafe parameter. Therefore by doing null checks before processing we can help to ensure that our code will run properly. To expand on an example that utilizes an object with methods we can look here:
if(dog == null || dog.firstName == null) return;
The above is the proper order to check for nulls, we start with the base object, dog in this case, and then begin walking down the tree of possibilities to make sure everything is valid before processing. If the order were reversed a NPE could potentially be thrown and our program would crash.
shareedit
   
Agreed. This approach could be used to find out which reference in a statement is null when a NullPointerException is being examined, for example. – Rob Hruska Oct 21 '10 at 15:07
13 
When dealing with String, if you want to use equals method I think it´s better to use the constant in the left side of the comparation, like this: Instead of: if(firstName == null || firstName.equals("")) return; I always use: if(("").equals(firstName)) This prevents the Nullpointer exception – Torres Oct 26 '10 at 6:23 


I maintain an old application written in VB6. In client's environment it raises runtime errors which I can't reproduce under debugger. Is there any way to get the stacktrace or location of error?
I mean, without putting trace statements all over the code like here or adding error handlers for logging to every procedure like here.
It seems to be a simple question. Sorry. I just don't know VB6 very well. And it is surprisingly hard to google out any information, considering how widely it is (or used to be) used.
shareedit
   
I asked the same question stackoverflow.com/questions/127645/… I'm convinced that it can't be done. – raven Jul 8 '09 at 18:35
   
Maybe I wasn't clear. I have an application in production in a remote location. I haven't got access to this system and I can't run debugger there. There is something in their environment that triggers runtime error. I can't expect their IT staff (not to mention regular users) to really help, beyond sending me whatever application's shown or dumped to log file. I need some tool, instrumentation or anything, that will help me get meaningful input from them. Is--as raven writes--writing a "On Error GoTo/Reraise/LogError" in every routine the only way? – Tomek Szpakowicz Jul 9 '09 at 15:28
   
Well, you could compile with debug symbols as I mentioned, then get them to do a memory dump when the error occurs. You'll then be able to load the memory dump and hopefully get the stack trace using Visual Studio. – Ant Jul 10 '09 at 8:57
   
The "get them to do" just about anything is the hardest part. – Tomek Szpakowicz Jul 10 '09 at 11:31
   
@Ant - will only work if these are unhandled exception errors rather than intrinsic Visual Basic runtime errors. It is not clear from the question which it is. – MarkJ Jul 12 '09 at 17:14

4 Answers

Try compiling to pcode and see if you still get the error. This is one common difference between the debug mode of VB6 and runtime. I used to compile to native and ran into errors that only occurred in runtime. When I switched to pcode I found either the error went away or more likely a new error that reflected the real problem cropped up and was more easily reproduced in debug mode.
If despite that you still getting the error then I really recommend starting at the top of your procedure stack and working you way down using Maero's suggestion of
On Error Goto Handler
<code>
Exit <routine>
Handler:
Err.Raise Err.Number, "(function_name)->" & Err.source, Err.Description
It is a pain but there is no real way around it.
shareedit
   
The app is compiled to P-code. The problem is not debugging native code. The problem is, runtime error happens only in environment, I don't have access to. I just expected that interpreted (P-code) code would be able to give me some more information about runtime error in production system than C/C++, without me putting trace statements/error handlers all over the code. – Tomek Szpakowicz Jul 9 '09 at 15:36
   
I see one big drawback here. Now, if I do this, all runtime errors are handled. Debugger will not stop application at error location. Instead it will stop inside error handler in some other procedure down the stack. So this method helps with a I-have-no-debugger-in-production-environment scenario but breaks normal work with VB6 IDE. – Tomek Szpakowicz Jul 10 '09 at 12:58
2 
@tomekszpakowicz: correct! A classic problem with a classic solution. Try this "If Not IsInIDE() Then On Error Goto Handler", using the IsInIDE function from here vbnet.mvps.org/index.html?code/helpers/isinide.htm – MarkJ Jul 12 '09 at 17:17
2 
I'm not really satisfied by any answer here. I've chosen this answer only because a) I actually used this technique to pinpoint the cause of failure, although I'm not willing to litter all the code with this stuff, and b) as we migrate our codebase to .NET, I simply stopped to care about finding some better solution. – Tomek Szpakowicz Jul 15 '10 at 8:43
The VB6 debugger is flaky sometimes. There are alternatives.
  • You could try Windbg, a free standalone debugger from Microsoft. Compile your VB6 with no optimisation and "create symbolic debug info" (i.e. create PDB files), and you will be able to debug. Here's a 2006 blog post by a Microsoft guy about using Windbg with VB6, and 2004 blog post by another Microsoft guy with a brief introduction to Windbg.
  • You could also use the Visual Studio 2008 debugger with VB6 and PDB files, e.g. with Visual C++ Express Edition (which is free). See this for more details.
  • Both Windbg and Visual Studio expect the source code to be in exactly the same path on the debug machine as it was on the build machine when the VB6 was built. The easiest way is to build and debug on the same machine. Otherwise you might need to fiddle with SUBST to create virtual drives - or I'm told the serious way is to use a Symbol Server.
shareedit
If you check the "Create Symbolic Debug Info" checkbox on the Project Properties/Compile tab, then you can debug in Visual Studio just like you would a native C++ application.
shareedit
   
+1. You can also use free debuggers like Windbg or Visual Studio 2008, see my answer. – MarkJ Jul 12 '09 at 17:21
   
I meant Visual Studio 2008 (or 2003 or 2005 or whatever), but yeah - good point about Windbg! – Ant Jul 13 '09 at 9:31
It's been a while, but I don't think there is a way to get a stack trace in a VB6 application without adding an error handler and outputting the appropriate message. There were some third party tools that would add error handling to an entire application but I believe it just added "On Error Goto" error handlers throughout the code.
Just as an aside, one of the more insidious runtime errors I ever encountered in a VB6 app was when I used a font that didn't exist on the client's PC in the property of a control. This generates a runtime error that cannot be trapped in code, so no amount of error handling that I added ever uncovered the error. I finally came across it by chance. Hope this helps.
shareedit
1 
If you invoke forms via the deprecated Form1.Show method, you won't be able to catch the error, but if you use the Dim form1Instance as Form1: Set form1Instance = new Form1(): form1Instance.Show syntax, an error will be thrown at the Set... line – rpetrich Jul 10 '09 at 18:13

No comments:

Post a Comment