NSDictionary alloc crash

SD crashed when running the script at the end of this post. The new part of the script was the 2 lines:

set TheDictionary2 to current application's NSDictionary's alloc()
return TheDictionary2

As soon as I entered these lines and clicked the run button SD crashed. Nothing showed up in the console.

I included 4 files with this post:
Uncaught excepotion.txt.zip
Apple crash report.txt.zip
Script debugger crash report.txt.zip
Dictionary.scpt.zip

Uncaught excepotion.txt.zip is the error output that came from clicking the “Show Details” button on the internal error dialog in SD.

Dictionary.scpt.zip is the actual script that causes the crash.

use AppleScript version "2.3.1"
use scripting additions

use framework "AppKit"
use framework "Foundation"


(*
	The NSDictionary class is Objectice-C's AppleScripts's equivalent of the record class.
	NSDictionary objects allow data for a specified dictionary entry to be created, stored, read, modified and deleted through the use of unique keys.
	When a new dictionary entry is created both the key and data associated with that key are created.  The presence of these keys is the major
	characteristic that diferenciates a dictionary from an array.  Dictionaries can be mutable or immutable.
	Each key-value pair in the dictionary is called an entry.  All the keys in a dictionary must be unique. All keys must be up type string.
*)

-- Once a specific key-value pair has been entered into a dictionary that dictionary entry can not be modifed later
set ImmutableDictionary to current application's NSDictionary's alloc()'s init() --> (NSDictionary) {}  (Creates a new, empty immutable dictionary)
set MutableDictionary to current application's NSMutableDictionary's alloc()'s init() --> (NSDictionary) {} (Creates a new, empty mutable dictionary)

set TheDictionary1 to current application's NSDictionary's dictionaryWithObjects:{"value1", "value2", "value3", "value4"} forKeys:{"key1", "key2", "key3", "key4"} --> (NSDictionary) {key3:"value3", key1:"value1", key4:"value4", key2:"value2"}

-- A dictionary can also be created using arrays
set TheValues to current application's NSArray's arrayWithArray:{"v1", "v2", "3", "v4"} --> (NSArray) {"v1","v2","3","v4"}
set TheKeys to current application's NSArray's arrayWithArray:{"k1", "k2", "k3", "k4"} --> (NSArray) {"k1","k2","k3","k4"}

set TheDictionary2 to current application's NSDictionary's alloc()
return TheDictionary2
TheDictionary2's initWithObjects:TheValues forKeys:TheKeys


-- set TheDictionary3 to NSDictionary("key1":" object1", "key2": "object2", "key3": "object3")

set TheDictionary3 to current application's NSDictionary's dictionaryWithDictionary:TheDictionary1

TheDictionary3

Uncaught excepotion.txt.zip (1.5 KB)
Apple crash report.txt.zip (1.5 KB)
Script debugger crash report.txt.zip (34.4 KB)

Dictionary.scpt.zip (7.5 KB)

I’m not surprised – you should never alloc an item and not immediately init it – that’s why they’re always done on the same line in Objective-C code.

IMO you’re better off avoiding alloc in AppleScriptObjC where it’s not needed – it’s more efficient to use convenience class methods where they’re available. For example, you can create an empty mutable dictionary using dictionary(). Where you have no choice, always do alloc and init together.

This is particularly important in the case of class clusters like NSDictionary.

Let me clarify a bit further. The crash is probably being triggered by the return statement. But if you remove it, you’re still likely to have a crash.

The problem is that init can – and in the case of dictionaries always will – return a different object than it was passed. So alloc might produce an NSDictionary, but depending on the method used, init will return a instance of a subclass of NSDictionary. But the way your code is written, you never capture that instance in a variable – your TheDictioanry2 is still pointing to something else, which may no longer even exist.

I’ve been trying new things as I’m going through learning about ASObj-C. I only reported the error because SD crashed and crashing is not the best response. I figured Mark might be able to display the error in a dialog without crashing. At the time I wasn’t thinking of asking for advice. I was just posting something that made SD crash.

I came across something on the net where the programmer created a dictionary differently then I usually do. So I tried it and it crashed. I thought it was because I accidentally put the “return TheDictionary2” before the line with initWithObjects. But it also crashed with the lines ordered as following.

