Objective-C Exception Handling: "Divided by Zero Exception" is not getting caught - objective-c

I have the following code in my program.
#try {
float result = 4 / 0; // LINE 1
} #catch (NSException *e) {
NSLog(#"Exception : %#", e);
return 0;
}
I expected an exception to be caught in LINE 1 and thrown to the #catch block. But the execution aborts at LINE 1 showing EXC_ARITHMETIC in console.
What am I doing wrong here? What necessary things I have to do to do exception handling?

EXC_ARITHMETIC is a type of low-level exception known as a "signal". The only way to catch them is to register a signal handler, for example:
#include<signal.h>
void handler(int signal) {
if (signal == FPE_FLTDIV)
printf("Divide by 0 exception\n");
}
signal(SIGFPE, handler);
However, the only safe thing to do in such a handler is clean up any resources and exit cleanly.

Divide by zero is not an NSException.
Give this a try (I never tried though):
#try {
float result = 4 / 0; // LINE 1
} #catch (NSException *e) {
NSLog(#"Exception : %#", e);
return 0;
}
#catch (id ue) {
//DIVIDE BY ZERO ATTEMPT MAY ENDUP HERE
NSLog(#"Exception : %#", ue);
return 0;
}
====== EDIT =======
Turns out divide by zero is not a obj-c exception. But seems you can catch such exceptions globally.
How do I catch global exceptions?

Exceptions List and division by zero isn't a predefined exception. Also, to know the type of exception, you should send name message to the exception object.
NSLog(#"Exception : %#", [ e name ] );

Actually float result = 4 / 0; would never raise any kind of signal or exception (xcode, LLVM). No idea why it just silently returns inf into result.

"4 / 0" is an expression with known literals, which can be very easily computed by compile time -- therefore there will be no runtime exception on that...

I am using the LLVM 5.1 compiler. In a *.m file just tried the line
float result = 4 / 0;
and
int result = 4 / 0;
and both give the result to be zero. But, because both contain the expression 4 / 0 which is integer division by zero regardless of the variable definition type, the compiler only gives a warning. All other compilers that I have used would have given an error from this expression.
The C language only specifies that integer division by zero is undefined. The compilers used in this case apparently define the result to be zero. This is a good example of why you should never depend on undefined behavior behaving the way you expect.

Related

Why does this conditional cause an error?

I have a method that contains a few conditionals. The first conditional works fine and does not cause any problems. However, the second one causes the app to crash.
- (void)didReceiveGaiaGattResponse:(CSRGaiaGattCommand *)command
{
GaiaCommandType cmdType = [command getCommandId];
NSData *requestPayload = [command getPayload];
uint8_t success = 0;
NSLog(#"cmdType: %li", (long)cmdType);
[requestPayload getBytes:&success range:NSMakeRange(0, sizeof(uint8_t))];
if (cmdType == GaiaCommand_GetCurrentBatteryLevel && requestPayload.length > 1)
{
uint16_t value = 0;
[requestPayload getBytes:&value range:NSMakeRange(1, sizeof(uint16_t))];
NSInteger battery = CFSwapInt16BigToHost(value);
[self sendEventWithName:someDEVICE_BATTERY_CHANGED body:#{#"batteryLevel":[NSNumber numberWithInteger:battery]}];
return;
}
else if (cmdType == GaiaCommand_GET_FBC && requestPayload.length > 1)
{
uint16_t value = 0;
[requestPayload getBytes:&value range:NSMakeRange(1, sizeof(uint16_t))];
NSInteger feedbackCancellationMode = CFSwapInt16BigToHost(value);
[self sendEventWithName:FEEDBACK_CANCELLATION_MODE body:#{#"feedbackCancellationMode": [NSNumber numberWithInt:feedbackCancellationMode]}];
return;
}
//do more stuff
}
The conditional
if (cmdType == GaiaCommand_GetCurrentBatteryLevel &&
requestPayload.length > 1)
works without problems.
However, the conditional
else if (cmdType == GaiaCommand_GET_FBC && requestPayload.length > 1)
causes the following warning in xcode
Implicit conversion loses integer precision: 'NSInteger' (aka 'long')
to 'int'
In addition, I also saw the error message in the debugger
* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[_NSInlineData getBytes:range:]: range {1, 2} exceeds
data length 2'
Consider what this is telling you:
Terminating app due to uncaught exception 'NSRangeException', reason:
'-[_NSInlineData getBytes:range:]: range {1, 2} exceeds data length 2'
Your data object is 2 bytes in length. The first byte, at position 0, is (according to your code) the success value. That leaves one more byte at position 1 to handle. But your code is attempt to copy 2 bytes out of it — that's the range {1, 2} in the message; a range starting at position 1 and with a length of 2. You're reading past the end of the data.
You have to check that the data has enough data to satisfy the -getBytes:... call you're attempting to make. You may also need to correct your assumptions about how large the cancellation mode value in the buffer is supposed to be, because it's apparently smaller than you expect. Your code assumes it's a uint16_t (2 bytes) but there's only one byte left in the data.
[NSNumber numberWithInt:feedbackCancellationMode]}]
should be
[NSNumber numberWithInteger: feedbackCancellationMode]}]

