I have an All Exceptions breakpoint configured in Xcode:
Sometimes Xcode will stop on a line like:
[managedObjectContext save:&error];
with the following backtrace:
but the program continues on as if nothing happened if you click Continue.
How can I ignore these "normal" exceptions, but still have the debugger stop on exceptions in my own code?
(I understand that this happens because Core Data internally throws and catches exceptions, and that Xcode is simply honoring my request to pause the program whenever an exception is thrown. However, I want to ignore these so I can get back to debugging my own code!)
Moderators: this is similar to "Xcode 4 exception breakpoint filtering", but I think that question takes too long to get around to the point and doesn't have any useful answers. Can they be linked?
For Core Data exceptions, what I typically do is remove the "All Exceptions" breakpoint from Xcode and instead:
Add a Symbolic Breakpoint on objc_exception_throw
Set a Condition on the Breakpoint to (BOOL)(! (BOOL)[[(NSException *)$x0 className] hasPrefix:#"_NSCoreData"])
The configured breakpoint should look something like this:
This will ignore any private Core Data exceptions (as determined by the class name being prefixed by _NSCoreData) that are used for control flow. Note that the appropriate register is going to be dependent on the target device / simulator that you are running in. Take a look at this table for reference.
Note that this technique can be adapted easily to other conditionals. The tricky part was in crafting the BOOL and NSException casts to get lldb happy with the condition.
I wrote an lldb script that lets you selectively ignore Objective-C exceptions with a much simpler syntax, and it handles both OS X, iOS Simulator, and both 32bit and 64bit ARM.
Installation
Put this script in ~/Library/lldb/ignore_specified_objc_exceptions.py or somewhere useful.
import lldb
import re
import shlex
# This script allows Xcode to selectively ignore Obj-C exceptions
# based on any selector on the NSException instance
def getRegister(target):
if target.triple.startswith('x86_64'):
return "rdi"
elif target.triple.startswith('i386'):
return "eax"
elif target.triple.startswith('arm64'):
return "x0"
else:
return "r0"
def callMethodOnException(frame, register, method):
return frame.EvaluateExpression("(NSString *)[(NSException *)${0} {1}]".format(register, method)).GetObjectDescription()
def filterException(debugger, user_input, result, unused):
target = debugger.GetSelectedTarget()
frame = target.GetProcess().GetSelectedThread().GetFrameAtIndex(0)
if frame.symbol.name != 'objc_exception_throw':
# We can't handle anything except objc_exception_throw
return None
filters = shlex.split(user_input)
register = getRegister(target)
for filter in filters:
method, regexp_str = filter.split(":", 1)
value = callMethodOnException(frame, register, method)
if value is None:
output = "Unable to grab exception from register {0} with method {1}; skipping...".format(register, method)
result.PutCString(output)
result.flush()
continue
regexp = re.compile(regexp_str)
if regexp.match(value):
output = "Skipping exception because exception's {0} ({1}) matches {2}".format(method, value, regexp_str)
result.PutCString(output)
result.flush()
# If we tell the debugger to continue before this script finishes,
# Xcode gets into a weird state where it won't refuse to quit LLDB,
# so we set async so the script terminates and hands control back to Xcode
debugger.SetAsync(True)
debugger.HandleCommand("continue")
return None
return None
def __lldb_init_module(debugger, unused):
debugger.HandleCommand('command script add --function ignore_specified_objc_exceptions.filterException ignore_specified_objc_exceptions')
Add the following to ~/.lldbinit:
command script import ~/Library/lldb/ignore_specified_objc_exceptions.py
replacing ~/Library/lldb/ignore_specified_objc_exceptions.py with the correct path if you saved it somewhere else.
Usage
In Xcode, add a breakpoint to catch all Objective-C exceptions
Edit the breakpoint and add a Debugger Command with the following command:
ignore_specified_objc_exceptions name:NSAccessibilityException className:NSSomeException
This will ignore exceptions where NSException -name matches NSAccessibilityException OR -className matches NSSomeException
It should look something like this:
In your case, you would use ignore_specified_objc_exceptions className:_NSCoreData
See http://chen.do/blog/2013/09/30/selectively-ignoring-objective-c-exceptions-in-xcode/ for the script and more details.
Here is an alternative quick answer for when you have a block of code e.g. a 3rd part library that throws multiple exceptions that you want to ignore:
Set two breakpoints, one before and one after the exception throwing block of code you want to ignore.
Run the program, until it stops at an exception, and type 'breakpoint list' into the debugger console, and find the number of the 'all exceptions' break point, it should look like this:
2: names = {'objc_exception_throw', '__cxa_throw'}, locations = 2
Options: disabled
2.1: where = libobjc.A.dylibobjc_exception_throw, address = 0x00007fff8f8da6b3, unresolved, hit count = 0
2.2: where = libc++abi.dylib__cxa_throw, address = 0x00007fff8d19fab7, unresolved, hit count = 0
This means it is breakpoint 2. Now in xcode, edit the first breakpoint (before the exception throwing code) and change the action to 'debugger command' and type in 'breakpoint disable 2' (and set 'automatically continue...' checkbox ).
Do the same for the break point after the offending line and have the command 'breakpoint enable 2'.
The all breakpoints exception will now turn on and off so it's only active when you need it.
Related
During testing my iOS app, (it's a workout app), the app crashed (EXC_BREAKPOINT) as it was trying to save the workout data.
The crash was an index out of range issue whereby the array count is 1 lesser than the workout seconds. (I should have started the seconds counter from 1 instead of 0)
for i in 0...seconds {
let data = "\(i),\(dataArray.powerGenY[i-1]),\(dataArray.powerGenYAlt[i-1])\n"
do {
try data.appendToURL(fileURL: fileURL)
}
catch {
print("Could not write data to file")
}
}
anyways, the error dropped me to LLDB. Is there any way I an Use LLDB to bypass this error and continue execution?
Having worked out for a hour, I wasn't prepared to have this crash take my data along with it. Since the crashed dropped me into LLDB, I wanted to see if there's any way to salvage the data by stepping over / bypassing / changing the value of i so that the program execution can continue.
Initially I tried
(lldb) po i = 3327
error: <EXPR>:3:1: error: cannot assign to value: 'i' is immutable
i = 3327
^
but it won't let me change the value (I is immutable)
Then I tried thread jump -l 1 but it spewed some error about not the code execution outside of current function.
(lldb) th j -l 29
error: CSVExport.swift:29 is outside the current function.
Finally, going thru this site https://www.inovex.de/blog/lldb-patch-your-code-with-breakpoints/ and trying a few things. The one that helped was thread jump
thread return
The mentioned disadvantage of thread jump can be avoided by using a
different technique to change control flow behaviour. Instead of
manipulating the affected lines of code directly the idea is to
manipulate other parts of the program which in turn results in the
desired behaviour. For the given example this means changing the
return value of can_pass() from 0 to 1. Which, of course, can be done
through LLDB. The command to use is thread just like before, but this
time with the subcommand return to prematurely return from a stack
frame, thereby short-circuiting its execution.
Executing thread return 1 did the trick. This returned true (1) to the index out of range issue and then continued the execution to the next line of code.
I have tested two cases:
I use STEPCAFControl_Reader then STEPControl_Reader to read my step file but both methods crash when I call STEPCAFControl_Reader::Transfer, repsectively STEPControl_Reader:: TransferRoots.
By using STEPControl_Reader, I displayed a log on my console, then there is a message like this:
1 F:(BOUNDED_SURFACE,B_SPLINE_SURFACE,B_SPLINE_SURFACE_WITH_KNOTS,GEOMETRIC_REPRESENTATION_ITEM,RATIONAL_B_SPLINE_SURFACE,REPRESENTATION_ITEM,SURFACE): Count of Parameters is not 1 for representation_item
EDIT:
There is a null reference inside TransferRoots() method.
const Handle(Transfer_TransientProcess) &proc = thesession->TransferReader()->TransientProcess();
if (proc->GetProgress().IsNull())
{
//This condition does not exist from the source code
std::cout << "GetProgress is null" << std::endl;
return 0;
}
Message_ProgressSentry PS ( proc->GetProgress(), "Root", 0, nb, 1 );
My app and FreeCAD crash but if I use CAD Assitant which OCC official viewer, it loads.
It looks like comments already provide an answer to the question - or more precisely answers:
STEPCAFControl_Reader::ReadFile() returns reading status, which should be checked before calling STEPCAFControl_Reader::Transfer().
Normally, it is a good practice to put OCCT algorithm into try/catch block and check for OCCT exceptions (Standard_Failure).
Add OCC_CATCH_SIGNALS at the beginning of try statements (required only on Linux) and OSD::SetSignal(false) within working thread creation to redirect abnormal cases (access violation, NULL dereference and others) to C++ exceptions (OSD_Signal which is subclass of Standard_Failure). This may conflict other signal handlers in mixed environment - so check also documentation of other frameworks used by application.
If you catch failures like NULL dereference on calling OCCT algorithm with valid arguments - this is a bug in OCCT which is desirable to be fixed in one or another way, even if input STEP file contains syntax/logical errors triggering such kind of issues. Report the issue on OCCT Bugtracker with sufficient information for reproducing bug, including sample files - it is not helpful to developers just saying that OCCT crashes somewhere. Consider also contributing into this open source project by debugging OCCT code and suggesting patches.
Check STEP file reading log for possible errors in the file itself. Consider reporting an issue to system producing a broken file, even if main file content can be loaded by STEP readers.
It is a common practice to use OSD::SetSignal() within OCCT-based applications (like CAD Assistant) to improve their robustness on non-fatal errors in application/OCCT code. It is more user friendly reporting an internal error message instead of silently crashing.
But it should be noted, that OSD::SetSignal() doesn't guarantee application not being crashed nor that application can work properly after catching such failure - due to asynchronous nature of some signals, the memory can be already corrupted at the moment, when C++ exception has been raised leading to all kinds of undesired behavior. For that reason, it is better not ignoring such kind of exceptions, even if it looks like application works fine with them.
OSD::SetSignal(false); // should be called ones at application startup
STEPCAFControl_Reader aReader;
try
{
OCC_CATCH_SIGNALS // necessary for redirecting signals on Linux
if (aReader.ReadFile (theFilePath) != IFSelect_RetDone) { return false; }
if (!aReader.Transfer (myXdeDoc)) { return false; }
}
catch (Standard_Failure const& theFailure)
{
std::cerr << "STEP import failed: " << theFailure.GetMessageString() << "\n";
return false;
}
return true;
For whatever reason my project has started giving me problems printing any variable when I set a breakpoint. Consider the following code:
if let index = hintTypesInUse.index(of: type) {
let indexPath = IndexPath(item: 0, section: index + 1)
hintTypesCollectionView?.reloadItems(at: [indexPath])
hintTypesInUse[type].addHint()
}
If I set a breakpoint on the second line here, and I try to do 'po hintTypesInUse' I just get:
error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x1728c634e).
The process has been returned to the state before expression evaluation.
Now hintTypesInUse is accessible in the code itself after this point, and this is just a random example, it goes for anything in this project. The only variables I seem to be able to access while debugging are local variables within that code block.
Tried looking through my build scheme to see if there was anything weird there, but it's set to debug mode, and I compared it with a blank new project and it looks identical to that.
Why can't I access any non-local variables while debugging?
And of course a restart of Xcode and a reboot was all it took to fix the problem. 😆
I have a pyclips / clips program for which I wrote some unit tests using pytest.
Each test case involes an initial clips.Clear() followed by the execution of real clips COOL code via clips.Load(rule_file.clp). Running each test individually works fine.
Yet, when telling pytest to run all tests, some fail with ClipsError: S03: environment could not be cleared. In fact, it depends on the order of the tests in the .py file. There seem to be test cases, that cause the subsequent test case to throw the exception.
Maybe some clips code is still "in use" so that the clearing fails?
I read here that (clear)
Clears CLIPS. Removes all constructs and all associated data structures (such as facts and instances) from the CLIPS environment. A clear may be performed safely at any time, however, certain constructs will not allow themselves to be deleted while they are in use.
Could this be the case here? What is causing the (clear) command to fail?
EDIT:
I was able to narrow down the problem. It occurs under the following circumstances:
test_case_A comes right before test_case_B.
In test_case_A there is a test such as
(test (eq (type ?f_bio_puts) clips_FUNCTION))
but f_bio_puts has been set to
(slot f_bio_puts (default [nil]))
So testing the type of a slot variable, which has been set to [nil] initially, seems to cause the (clear) command to fail. Any ideas?
EDIT 2
I think I know what is causing the problem. It is the test line. I adapted my code to make it run in the clips Dialog Windows. And I got this error when loading via (batch ...)
[INSFUN2] No such instance nil in function type.
[DRIVE1] This error occurred in the join network
Problem resided in associated join
Of pattern #1 in rule part_1
I guess it is a bug of pyclips that this is masked.
Change the EnvClear function in the CLIPS source code construct.c file adding the following lines of code to reset the error flags:
globle void EnvClear(
void *theEnv)
{
struct callFunctionItem *theFunction;
/*==============================*/
/* Clear error flags if issued */
/* from an embedded controller. */
/*==============================*/
if ((EvaluationData(theEnv)->CurrentEvaluationDepth == 0) &&
(! CommandLineData(theEnv)->EvaluatingTopLevelCommand) &&
(EvaluationData(theEnv)->CurrentExpression == NULL))
{
SetEvaluationError(theEnv,FALSE);
SetHaltExecution(theEnv,FALSE);
}
For assert macros in my iPhone project, I'm looking for a way to programmatically break into the debugger. On Windows (MSVC++), I can use __debugbreak() for this purpose. Invoking this function will stop my program, launch the debugger, and display a callstack of the line that called __debugbreak().
Is there anything similar to __debugbreak() for the iPhone? I've tried Debugger(), but that gives me a linker error.
Thanks,
Claus
edit
Turns out this also works:
#define Debugger() { raise( SIGINT ) ; }
I think it's the same principle.
I use this:
#define Debugger() { kill( getpid(), SIGINT ) ; }
I think it works
in the simulator and on the device.. no assembly required!
A helpful person on Apple's developer forum gave me the tip to use asm("trap") when running on the device and asm("int3") when running on the simulator. This makes the program break into the debugger if you started your programm in debug mode (Option-Command-Y).
(__builtin_trap() also breaks into the debugger, but you can't continue afterwards. assert(false) terminates the program with a message, but doesn't break into the debugger.)
First Add -DDEBUG to OTHER_CFLAGS on your debug target; this will define the DEBUG symbol when building a debug build.
Then add a simple assert macro to your prefix header:
#ifdef DEBUG
#define MyAssert(val) _MyAssert(val)
#else
#define MyAssert(val) do { } while(0)
#endif
Next create a _MyAssert function in a module somewhere:
#ifdef DEBUG
void _MyAssert(int expression)
{
if (expression == 0) {
NSLog(#"Assertion failed!"); // Place breakpoint here
}
}
#endif
Finally create a breakpoint on the NSLog line.
I just set a breakpoint at the place I want to stop. Xcode remembers breakpoints persistently, so any time I run the app with gdb, it'll stop at that point.
If you want to break on assertion failures, a good place to set a breakpoint is on the function objc_exception_throw, in the Objective-C runtime, which is what actually throws an exception. Use the Run > Show > Breakpoints window and double-click the "Double-click for symbol" row, then type the name.
Is there something wrong with the simple assert() macro? Something like
assert(pointerToTest != nil);
will halt your process at that point if the condition is not true. If running under the debugger, you'll be presented with a stack trace of calls that led to the failed assertion. If you want to trigger it every time you hit a certain code path, you could do
assert(false);
I find these assertions extremely useful for verifying that all IBOutlets are non-nil when a window or view is brought up from a NIB.
If you run your program in debug, your app should launch the debugger when it reaches an invalid assertion.
For it to stop, as Jens Alfke tried to say, you need to enable "Stop on Objective-C Exceptions" (under the Run menu).
For more info about debugging vs. releasing and asserts, read http://myok12.wordpress.com/2010/10/10/to-use-or-not-to-use-assertions/
While an ancient thread, found this while researching same topic for Xcode 7. What solved this for me was a feature called "Create Exception Breakpoint..."
Debug > Breakpoints > Create Exception Breakpoint...
This puts a special breakpoint in the Breakpoint Navigator (under View > Navigators > Show Breakpoint Navigator).
This breaks on the actual throw of the exception:
[ exception raise ]
without terminating your code execution. You can just continue if that is how your code is structured.
Double-clicking the break point marker next to "All Exception" lets you adjust where and how the exception break point stops:
Check out conditional breakpoints:
http://www.cocoabuilder.com/archive/message/xcode/2008/10/22/25358