set TheDictionary2 to current application's NSDictionary's alloc()
TheDictionary2's initWithObjects:TheValues forKeys:TheKeys
return TheDictionary2

Then I posted the crash before moving on. While pondering the problem I got your very quick response and did what you said and putting it it all in 1 line and it worked.

set TheDictionary2 to current application's NSDictionary's alloc()'s initWithObjects:TheValues forKeys:TheKeys

Sorry, it was not my attention to post a call for help without first trying to figure the problem out. But with that said I appreciate the assistance. I would have tried a lot of things before trying that.

Bill

I understand, but Script Debugger can’t stop this sort of low-level crash. In the words of the 10.10 AppleScript Release Notes:

Warning: Using Objective-C frameworks from AppleScript provides many new and exciting opportunities to crash the host process.

Shane,

I’ve always been a bit unsure what actually crashes when I make an error coding with ASObj-C. It’s called ASObj-C but when I run the script it doesn’t interface with Objective-C. When it comes right down to it Objective-C has nothing to do with it except for some some syntactic decisions in the ASObj-C programming interface. ASObj-C interfaces with cocoa frameworks through the bridge. So when I messed up the initialization of a cocoa dictionary object does that crash part of Cocoa? I’ve suspected when I work with ASObj-C I’m more working with a copy of things and each time I run the script it starts new and uncorrupted unless I do something that seriously corrupts the OS. Is that more or less true?

Also I assume I should still report all ASObj-C crashes or other problems. I’m nowhere near as qualified as you and Mark to know what can be fixed and what can’t.

Bill

AppleScript tries to trap exceptions where it can. For example, if you enter a method name incorrectly, it traps the unrecognized selector error. But AppleScriptObjC works in part by using the Objective-C runtime to create a Cocoa instance that hosts your script. That instance belongs to the host, in this case Script Debugger, and if it’s programmed wrongly, it can crash Script Debugger just the same as if it were Script Debugger’s own code.

For example, run this:

use framework "AppKit"
current application's NSApp

That returns a pointer to Script Debugger itself, and you can freely call methods on it. If you call stop:, that’s what will happen.

So you’re potentially operating at a very low level, and there’s no safety net.

Definitely. Just don’t be surprised if the answer in some cases is to change your code. That’s just the nature of the beast.

I didn’t know AStObj-C calls to cocoa frameworks accessed Objective-C runtime to create Cocoa instances. I always looked at that part of the process as magic happen here stuff. Objective-C itself can make a real mess when coded wrong and making a real big mess is even easier with Objective-C runtime.

Every time I have a crash I report it and change my code to get around the crash. Mark has always done a great job with fixing problems, as you also do now. But few companies are that responsive. So I got into that habit a log time ago. I just report problems and move on.

Bill

And we will continue to be as responsive as we can. But as Shane has said, when it comes to ASObjC, our response will sometimes be that you need to code your script differently.

It is unfortunate that ASObjC errors lead to Script Debugger crashes because it reflects poorly on Script Debugger, but there isn’t anything we can do. In the future, I hope to re-engineer Script Debugger to run all scripts in their own process. This will insulate Script Debugger from script-induced errors (and address some ASObjC threading issues). The script may still crash, but Script Debugger will stay up and be able to report some information about the crash (Objective-C stack trace, etc.).

This change represents a total re-write of the script execution environment within Script Debugger and so isn’t something we can do quickly.

Mark,

Actually I’ve never heard anyone complain about ASObj-C crashing SD. A lot of people are like me in that I don’t know how AS and Cocoa interface works but understand something complicated is going on and more than SD is involved. When Shane told me it accesses runtime Objective-C to get an instance of a class then I understood how dangerous ASObj-C can be.

As I think about it now code completion, clippings and to some extent even well chosen text substitutions are about the best protection SD6 can have against ASObj-C mishaps. I would guess that’s why I don’t hear about ASObj-C related crashes that much from SD6 users. If I used Script Editor I would get into a lot more trouble. I only got into trouble while using SD6 this time because I tried to access data before I did the init and I didn’t understand that alloc & init have to be on the same. I’ll never make that mistake again.

So all things considered I really like ASObj-C and I love the way it is implemented in SD6. Using a 5 star rating system I’d give SD6 10 gold stars :slight_smile:

Bill

1 Like