SC_METHOD Exception

I'm trying to use a SC_METHOD in my simulation. Here is the code:
gcrypt::gcrypt(sc_module_name name):
gcrypt_base(name)
{
SC_METHOD(on_clock_update);
sensitive << clock;
dont_initialize();
};
void gcrypt::on_clock_update()
{
if (clock.read() == 0)
{
SC_REPORT_WARNING(name(), "Invalid clock port value of 0");
_ns_per_cycle = 0;
return;
}
_ns_per_cycle = 1e9 / clock.read();
}
The gcrypt_base constructor is:
gcrypt_base::gcrypt_base(sc_module_name name) :
sc_module(name),
...
{
...
}
I get this exception thrown by SC_METHOD:
Exception thrown at 0x6FB78281 (vcruntime140d.dll) in
SystemCModuleTest.exe: 0xC0000005: Access violation reading location
0x115348EF.
I saw the __vfptr value was "Unable to read memory".
How to solve this problem?
I believe you haven't specified the /vmg option while compiling your code. The /vmg option is required because of the way SystemC implements method processes.

EXC_BAD_ACCESS when reading 9 characters, but works with less than 9

I'm developing a console app in Objective-C. I've got it working, but when manually testing edge cases, I found a strange behavior that I can't explain.
Basically, I've set up scanf() in a loop, and when the user types invalid info, it prints an "invalid option" message. Then, if the input is less than 9 characters long, it goes through the loop again as intended. But, if the input is 9 characters or longer, it gives a EXC_BAD_ACCESS error on a certain line.(This error doesn't happen if I comment out said line.)I can't figure out any reason why 8 vs 9 characters being read would cause this error. Any ideas?
Below are the two methods that I figure are relevant, with a comment on the line throwing the error. If you think other referenced code may be causing this, let me know and I'll add that code.
-(void)startMenu {
printf("\nGAME OPTIONS\n| WinningScore = %d (w) | Name = %s (n) | Back (b) |\n",
_options.winningScore, [_options.name UTF8String]);
}
-(void)start {
char selectedOption;
char w = 'w';
char n = 'n';
char b = 'b';
while(YES) {
[self startMenu]; // This line gets the EXC_BAD_ACCESS error
// if the user puts in 9 or more characters.
// If it is commented out, then no error is thrown.
scanf("%s", &selectedOption);
if(selectedOption == w) {
[self setWinningScore];
} else if(selectedOption == n) {
[self setName];
} else if(selectedOption == b) {
break;
} else {
printf("'%s' is not a valid option.\n", &selectedOption);
}
}
}
It this was C (and the post is tagged C) I'd suggest:
char selectedOption;
....
scanf(" %c", &selectedOption);
...
printf("'%c' is not a valid option.\n", selectedOption);
The failure showing up after a 9 charterer input is serendipity. scanf("%s", &selectedOption); is certainly wrong for reading a single character. Any input starts causing problems. Use the matching format specifier and variable.
[Edit]
A C-like solution.
If more than 1 char is desire for input, use the idea put forth by #Devolus. Example:
char selectedOption[10];
if (fgets(selectedOption, sizeof selectedOption, stdin) == NULL)
Handle_EOForIOerror();
// Get rid of potential trailing \n if desired.
size_t len = strlen(selectedOption);
if (len > 0 && selectedOption[len-1] == '\n') selectedOption[--len] = '\0';
You should use fgets instead of scanf here, as you can limit the number of characters in the buffer.
scanf is potentially unsafe because the buffer can be exceeded.

NSObject description and custom summaries in Xcode

