bypassing exc_breakpoint crash to continue program execution - swift

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.

Related

Error when running coreml in the background: Error computing NN outputs error

I'm running an mlmodel that is coming from keras on an iPhone 6. The predictions often fails with the error Error computing NN outputs. Does anyone know what could be the cause and if there is anything I can do about it?
do {
return try model.prediction(input1: input)
} catch let err {
fatalError(err.localizedDescription) // Error computing NN outputs error
}
EDIT: I tried apple's sample project and that one works in the background so it seems it's specific to either our project or model type.
I got the same error myself at similar "seemingly random" times. A bit of debug tracing established that it was caused by the app sometimes trying to load its coreml model when it was sent to background, then crashing or freezing when reloaded into foreground.
The message Error computing NN outputs error was preceded by:
Execution of the command buffer was aborted due to an error during execution. Insufficient Permission (to submit GPU work from background) (IOAF code 6)
I didn't need (or want) the model to be used when the app was in background, so I detected when the app was going in / out of background, set a flag and used a guard statement before attempting to call the model.
Detect when going into background using applicationWillResignActive within the AppDelegate.swift file and set a Bool flag e.g. appInBackground = true. See this for more info: Detect iOS app entering background
Detect when app re-enters foreground using applicationDidBecomeActive in the same AppDelegate.swift file, and reset flag appInBackground = false
Then in the function where you call the model, just before calling model, use a statement such as:
guard appInBackground == false else { return } // new line to add
guard let model = try? VNCoreMLModel(for modelName.model) else { fatalError("could not load model") // original line to load model
I doubt this is the most elegant solution, but it worked for me.
I haven't established why the attempt to load the model in background only happens sometimes.
In the Apple example you link to, it looks like their app only ever calls the model in response to a user input, so it will never try to load the model when in background. Hence the difference in my case ... and possibly yours as well?
In the end it was enough for us to set the usesCPUOnly flag. Using the GPU in the background seems prohibited in iOS. Apple actually wrote about this in their documentation as well. To specify this flag we couldn't use the generated model class anymore but had to call the raw coreml classes instead. I can imagine this changing in a future version however. The snippet below is taken from the generated model class, but with the added MLPredictionOptions specified.
let options = MLPredictionOptions()
options.usesCPUOnly = true // Can't use GPU in the background
// Copied from from the generated model class
let input = model_input(input: mlMultiArray)
let output = try generatedModel.model.prediction(from: input, options: options)
let result = model_output(output: output.featureValue(for: "output")!.multiArrayValue!).output

Problems debugging swift project - can't print any variable to the console while paused (exc_bad_access)

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. 😆

Calling a method from ABL code not working

When I create a new quote from Epicor I would like to add an item from the parts form automatically.
I am trying to do this using the following ABL code which runs when 'GetNewQuoteHed' is called:
run Update.
run GetNewQuoteDtl.
run ChangePartNumMaster("Rod Tube").
ttQuoteDtl.OrderQty = 5.
run Update.
I am getting the error:
Index -1 is either negative or above rows count.
This error occurs for each line in my ABL code.
What am I doing wrong?
That's not the proper format for a 4GL error message (nor is it at all familiar) so I'd say it is an Epicor application message. Epicor support is probably your best bet. However... Just guessing but it sounds like you might need to somehow initialize the thing that you're updating.
Agree with #Tom, but i would also say try and isolate the error and see where the error is raised as soon as you find the point the error is actually raised it is normally much easier to figure out exactly what is going wrong and how to solve it.
Working between a 0 based and a 1 based system there can be issues with the 1st or last entry depending on which way you moving. As the index for 0 based systems starts at 0 and ends at n-1 where 1 based systems start at 1 and end at n.

Ignore certain exceptions when using Xcode's All Exceptions breakpoint

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.

Confusion about CFNetwork, CFReadStreamOpen, and CFRunLoopRun

That sinking feeling when you realize you have no idea what's going on...
I've been using this code in my network code for almost two years without problems.
if (!CFReadStreamOpen(myReadStream)) {
CFStreamError myErr = CFReadStreamGetError(myReadStream);
if (myErr.error != 0) {
// An error has occurred.
if (myErr.domain == kCFStreamErrorDomainPOSIX) {
// Interpret myErr.error as a UNIX errno.
strerror(myErr.error);
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) {
OSStatus macError = (OSStatus)myErr.error;
}
// Check other domains.
}
}
I believe it was originally based on the code samples given here:
http://developer.apple.com/library/mac/#documentation/Networking/Conceptual/CFNetwork/CFStreamTasks/CFStreamTasks.html
I recently noticed, however, that some connections are failing, because CFReadStreamOpen returns false but the error code is 0. After staring at the above link some more, I noticed the CFRunLoopRun() statement, and added it:
if (!CFReadStreamOpen(myReadStream)) {
CFStreamError myErr = CFReadStreamGetError(myReadStream);
if (myErr.error != 0) {
// An error has occurred.
if (myErr.domain == kCFStreamErrorDomainPOSIX) {
// Interpret myErr.error as a UNIX errno.
strerror(myErr.error);
} else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) {
OSStatus macError = (OSStatus)myErr.error;
}
// Check other domains.
} else
// start the run loop
CFRunLoopRun();
}
This fixed the connection problem. However, my app started showing random problems - interface sometimes not responsive, or not drawing, text fields not editable, that kind of stuff.
I've read up on CFReadStreamOpen and on run loops (specifically, that the main run loop runs by itself and I shouldn't run a run loop unless I'm setting it up myself in a secondary thread - which I'm not, as far as I know). But I'm still confused about what's actually happening above. Specifically:
1) Why does CFReadStreamOpen sometimes return FALSE and error code 0? What does that actually mean?
2) What does the CFRunLoopRun call actually do in the above code? Why does the sample code make that call - if this code is running in the main thread I shouldn't have to run the run loop?
I guess I'll answer my own question, as much as I can.
1) In my code, at least, CFReadStreamOpen always seems to return false. The documentation is a bit confusing, but I read it to mean the stream wasn't opened yet, but will be open later in the run loop.
2) Most of the calls I was making were happening in the main thread, where the run loop was already running, so calling CFRunLoopRun was unnecessary. The call that was giving me problems was happening inside a block, which apparently spawned a new thread. This new thread didn't start a new run loop - so the stream would never open unless I explicitly ran the new thread's run loop.
I'm still not 100% clear on what happens if I call CFRunLoopRun() on a thread with an already running run loop, but it's obviously not good.
I ended up ditching my home-brewed networking code and switching to ASIHTTPRequest, which I was considering to do anyway.