EXC_BAD_INSTRUCTION when using NSRunAlertPanel - objective-c

To show errors on some condition, I am using NSRunAlertPanel on Mac OS X (on the code which is ported from Windows, where I was using MessageBox).
Before actual creation of Windows, some code is being run and calling this code to show some conditional error.
In a thread com.apple.libdispatch-manager, under following call stack
0 _dispatch_mgr_invoke
1 _dispatch_mgr_thread
it is giving EXC_BAD_INSTRUCTION
Is it because Windows is not created before NSRunAlertPanel?
What is the reason of this runtime error? What is exact alternative of MessageBox on Mac OS X?
Long ShowDebugMessageBox (const wchar_t * Message, const wchar_t * Title)
{
NSString * message; ///< Message.
NSString * title; ///< Title.
NSInteger response; ///< response.
message = WideToNSString (Message);
title = WideToNSString (Title);
//response = NSRunAlertPanel(title, message, #"Yes", #"No", #"Cancel");
response = NSRunCriticalAlertPanel (title, message, #"Okay", #"Cancel", nil);
switch(response) {
case NSAlertDefaultReturn:
return IDYES;
case NSAlertAlternateReturn:
return IDNO;
default:
return IDCANCEL;
}
}
NSString * WideToNSString (const wchar_t * Str)
{
if(!Str) {
return nil;
}
NSString * str; ///< String in NSString.
#if CP_SIZEOFWCHAR == 4
str = [[NSString alloc] initWithBytes: (CVPtr) Str
length: sizeof(wchar_t)* wcslen(Str)
encoding: NSUTF32LittleEndianStringEncoding];
//encoding: NSUTF32StringEncoding];
#else
str = [[NSString alloc] initWithBytes: (CVPtr) Str
length: sizeof(wchar_t)* wcslen(Str);
encoding: NSUTF16LittleEndianStringEncoding];
//encoding: NSUTF16StringEncoding];
#endif
return str;
}
class File {
public:
int Open(char * fname, int mode)
{
fd = open(fname, mode);
}
int Close()
{
close(fd);
//fd = 0; //CAUSE of the PROBLEM
}
~File ()
{
//ALERT Display message box about the error.
ALERT(fd != 0);
}
private:
int fd;
};
This is the code to show the message box.
Code to get NSString from wchar_t * string (Wide string) is perfectly fine and was tested. It is used in many places and running fine.
Same code on the other application (which creates Window first) is running fine.
Problem occurs when the destructor of File is called. Since fd is not 0, it shows message box and cause the problem.
When fd is set to 0, no alert box is displayed for constructor. However, other alert are shown but no problem occurred.
Is it due fd?

You haven't provided enough information to say what is causing the exception (please show the code).
I use NSRunCriticalAlertPanel() to display fatal errors in my app, which I am able to call pretty much any time I like:
void criticalAlertPanel(NSString *title, NSString *fmt, ...)
{
va_list va;
va_start(va, fmt);
NSString *message = [[NSString alloc] initWithFormat:fmt arguments:va];
va_end(va);
NSRunCriticalAlertPanel(title, message, #"OK", nil, nil);
}
(this code is ARC enabled).

Related

Programmatically creating an ad-hoc network in Big Sur

Before Mac OS Big Sur, one could create an ad-hoc network by calling the startIBSSModeWithSSID:security:channel:password:error: function of a CWInterface obtained from a CWWifiClient. It seems that after an update to Big Sur, the above function is deprecated and throws a kCWOperationNotPermittedErr (-3930) error every time.
I tried launching the application from root, and it still refused to create an ad-hoc network. Meanwhile, using the "Create Network" option in the WiFi dropdown menu works with an administrator password.
A previous answer on this site I have come across is outdated and the code does not work anymore. There is a post on the Apple Developer forums created 5 months ago but it remains unanswered, with the "solution" being to file a tech support incident.
This is the code I am using:
#import <Foundation/Foundation.h>
#import <CoreWLAN/CoreWLAN.h>
#import <SecurityFoundation/SFAuthorization.h>
#import <objc/message.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
bool success = 0;
CWWiFiClient* wifiClient = [CWWiFiClient sharedWiFiClient];
CWInterface* interface = [wifiClient interface];
NSString* namestr = #"very_creative_ssid";
NSData* name = [namestr dataUsingEncoding:NSUTF8StringEncoding];
NSString* pass = #"very_cruel_framework"; // not used
NSError* err = nil;
success = [interface startIBSSModeWithSSID:name
security:kCWIBSSModeSecurityNone
channel:11
password:nil
error:&err];
if (!success) {
NSLog(#"%#", err);
return 1;
}
[NSRunLoop.currentRunLoop run];
}
return 0;
}
Is there a way to programmatically create an ad-hoc network in Big Sur without throwing an error?
Edit: Here is the console output (1 line):
2022-01-12 05:25:03.723 cwlantest[15305:448617] Error Domain=com.apple.coreWLAN.error Code=-3930 "(null)"
I'm going to put this as an answer, if anyone finds anything new or Apple adds this feature in the future, I'll be very happy to be wrong.
TLDR: Not anymore!
Since Apple removed the "Create network..." option from the wifi menubar, the only way to create an ad-hoc network is through Network Sharing. I followed https://www.makeuseof.com/how-to-create-a-secure-ad-hoc-network-in-macos/ under the How to Create a Secure Ad Hoc Network section to make a network:
sudo networksetup -createnetworkservice AdHoc lo0
sudo networksetup -setmanual AdHoc 192.168.1.88 255.255.255.255
And in System Preferences, share your network connection from AdHoc over WiFi.
With that on, I checked the CWInterface.interfaceMode() and it was in HostAP mode. Pure speculation, but I think IBSS was removed completely, it's marked as Deprecated in the developer documentation. -3930 is kCWOperationNotPermittedErr, so I'm not 100% sure that's accurate, but it's possible.
There are private interfaces to set HostAP mode in CoreWLAN:
https://github.com/onmyway133/Runtime-Headers/blob/master/macOS/10.13/CoreWLAN.framework/CWInterface.h https://medium.com/swlh/calling-ios-and-macos-hidden-api-in-style-1a924f244ad1 https://gist.github.com/wolever/4418079
After replacing objc_msgsend with NSInvocation in the last link since objc_msgsend seems to have been removed:
#import <CoreWLAN/CoreWLAN.h>
#import <objc/message.h>
int main(int argc, char* argv[]) {
#autoreleasepool {
int ch;
NSString *ssid = nil, *password = nil;
while((ch = getopt(argc, argv, "s:p:h")) != -1) {
switch(ch) {
case 's':
ssid = [NSString stringWithUTF8String:optarg];
break;
case 'p':
password = [NSString stringWithUTF8String:optarg];
break;
case '?':
case 'h':
default:
printf("USAGE: %s [-s ssid] [-p password] [-h] command\n", argv[0]);
printf("\nOPTIONS:\n");
printf(" -s ssid SSID\n");
printf(" -p password WEP password\n");
printf(" -h Print help\n");
printf("\nCOMMAND:\n");
printf(" status Print interface mode\n");
printf(" start Start Host AP mode\n");
printf(" stop Stop Host AP mode\n");
return 0;
}
}
NSString *command = nil;
if(argv[optind]) {
command = [NSString stringWithUTF8String:argv[optind]];
}
CWInterface *iface = [[CWWiFiClient sharedWiFiClient] interface];
if(!command || [command isEqualToString:#"status"]) {
NSString *mode = nil;
switch(iface.interfaceMode) {
case kCWInterfaceModeStation:
mode = #"Station";
break;
case kCWInterfaceModeIBSS:
mode = #"IBSS";
break;
case kCWInterfaceModeHostAP:
mode = #"HostAP";
break;
case kCWInterfaceModeNone:
default:
mode = #"None";
}
printf("%s\n", [mode UTF8String]);
} else if([command isEqualToString:#"stop"]) {
// Stop Host AP mode
if(getuid() != 0) {
printf("this may need root (trying anyway)...\n");
}
SEL selector = #selector(stopHostAPMode);
NSMethodSignature *signature = [iface methodSignatureForSelector: selector];
NSInvocation *invocation =
[NSInvocation invocationWithMethodSignature:signature];
invocation.target = iface;
invocation.selector = selector;
[invocation invoke];
printf("Done?");
//objc_msgSend(iface, #selector(stopHostAPMode));
} else if([command isEqualToString:#"start"]) {
if(!ssid) {
printf("error: an ssid must be specified\n");
return 1;
}
// known security types:
// 2: no securiry
// 16: wep
// Note: values [-127..127] have been tried, and all but these return errors.
unsigned long long securityType = 2;
if(password) {
if([password length] < 10) {
printf("error: password too short (must be >= 10 characters)\n");
return 1;
}
securityType = 16;
}
NSSet *chans = [iface supportedWLANChannels];
//printf("chan count: %lu\n", [chans count]);
NSEnumerator *enumerator = [chans objectEnumerator];
CWChannel *channel;
while ((channel = [enumerator nextObject])) {
//printf("channel: %lu\n", [channel channelNumber]);
if ([channel channelNumber] == 11)
break;
}
printf("Found Channel: %d\n", channel.channelNumber);
// Start Host AP mode
NSError *error = nil;
NSError **errorptr = &error;
SEL selector = #selector(startHostAPModeWithSSID:securityType:channel:password:error:);
NSMethodSignature *signature = [iface methodSignatureForSelector: selector];
NSInvocation *invocation =
[NSInvocation invocationWithMethodSignature:signature];
invocation.target = iface;
invocation.selector = selector;
NSString * ssidstr = #"Test";
NSString * pass = #"barbarbarr";
NSData * ssidArg = [ssidstr dataUsingEncoding:NSUTF8StringEncoding];
[invocation setArgument: &ssidArg atIndex:2];
[invocation setArgument: &securityType atIndex:3];
[invocation setArgument: &channel atIndex:4];
[invocation setArgument: &pass atIndex:5];
[invocation setArgument: &errorptr atIndex:6];
[invocation invoke];
BOOL success;
[invocation getReturnValue:&success];
if (!success) {
printf("startHostAPModeWithSSID error: %s\n", [(*errorptr).localizedDescription UTF8String]);
return 1;
} else {
printf("Success?\n");
return 0;
}
}
return 0;
}
}
./hostap stop does successfully kick me out of hostap mode started from network sharing, but ./hostap start fails with -3903 kCWNotSupportedErr.
Also, using startHostAPMode: without other settings does succeed, but the wifi menu shows WiFi: Internet Sharing, so I think this is a private api meant specifically for network sharing and will likely need other configuration to get working. You could potentially continue down that road, but it didn't look very promising. The best bet is to just use network sharing or potentially look into scripting System Preferences with AppleScript if you really want a scripted approach.

Call to AXIsProcessTrustedWithOptions does not work after change setting value

I am testing accessibility permissions using AXIsProcessTrustedWithOptions.
When app starts, value is correctly returned. However if I change the setting in System Preferences -> Security & Privacy while app is running call to API is still returning the previous value.
Is that a bug?
Here is example code:
bool checkIfAccessibilityEnabledAndDisplayPopup()
{
// Method to check if accessibility is enabled
// Passing YES to kAXTrustedCheckOptionPrompt forces showing popup
NSDictionary *options = #{(bridge id)kAXTrustedCheckOptionPrompt: #YES};
Boolean accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);
return (!!accessibilityEnabled);
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSLog(#"Starting");
for (int i=0;i<100;i) {
checkIfAccessibilityEnabledAndDisplayPopup();
[NSThread sleepForTimeInterval:20.0f];
NSDictionary *options = #{(__bridge id)kAXTrustedCheckOptionPrompt: #NO};
Boolean b = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);
Boolean b1 = AXIsProcessTrusted();
NSLog(#"accessibility AXIsProcessTrustedWithOptions--> %d AXIsProcessTrusted --->
%d", b, b1);
}
}

xcode - alert that shows crash reason

Is there a way to build an alert box that shows what the crash reason is? Specifically, what line of code is causing the crash?
My boss is asking for this, and I haven't found a way to make this possible. I'm going through the analytics tab on the device and finding the crash, but he wants something that populates on the device (it's an internal app) giving the reason for the crash.
Is this possible?
If you want to show an alert when app crashes you can't do that but you can read the crash log when you open the app again after a crash.
You could create a method with following logic, it basically reads back trace for last crash when you open the app again after a crash.
aslmsg q, m;
int i;
const char *key, *val;
float how_old = fTime ;
q = asl_new(ASL_TYPE_QUERY);
asl_set_query(q, ASL_KEY_LEVEL, strLoggerLevel ,ASL_QUERY_OP_LESS_EQUAL);
asl_set_query(q, ASL_KEY_FACILITY, [#"YourBundleIdOfAPP" UTF8String] ,ASL_QUERY_OP_EQUAL);
asl_set_query(q, ASL_KEY_TIME, [[NSString stringWithFormat:#"%.f", [[NSDate date] timeIntervalSince1970] - how_old] UTF8String], ASL_QUERY_OP_GREATER_EQUAL);
int goInside=0;
aslresponse r = asl_search(NULL, q);
while (NULL != (m = aslresponse_next(r)))
{
NSString *cValueToWrite;
NSMutableDictionary *tmpDict = [NSMutableDictionary dictionary];
for (i = 0; (NULL != (key = asl_key(m, i))); i++)
{
//get the only required fields
if(i==12 || i==10 || i==11 || i==8 || i==9 ||i==3)
{
NSString *keyString = [NSString stringWithUTF8String:(char *)key];
val = asl_get(m, key);
NSString *string = [NSString stringWithUTF8String:val];
[tmpDict setObject:string forKey:keyString];
}
}
cValueToWrite=[[NSString alloc]initWithFormat:#"\n--------------[Debug]----------------\nDateTime: %#\nApplication: %#\nInfo: %#",[tmpDict valueForKey:#"CFLog Local Time"],[tmpDict valueForKey:#"Sender"],[tmpDict valueForKey:#"Message"]];
}
strLoggerLevel is the NSString which hold the logger type which you want which ranges upto 7

Why do i get "program received signal: "EXC_BAD_ACCESS" on NSString veriable

I just recently started learning Objective C, when i run the next program i get error
"program received signal: "EXC_BAD_ACCESS"
For the code line
if([*userChoice isEqualToString:#"yes"])
The full code is:
void initGame (void);
void restartGame(void);
void toGoOn(char *playerChoice);
int guess=-1;
int from=-1;
int to=-1;
bool playStatus=true;
bool gameStatus=true;
int answer=-1;
NSString *userChoice[10];
//if true the game is on
int main (int argc, const char * argv[])
{
#autoreleasepool {
GuessManager *game=GUESS;
NSLog(#"Hello, lets play");
NSLog(#"Please provide a positive range in which you would like to play");
do{
initGame();
[game setnumberToGuess:from :to];
do {
printf("Make you guess:");
scanf("%d", &guess);
[game setUserGuess:guess];
[game checkUserGuess];
if([game getDidIgetIt])
{
playStatus=false;
}
else
{
playStatus=true;
}
} while (playStatus);
restartGame();
}while(gameStatus);
printf("Thanks For Playing PanGogi Games! GoodBye");
}
return 0;
}
void initGame (void)
{
printf("from:");
scanf("%d",&from);
printf("to:");
scanf("%d",&to);
}
void restartGame(void)
{
printf("Would you like to continue?(yes/no)");
scanf("%s",&userChoice);
//scanf("%d",&answer);
// if(answer==1)
if([*userChoice isEqualToString:#"yes"])
{
gameStatus=true;
}
else
{
gameStatus=false;
}
}
I understand that its related to the NSString variable userChoice and how its used in
the if, but what i cant find is what am i doing wrong.
Please help :)
You have 3 errors in the code
1) I think you are getting confused with NSString and C style char array... You just need to use single NSString object to save multi character data..
NSString *userChoice;
2) Since you want to input data using scanf, you need a C style character array. scanf won't work with NSString types.
char tempArray[10];
int count = scanf("%s",&tempArray);
userChoice = [NSString stringWithBytes:tempArray length:count encoding: NSUTF8StringEncoding];
3) Now you can use NSString directly.. No need for pointer like syntax
if( [userChoice isEqualToString: #"yes"]){
.....
.....
}
You're using NSString as if it was char. It's not. It's a class that represents a string.
The scanf function is a C function and needs a char array, not an NSString.
char str[80];
scanf("%s", &str);
You can initialize an NSString object with a char array like this:
NSString *userChoice = [NSString stringWithCString:str encoding:NSASCIIEncoding];
And compare like this:
if ([userChoice isEqualToString:#"yes"]) {
...
} else {
...
}

Why does this objective-c exception backtrace show only the last two calls?

Using Xcode (4.3.3 and llvm), I set a breakpoint on all exceptions but often when the breakpoint is hit, the stack looks like this:
(lldb) bt
* thread #1: tid = 0x1c03, 0x31a891c4 libobjc.A.dylib`objc_exception_throw, stop reason = breakpoint 1.1
frame #0: 0x31a891c4 libobjc.A.dylib`objc_exception_throw
frame #1: 0x33a677b8 CoreFoundation`+[NSException raise:format:arguments:] + 100
There's no information about the caller of NSException raise:format:arguments:, the stack just stops there.
Something must have called raise so what happened to the stack? What should I look for to help me debug such issues (e.g. does this indicate some specific type of stack corruption or something else)?
Update: here's the code with the garbage.
The problem was that I accidentally wrote %s when I meant %#. Might have been a bit of a stretch to call that a properly-allocated string but I could "po imageName" in the llvm console, it just had some garbage at the end.
NSString *imageName = [NSString stringWithFormat:#"award_%s", award];
UIImage *image = [UIImage imageNamed:imageName];
[_awardIconMapping setObject:image forKey:award];
There was no thread #0 by the time the exception was hit. Using #try/#catch, I get a sensible exception from the last line (sorry, I thought it was the image= line before):
2012-07-06 10:43:36.184 CallVille[834:707] ****** Hit exception ********
-[__NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: wiseGuy)
I use this function to print the stack traces from a NSException:
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
+ (void) printStackTrace: (NSException*) e
{
NSArray * addresses = [e callStackReturnAddresses];
if( [addresses count])
{
void * backtrace_frames[[addresses count]];
int i = 0;
for (NSNumber * address in addresses)
{
backtrace_frames[i] = (void *)[address unsignedLongValue];
i++;
}
char **frameStrings = backtrace_symbols(&backtrace_frames[0], [addresses count]);
if(frameStrings != NULL)
{
int x;
for(x = 0; x < [addresses count]; x++)
{
NSString *frame_description = [NSString stringWithUTF8String:frameStrings[ x]];
NSLog( #"------- %#", frame_description);
}
free( frameStrings);
frameStrings = nil;
}
}
}