I am trying to understand the Go 1.13 error handling from https://pkg.go.dev/github.com/pkg/errors?tab=doc#pkg-overview but could not get the meaning of the following description:
which when applied recursively up the call stack results in error reports without context or debugging information
Could someone please provide an example in corresponding to sentence above.
What is the advantage of error in Go 1.13 in comparing to old style error handling?
Reading the next section on the page could potentially enlighten you.
The "err" being returned recursively, is the error being propagated to the caller, ultimately reaching the top level caller (main for instance), this is what this means.
Now if the cause or detail of the error is not specified, it is going to be very hard to know how to fix it. Providing context, ensures that the emitter of the error can be easily identified.
Related
I have written a custom clang Frontend tool according to the following link.
http://clang.llvm.org/docs/RAVFrontendAction.html
Now I am giving clang source code itself to my frontend tool for static analysis.
My tool is throwing an exception for this test case
https://llvm.org/svn/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
From the documentation of this test case, It is written for undefined behavior.
And while running ClangTool on this test it throws stackoverflow exception even before the control comes in HandleTranslationUnit.
As clang can generate AST for the above test case, I assume the exception might be coming during compilation. Now the question is can't I continue visiting AST nodes for such files as I don't care about the semantics of input source files. I am only interested in static analysis.
Is this the expected behavior? Then how to traverse the generated AST and visit the nodes. I am really stuck at this moment and have no clue how to proceed.
Would you please help me to fix this issue.
Thanks in advance!
Thanks,
Hemant Bhagat
I found the answer. There is problem with system recursion depth. On Windows default recursion depth limit is 512. So in the case of test case mentioned in question, stack is getting overflowed even before reaching recursion limit. Hence decreasing the recursion depth limit to 27 avoided stack overflow exception.
Similar is the case with template depth.
Is parameter validation using error return codes considered good practice ? I mean where should somebody use errors vs panics (are there any guidelines?).
For instance:
Is checking for non-nil + returning an error if it is nil a good
practice ?
Or checking for correct integer ranges etc.
I imagine that using errors that often would make Go feel very C-ish and would look pretty bad. Are panics a good alternative in those situations ?
Or should a Gopher use the Python/Ruby/JS-approach "just let it fail" ?
I'm a bit confused because panics are for real "errors" in my understanding. But using errors all the time is just bad.
And even if I would return error code: What could I do if somebody passes wrong parameter to my function but ignores the errors codes ? -> Nothing! So honestly I would say panics are nice for those situations but in a language where error codes are used over panics this is not very clear.
"Escaping" panics1 in Go (I mean, those which might be produced by the functions comprising the public API of your package) are to deal with errors programmers do. So, if your function gets a pointer to an object, and that can't be nil (say, to indicate that the value is missing) just go on and dereference the pointer to make the runtime panic itself if it happens to be nil. If a function expects an integer that must be in a certain range, panic if it's not in that range — because in a correct program all values which might be passed to your function are in that range, and if they don't then either the programmer failed to obey the API or they did not sanitize the value acquired from the outside which, again, is not your fault.
On the other hand, problems like failure to open a file or pefrorm some other action your function is supposed to perform when called correctly should not cause panics and the function should return an appropriate error instead.
Note that the recommendation for explicit checking for null parameters in the functions of public APIs in .NET and Java code has different goal of making such kinds of errors sort-of more readable. But since 99% of .NET and Java code just lets all the exceptions propagate to the top level (and then be displayed or may be logged) it's just replacing one (generated by runtime) exception with another. It might make errors more obvious—the execution fails in the API function, not somewhere deeper down the call stack—but adds unnecessary cruft to these API functions. So yes, this is opinionated but my subjective opinion is: to let it just crash is OK in Go—you'll get a descriptive stack trace.
TL;DR
With regard to processing of run-time problems,
panics are for programming errors;
returning errors is for problems with carrying out the intended tasks of functions.
1 Another legitimate use for panics is quick "cold-path" returning from deep recursive processing/computation; in this case panic should be caught and processed by your package, and the corresponding public API functions should return errors. See this and this for more info.
The answer to this is subjective. Here are my thoughts:
Regarding panic, I like this quote from Go By Example (ref)
A panic typically means something went unexpectedly wrong. Mostly we use it to fail fast on errors that shouldn’t occur during normal operation, or that we aren’t prepared to handle gracefully.
In the description of your use case, I would argue that you should raise an errors and handle the errors. I would further argue that it is good practice to check the error status when one is provided by the function you are using and that the user should check if one is provided in the documentation.
Panics I would use to stop the execution if I run across an error that is returned from the function you are writing that I check and don't have a way to recover from.
Currently, I see a recurring error:
2013-04-18 02:35:51.583 aaah[1713:1110f] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x1fc00dc0> was mutated while being enumerated.'
In the failing background queue (I see my queues state upon the moment of a crash by pressing Command + 5) I see:
0 _pthread_kill
1 pthread_kill
And I see assembly output which I completely don't understand.
I know how to resolve this kind of array enumeration errors - I just can't understand where/how I should seek for the piece of code causing my app to crash.
I have much multi-threaded code using AFNetworking and Core Data, so I can't just remember where the crucial section might be.
Also, this error occurs not always, but from time to time, so it is difficult just to use "isolation approach", isolating smaller and smaller pieces of code, to finally identify the buggy piece of code.
So the question is:
How can I extract some more useful information from this output, or Xcode can provide me with some more verbosity level, so I could know how to resolve this annoying piece of code.
Have you tried setting an exception breakpoint? Sometimes the debugger struggles with exception handling inside blocks but it might help.
In the breakpoints navigator (one of the tabs on the left side of the window) click the plus button at the bottom of the window and select add an exception breakpoint. Then hit done.
Now when you crash, the debugger should hopefully put you right before the instant the exception was raised.
See http://developer.apple.com/library/mac/#recipes/xcode_help-breakpoint_navigator/articles/adding_an_exception_breakpoint.html for more info.
Edit:
Based on the feedback provided in the comments, here's some more analysis:
The exception your application is raising means that you attempted to change a collection type (in this case, an NSMutableOrderedSet) inside of an enumeration block (in your case, most likely a for-loop). It looks like you're trying to remove objects in a set that you are looping over: [NSMutableOrderedSet removeObjectsInRange:inOrderedSet:]
To resolve this you should store the ranges you wish to remove and then do the actual removing once you're no longer iterating over the set. It's still going to be difficult since, as I understand it, you're not breaking inside of Objective-C code. You should look at the running threads in the panel on the left and look at what method they're currently in. That might give you a hint as to where your code is wrong.
I am looking at code written by someone else.
Some of the big functions are a mess, with changes to the error handling at many points throughout the function. There is a variety of On Error Goto ErrHandler, On Error Goto 0, On Error Resume Next, as you go through the function.
What would be the best way to go through and clean up this error handling so that there is just one On Error Goto ErrHandler at the top of the function as it should be?
I don't think that having a single Error Handler is necessarily the best solution.
If you have a huge function with one error handler and something goes wrong, you have no idea at which point it failed.
It sounds to be as though the functions you describe have the correct error handling in them but that doesn't mean it is easy to read.
Maybe the best solution is to re-factor the big functions into several smaller ones which can have their own single error handler that way when an error occurs you only have a few lines to track down the bug?
You could use the existing error handler statement to give you suitable markers for code re-factoring.
It's hard to say without looking at the code in question, but there are times when several different types of error handling in a single function is legitimate. In general, a single On Error GoTo ErrHandler at the top of the function serves the same function as an enclosing try/catch block in a language that supports exceptions -- it's there to catch the unexpected errors that occur.
However, within the function, there may be places where an error is a normal, expected occurrence that you want to check for inline. For example, say you're going access a network drive, where you have to account for the remote server being offline, the network down, etc. In this case, even though there's an On Error GoTo ErrHandler statement at the top, you can turn that off locally with an On Error Resume Next and try to access the drive. If an error occurs, VB6 will now just fall through to the next statement where you can check Err.Number for anything other than 0. This is analogous to a nested try/catch to trap an expected error condition that you can handle locally. Once execution has passed beyond the risky code, you have to mark the end of the section where you're going to "manually" check for errors this way with another On Error GoTo ErrHandler statement to re-enable the function-level handler.
So there's a case where more than one On Error... statment is valid. The argument can be made that the risky function should be refactored out and have its own handler, but you'd still have to deal with the specific (expected) error return values from that separate function, because the called function probably won't know what to do in the face of these errors in the context of the calling function. You would still handle that with the short-term On Error Resume Next technique.
On Error GoTo 0 disables all error handling, letting VB6 bail out of your function whenever an unexpected error occurs. I'm having a hard time coming up with a non-contrived situation where that would be a good option.
I realise this is an older programming environment, but I have to clean up some VB6 code and I am finding that most of it uses:
On Error Resume Next
What is the general consensus about the use of On Error Resume Next?
Surely, if there is an error, you would want the app to stop what it was doing, rollback any data changes, and inform the user of the error, rather than just resuming.
When is it a good idea to use On Error Resume Next?
It is perfectly reasonable to use On Error Resume Next to implement local structured error handling. This involves testing for an exception and acting on it of course, as well as disarming the mechanism afterward. Example:
On Error Resume Next
GetAttr strFilePath
If Err Then
On Error GoTo 0
'Deal with "no file" scenario.
Else
On Error GoTo 0
'Open and process the file.
End If
That's just a simple example where only one sort of exception is expected. In some cases it is necessary to test Err.Number for specific values and take different actions based on them.
The unstructured approach based on GoTo label can often work as well, but it is hardly superior in most instances. In VBScript the pattern shown above is the only form of exception handling you even have since there are no GoTos or labels.
What's objectionable is arming explicit exception testing at the head of every procedure and ignoring it... a sort of Trust the Force, Luke approach to trying to mask coding errors.
I have found it useful in functions where an error would not warrant the user being interrupted with the issue. A good example is in the resize event. If you make a mistake or there's a problem in the resize event then you probably don't want the user to see this, as it probably wouldn't affect functionality.
I would say in general, use it sparingly.
Almost never - unless used consciously for example on a line where a successful call will set a particular return value, and the subsequent code handles the return value to cater for the error case.