I override object's -(NSString*)description however Xcode always displays error: summary string parsing error in summary field in variables view.
My current implementation is the following:
- (NSString*)description {
return [NSString stringWithFormat:#"<%# %p> x=%f, y=%f", self.class, self, _x, _y];
}
If I type po objectName in console, LLDB shows a fine output as expected, however Xcode and command p objectName always indicate error, so what's the proper debug description format to make summary field work? Worth to notice that the output of "p" command is the same as a summary message that you see in Xcode for instances of Foundation classes.
Update:
As far as I can see from "WWDC 2012 session Debugging in Xcode", custom summaries can be implemented using Custom python script only. -(NSString*)description or -(NSString*)debugDescription methods are not connected anyhow to summary messages. I thought they are because I got an error displayed, but it seems it's a standard message for classes that do not have their own formatters.
I would suggest at least:
- (NSString*)description {
return [NSString stringWithFormat:#"%#; x=%f, y=%f", [super description], _x, _y];
}
So that you're not manually replicating the NSObject default and thereby blocking any non-default behaviour your superclass may have opted to include.
Beyond that, "summary string parsing error" is an lldb error. It's being reported by the debugger only. Per its documentation, po is correct for Objective-C objects; p is for C or C++ objects. So you needn't heed that error — it's essentially just telling you that you used the wrong lldb command.
EDIT: for what it's worth, the method used by CFArray is open source and looks like:
static CFStringRef __CFArrayCopyDescription(CFTypeRef cf) {
CFArrayRef array = (CFArrayRef)cf;
CFMutableStringRef result;
const CFArrayCallBacks *cb;
CFAllocatorRef allocator;
CFIndex idx, cnt;
cnt = __CFArrayGetCount(array);
allocator = CFGetAllocator(array);
result = CFStringCreateMutable(allocator, 0);
switch (__CFArrayGetType(array)) {
case __kCFArrayImmutable:
CFStringAppendFormat(result, NULL, CFSTR("<CFArray %p [%p]>{type = immutable, count = %u, values = (%s"), cf, allocator, cnt, cnt ? "\n" : "");
break;
case __kCFArrayDeque:
CFStringAppendFormat(result, NULL, CFSTR("<CFArray %p [%p]>{type = mutable-small, count = %u, values = (%s"), cf, allocator, cnt, cnt ? "\n" : "");
break;
}
cb = __CFArrayGetCallBacks(array);
for (idx = 0; idx < cnt; idx++) {
CFStringRef desc = NULL;
const void *val = __CFArrayGetBucketAtIndex(array, idx)->_item;
if (NULL != cb->copyDescription) {
desc = (CFStringRef)INVOKE_CALLBACK1(cb->copyDescription, val);
}
if (NULL != desc) {
CFStringAppendFormat(result, NULL, CFSTR("\t%u : %#\n"), idx, desc);
CFRelease(desc);
} else {
CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p>\n"), idx, val);
}
}
CFStringAppend(result, CFSTR(")}"));
return result;
}
As with the other comments above, I'm willing to gamble that the answer is: Xcode's debugger isn't smart in any sense and definitely isn't smart enough to use the correct po means of getting an Objective-C description; if your object is an uninflected Objective-C object then the debugger isn't going to be able to figure it out.

array index blows up obj c

I am writing an iPhone app in Xcode 4.6.3.
I don't really know how to ask this question, but during operation, an array index goes from 0, which is hardcoded in a method, to 58911 for some reason. The chain is:
- (void)syncInitialState
{
[self syncState:0]; //value starts hardcoded here
}
then:
- (void)syncState:(int)index
{
self.state = [macrostate getState:index];
[self syncState];
}
in Macrostate:
- (NPState *)getState:(int)index
{
int *singleArray = {&index};
NSPointerArray *pointerArray = [self subsetFromIntArray:singleArray];
return (__bridge NPState *)[pointerArray pointerAtIndex:0]; //only one object
}
finally:
- (NSPointerArray *)subsetFromIntArray:(int *)intArray
{
NSPointerArray *subset = [NSPointerArray strongObjectsPointerArray];
for (int i=0; i<sizeof(intArray); i++) {
[subset addPointer:[pointerArrayOfStates pointerAtIndex:intArray[i]]]; //fails
}
return subset;
}
Obviously it fails because 58911 is outside the bounds of the pointer array. I have never seen this before. Thanks for reading.
It might help to know that the error is: * Terminating app due to uncaught exception 'NSRangeException', reason: ' -[NSConcretePointerArray pointerAtIndex:]: attempt to access pointer at index 58911 beyond bounds 4' ** First throw call stack: (0x1caa012 0x10e7e7e 0x1ca9deb 0xb1c1ab 0xd8ae 0xd7a5 0x47c6 0x485e 0x567f 0x5d95 0x2d3f 0x10d1c7 0x10d232 0x5c3d5 0x5c76f 0x5c905 0x65917 0x29c5 0x29157 0x29747 0x2a94b 0x3bcb5 0x3cbeb 0x2e698 0x1c05df9 0x1c05ad0 0x1c1fbf5 0x1c1f962 0x1c50bb6 0x1c4ff44 0x1c4fe1b 0x2a17a 0x2bffc 0x26fd 0x2625) libc++abi.dylib: terminate called throwing an exception
You can't use sizeof to get the length of the int array. You need to add a "length" parameter to your subsetFromIntArray: method and use that instead of sizeof.