Navigation
Monday
Jun162014

The Case for Message Passing in Swift

Update: Chris Lattner has asked developers to not file duplicate radars for feature requests. Please do not duplicate any radars listed in this post.

Apple introduced Swift as "Objective-C without the C", but in many ways, Swift is closer to "C++ without the C" (or Objective-C without the Smalltalk). Swift's generics, for example, are closer to C++'s templates than to any feature of Objective-C. One of the more subtle ways that Swift resembles C++ is in how it calls methods. Unlike Objective-C, where methods are called using message passing, Swift uses a vtable for method dispatch, and when the compiler has enough information, inlines the function call directly. While this improves performance over message passing, it trades power and flexibility for performance gains that aren't necessary for most apps.

In this article, I will present use cases which are currently impossible or difficult to implement without message passing. For each of these cases, I have filed radars asking for support in Swift. That way, even if message passing is not added to Swift, support for these other use cases may be added. There is also a radar requesting message passing. If you have any use ceases for message passing not covered in this article, please include them in your radar, and let me know and I'll update this article with links to your use cases, but please do not file duplicates of the radars in this article.

A Small Note on Binary Compatibility

At WWDC, Apple promised that although Swift's syntax may change, the code you write now will be "binary compatible" with Swift in the future. Binary compatibility might make radical changes, like switching to message-passing, impossible. However, I don't think "binary compatibility" in this case means that Swift frameworks written today will work with future Swift code. The Swift runtime and standard library is linked into all Swift apps: the OS does not include either. Some of the Swift developers have already indicated that they plan to make major changes to the language, like adding access modifiers. By "binary compatibility", I believe Apple means that apps compiled today will continue to run in the future. As such, I don't think binary compatibility precludes adding message passing.

Background

Objective-C began as a fusion of C and Smalltalk. It was an attempt to balance high-level, object-oriented features with the performance of a low-level language like C. C calls functions directly, as the compiler knows the exact address of the function to call. Objective-C added Smalltalk-style message passing, which determines the function to call at runtime. Each class contains a dictionary mapping selectors to function addresses. When an instance of a class is sent a message, it looks up the address that corresponds to the message's selector, and calls the function at this address.

C++ classes, on the other hand, use vtables to handle dynamic dispatch. By the name, you might think a vtable is similar to the dictionary used in message passing, but vtables are usually just arrays of function pointers. The vtable is constructed at compile time, and functions are inserted into the vtable in the order they are declared. The compiler then translates message calls into vtable lookups. For example, someInstance->foo() might be translated to someInstance->vtable[3]().

Because the compiler must know how to translate a method call into the proper vtable index, the vtable must be known at compile time, and cannot change at runtime. In contrast, the message passing dictionary can be modified at runtime, and its possible to send messages to a class which are not in its message passing dictionary, though you may trigger a runtime exception by doing so. This allows you to send messages that aren't known at compile-time, and enables some powerful metaprogramming features.

Swift utilizes all three approaches. Swift classes that inherit from Objective-C classes will use message passing. Other classes will use vtables, except in cases where the compiler has enough information to call the method directly. Since Cocoa is still written in Objective-C, apps written in Swift will use message passing a large percentage of the time.

Safety First

In all of the Swift presentations and documentation released at WWDC, Apple stressed that Swift is "safe by default", unlike Objective-C. Since Objective-C was based on C, Objective-C objects were mostly just raw C pointers. This allowed programmers to write data corruption, crashing, and security bugs by not performing correct boundary checks. The most famous example of such a bug is the Heartbleed bug which compromised the security of most servers on the Web. When the swift compiler can detect an out-of-bounds access, it will throw an error. At runtime, an out-of-bounds access will trigger a crash. Swift references are even non-nullable by default, helping developers to avoid the billion-dollar mistake.

One of the ways that Swift practices this "safety-first" mentality is through type safety. Whereas Objective-C was a dynamically-typed language with optional static typing, Swift, like C++, is a statically-typed language with the ability to ignore type information when necessary. This is partially due to the history of Objective-C. In its infancy, the only object type was id. Partially due to this, selectors have never encoded type information, making it possible to send a message to an object with arguments of the incorrect type. This can open security holes, corrupt data, or cause a crash.

If Swift were to adopt message passing, it could do so in a way that encoded static type information into the message. This would be slower than Objective-C message passing, but it would probably be fast enough. Message passing is much slower than a C++ virtual method call, but message passing is rarely the bottleneck in Objective-C code, and when it is, there are optimizations like IMP caching that can be used to speed up critical code. Objective-C has powered rich, fast, and smooth interactions on iOS for alost 7 years, while Android still struggles with garbage-collection and JIT-induced slowdowns. There are certain areas (e.g. high-end games, signal processing) where message passing is truly too slow, but this is not the case for most apps.

Objective-What?

It has been argued that, since Swift and Objective-C have distinct advantages but are interoperable, it's beneficial to have both languages. Microsoft's strategy to have multiple languages which all support the Common Language Runtime means that developers can choose the right language for the job. But Apple is not Microsoft, and maintaining two mainstream languages is a lot of work. Apple is a company that thrives when it is focused on a few things, and it's Apple's culture to provide customers with one best product.

Objective-C isn't going away any time soon, but if Swift succeeds in becoming the dominant language for iOS and Mac development, Objective-C will go away. Eventually the cost of maintaining two languages and runtimes will cease to be worth it. Like Carbon before it, Objective-C will be deprecated, leaving Swift as the only supported language for app development on Apple platforms. In general, I am loathe to argue that my way is the one true way to do things, but since Swift will eventually be the one way to do things, and since now is the time when large changes will be easiest to introduce, I feel compelled to argue that Swift should forswear all but message passing.

Mocks and Other Uses of Message Forwarding

Mock objects are extremely useful for test-driven development. In Objective-C, OCMock implements mock objects through a proxy object. OCMock's partial mocks in particular are a great example of the power of message passing. A partial mock object stores the original object as a property. It then intercepts any messages sent to it, and either forwards the message to the original object or, if the method has been stubbed in the test, returns the stub value instead.

To achieve the same effect in Swift, the mock object would have to implement all of the methods of the original object. Each of these methods would have to test if they have been stubbed, and call the method on the original object. Because classes change over time, it's important to always remember to update the mock object when the class is updated, which is tedious and time-consuming. This can be made better if the class designer designs a protocol that the original class and the mock class both implement. However, since extensions can add methods to classes, this effort is ultimately futile, as a class designer cannot preemptively add extension methods to the mock object.

Another approach would be to subclass the original object and override the stubbed methods. This is the approach that the Google C++ Mocking Framework takes. There are a few problems with this approach. First, subclassing has additional side effects. For example, in Swift, convenience initializers are only inherited if the subclass doesn't have its own designated initializer. If we needed to stub the designated initializer, the convenience initializers would disappear from the mock object. This method also has the disadvantage that a separate subclass must be created for every combination of stubbed methods. In practice, this leads to a large number of mock subclasses, which are mostly just boilerplate code.

The bottom line is that languages with message forwarding implement partial mocks much more completely and cleanly than languages without. I've filed a radar asking for partial mock objects in Swift.

There are, however, many other uses of message forwarding. It's been used to implement something akin to multiple inheritance. It's been used to automatically implement a facade pattern for database access, that updates as the database schema does. It's been used to implement a cancelable editing interface. Each of these things could be implemented without message forwarding, but they would require a lot of glue code that would need to be constantly updated. Message forwarding is a powerful tool that allows us to better decouple our classes and do more with less code.

Method Swizzling or: No Mac is an Island

Method Swizzling is an occasionally-used technique where two method implementations are swapped in the message passing dictionary. If you swizzled two methods, -method1 and -method2, sending a message for method1 would execute -method2, and vice-versa. This technique is not possible with vtables.

Method swizzling is most often used to patch bugs in frameworks, or for plug-ins, to inject code into the host application, without resorting to more dangerous techniques such as mach_override. Before the introduction of base localization, method swizzling was used by many Mac apps to automatically localize nibs. Of course, Apple engineers strongly discourage swizzling methods in Apple's frameworks. Occasionally, it is required to work around a bug or add important functionality, but since Apple is continually fixing bugs and adding features, any solution is temporary. And since Apple strives to not break compatibility with older apps, swizzling their methods makes their job harder. But for frameworks that will never be updated, and for tight deadlines, sometimes swizzling can save a project.

On the Mac, swizzling is used to implement plug-in functionality, even for apps that don't have a plug-in API. This adds features that are very important to power users. Many popular Photoshop and Xcode plug-ins use method swizzling. GPGMail, a plug-in for Mail.app which adds OpenPGP encryption to Mail.app, makes extensive use of method swizzling. This functionality is incredibly important to security-minded individuals, especially in the wake of the Snowden leaks. If Mail.app were rewritten in Swift, this would not be possible.

On iOS, sandboxing prevents this kind of thing, and on OS X, sandboxed apps are more difficult to inject code into. Maybe app extensions will eventually solve the problems that current plug-ins are addressing. Until then, however, the malleability of OS X apps allows plug-ins to be developed for them even when the apps' authors never considered adding plug-in support. For this reason, message passing should be the default for all Swift apps on OS X. Even if an app's author doesn't think they need message passing, it automatically makes their app part of a vibrant third-party ecosystem, which power users consider an irreplaceable part of OS X.

Configuration

Message passing makes it easier to configure your app at runtime. This can help technically-minded designers work faster. One famous story from the development of the original Mac is the Calculator Construction Set. Steve Jobs was unhappy with the design of the Mac's calculator, and kept rejecting changes made by the developer, Chris Espinosa. Chris eventually wrote an application that allowed Steve to configure the calculator at runtime, and Steve was quickly able to come up with a design he liked.

The ability to convert a string containing a method's name to a method call is useful for anyone creating a similar tool, or a DSL, to customize the interface of an app. (Converting strings to classes is another issue beyond the scope of message passing.) Interface Builder can, at compile time, compile action strings to calls to Swift methods, but third party tools can't easily do this. In addition, this kind of customization is useful in NSUserDefaults for changing how an app behaves.

I have filed a radar asking for the ability to convert a string to a method call.

Remote Methods

Objective-C's Distributed Objects have problems, but the basic concept is useful in many situations. Sending a method name from a server to a client app to execute a method on client can make the server and client easy to code and maintain. There are obvious security implications, so the client must be careful of which methods it allows to be executed, but imagine writing an IRC client that converts IRC client commands to method names, and then calls those methods. Then, rather than keeping some kind of mapping from IRC commands to methods, you simply need to add a method for each IRC command you wish to process. This is not only less code, but can also run more quickly than a large if/else or a dictionary lookup.

Runtime Metaprogramming

Most importantly, message passing enables runtime metaprogramming, which while currently not used to solve most problems, is increasingly important to the future of programming. Over the past few decades, developers have programmed using increasingly higher-level abstractions. Since computers excel at automation, the ultimate goal is to tell a computer, in natural language, what a program should do. Metaprogramming is an important step in that direction, as it allows you to write declarative systems that respond to changes at runtime.

Metaprogramming allows you to do a lot of very cool things. In one noteworthy example, Steven G. Harms used metaprogramming to automatically conjugate all Latin verbs for all tenses, voices and moods. Typically, this would require writing thousands of methods, but his implementation only required 24 methods. For many problems, Swift requires fewer lines of code than Objective-C, but for a large number of very interesting problems, runtime metaprogramming allows Objective-C to be much more concise than Swift.

Swift is an opportunity to do metaprogramming right. Objective-C's metaprogramming capabilities are a tad limited compared to languages like Ruby. By making a break from the Objective-C runtime, we have a chance to implement a more complete metaprogramming API. One of Swift's major advantages over Objective-C is its REPL, which allows Swift playgrounds to compile and execute code while the application is running. If that functionality could be exposed to developers with an eval() function, along with functions to modify existing classes, Swift could be a premier language for metaprogramming.

I have filed a radar asking for an eval() function in Swift. There is also a radar asking for runtime introspection and reflection functions, which help enable runtime metaprogramming.

The Big Picture

In the NeXT days, Objective-C was marketed to developers as a way to develop faster in fewer lines of code. Swift achieves this better than Objective-C for some problems, but the lack of message passing makes Objective-C much better suited for other problems. Although direct and vtable dispatch allow many compiler optimizations that message passing does not, message passing is rarely a bottleneck in Mac and iOS apps, and when it is, there are optimizations that can be used to alleviate the problem. Furthermore, since most Swift code uses message passing to communicate with Apple's Objective-C APIs, we already know that message passing is fast enough in Swift. As a language that will be primarily used to write apps for Apple's ecosystem, Swift should strive for as much developer productivity as possible, while keeping performance acceptable, and implementing message passing across the board is a great way to achieve these goals.

Wednesday
Sep112013

A High-Level Explanation of mach_override and How Misusing it Can Cause a Stack Overflow

mach_override is a C library for Mac OS X which allows you to override the implementation of one C function with another. In a recent article, I claimed that calling mach_override_ptr twice using the same paramaters could cause a stack overflow due to infinite recursion. In this article, I will explain how mach_override works at a high level, and explain how it can cause infinite recursion.

The information in this article is derived from the mach_override source code. mach_override was written by Jonathan "Wolf" Rentzsch, who introduced it in a paper submitted to the MacHack conference in 2003. Since then, the implementation of mach_override has changed significantly, in no small part due to the switch from PowerPC to Intel. So while the MacHack paper and presentation slides contain more in-depth information than this article, much of that information is outdated, and must be reconciled against the source code.

How mach_override Works

mach_override exposes one public function, mach_override_ptr, which takes three arguments. The first argument takes a pointer to the function to be overridden; the second argument takes a pointer to a function that will override the first; and the third argument takes the address of a function pointer which, if mach_override_ptr succeeds, can be called to execute the original function. The function pointer used in the third argument is typically called within the replacement function, and must be scoped appropriately.

This API is superficially similar to Objective-C method swizzling, but it's implementation differs significantly. Objective-C's dynamic messaging system provides a level of indirection that allows users to reroute messages at runtime. Since function calls in C do not have such a level of indirection, mach_override has to take drastic measures to create its own.

In C, the addresses of functions are computed during linking and loading. By the time mach_override_ptr executes, any code that will call the function to override will already have that function's address. Searching through memory and modifying all the code that calls this function is impractical, so mach_override rewrites the beginning of the overridden function at runtime, replacing the first instruction with a jump instruction. For those not familiar with assembly programming, a jump is like a goto, except that it can jump to a line outside the current function.

However, the overridden function will not jump directly to the replacement function. It will jump to what mach_override calls a branch island. A branch island is a small function, created at runtime, which optionally performs a few instructions before jumping to another function. This branch island is called the escape island, and jumps directly to the replacement function without doing anything else.

A second branch island, called the reentry island, is created when the third parameter is not NULL. This island executes the original first instruction from the overridden function, and then jumps to the second instruction of the original function. Thus, executing the reentry island is equivalent to executing the original function, so the address of the reentry island is assigned to the function pointer passed in as the third argument.

To create each branch island, mach_override allocates a page of virtual memory, makes it writable and executable, and then writes the branch to the beginning of the page. Similarly, to replace the first instruction of the original function, mach_override makes page(s) containing that instruction writable. Memory that is both writable and executable makes certain classes of exploits easier pull off, so you should only use mach_override when it's absolutely necessary.

The Stack Overflow

Each time mach_override_ptr is called, new branch islands are created. If called twice with the same parameters, mach_override_ptr will create two identical escape islands. The second time mach_override_ptr is called, it will replace the first instruction, which is a jump to the first escape island, with a jump to the second escape island.

The two reentry islands, however, will be different. Because the first instruction of the original function is copied to the reentry island, the first reentry island will contain the original first instruction, and the second reentry island will contain the aforementioned jump to the first escape island. Since the function pointer passed in as the third parameter is overwritten each time mach_override_ptr is called, it ends up pointing to the second reentry island. When the replacement function calls this function pointer, it calls the second reentry island, which calls the first escape island, which calls the replacement function, as illustrated below.

The original function calls escape island 2, which calls the replacement function, which calls reentry island 2, which calls escape island 1, which calls the replacement function

This bug is only possible because mach_override_ptr rewrites part of the original function, and because the same reentry function pointer is passed in both times. However, even when using unique replacement functions and reentry function pointers, calling mach_override_ptr twice on the same original function can cause unexpected behavior. The MACH_OVERRIDE macro in mach_override.h even attempts to prevent calling mach_override_ptr on the same function more than once. Because of the potential to cause bugs if called more than once, and because of the security implications, great care should be taken while using mach_override.

Friday
Aug232013

Fixing Bugs When You Can't Reproduce the Problem

The most difficult bugs to fix are the bugs you can't reproduce. Most bug reports only describe the effect of a bug, but to fix a bug, you need to know its cause. It is a lot easier to determine a bug's cause when you can trace its execution path, and if you can reliably reproduce a bug, then you can confirm that your changes actually fix it. Sometimes, however, you will be faced with bugs which you cannot reproduce. In this post, I will recount the story of one such bug, and hopefully provide you with some tips for dealing with similar problems.

My boss recently assigned me a bug that had been reported by a few of our customers. Nobody in the company had been able to reproduce it, and I wasn't confident that I'd do any better. However, this bug was causing our app to crash on users' computers, so it was important to fix.

Step 1: Determine Why the Bug is Unreproducible

There are many reasons why a bug can be difficult to reproduce. It could be present only on machines with specific hardware or software, the bug description may be missing an important step, or the bug may only happen sometimes. If I could determine why no one was able to reproduce the bug, I might be able to create the conditions necessary to reproduce it.

The users had no hardware or software in common, and the app crashed on launch, before the users had a chance to do anything. I tried every way I knew to start the app, but none of them caused it to crash. It did appear, however, that the app wasn't crashing very often.

There were only 24 crash reports for this issue, and although we had only recently released the product, I knew that there were tens of thousands of people using it. Furthermore, no user had reported the problem more than once. I did some math and estimated that the app crashed once or twice for every thousand launches.

It's important to note that at this point, I didn't actually know anything. I hadn't even confirmed that there was an actual bug. Although it's unlikely, it was possible that all the crash reports were being faked by someone. On the other hand, this issue could be widespread, but users were not opting to send us their crash reports. It was also possible that the crash reports were being caused by a different bug that was writing the same garbage data to the stack, thus creating crash reports which hid the real problem. This latter possibility was not just theoretical: I had seen crash reports like that for previous versions of this app.

However, I did have a testable hypothesis: If I launched the app 5000 times, it had a 99.3% chance of crashing at least once. To test this hypothesis, I used Frank to write a simple script that would repeatedly launch and quit the app, waiting until the app finished launching before quitting. If the app crashed ay any time, the script would terminate. I then added some logging to the app to make sure that the report's stack trace was accurate.

The next day I found that, after launching about 1,300 times, the app crashed on launch. My hypothesis seemed to be correct. Unfortunately, it took 10 hours to cause the crash. It would take a very long time to fix this problem through trial and error.

Step 2: Deduce the Approximate Cause

Now that I understood why the bug was difficult to reproduce, I needed to understand more about the bug itself. The crash was caused by a function calling itself recursively until it exhausted all the space on the stack. Normally, these kinds of bugs aren't too difficult to fix, but this function should not have been calling itself at all.

This function was, however, being used to override another function using mach_override, which lets you replace the implementation of one function with another, and allows you to call the original function from within its replacement. I'm not going to go into great technical detail about mach_override in this post, but I will post a follow-up for explaining how it works in more detail.

(N.B.: Using mach_override is dangerous, and not something you should do unless you absolutely have to. In this case, we needed to use mach_override to implement a feature central to our product. If you use mach_override, it's important to know how it works. mach_override is complicated and esoteric, so if you have a problem with it, you're unlikely to find an expert to help you. You could find yourself 80% finished with development, only to be blocked by an issue with mach_override that you can't figure out on your own.)

In order to allow you to call the original function, mach_override returns a function pointer which will call the original function. We were saving this function pointer as a global variable, and calling it from the replacement function. The code looked something like this.

void (*reentryFunc)() = NULL;

void replacementFunc()
{
    // First half of the function

    reentryFunc();

    // Second half of the function
}

void handleOneTimeNotification()
{
    // Unrelated initialization

    mach_override_ptr((void*)  originalFunc,
                      (void*)  replacementFunc,
                      (void**) &reentryFunc);

    // More unrelated initialization
}

The stack trace included the exact address where replacementFunc was recursively calling itself, so I loaded up the app in lldb and disassembled replacementFunc. It turned out that reentryFunc was calling our replacement function instead of the original function. I now knew the approximate cause of the bug, but I still didn't know why it was happening.

Step 3: Read the Source

Having access to the source code is almost essential when debugging these kinds of problems. If the crash is occurring in a proprietary framework (including Apple's frameworks), you will probably have to disassemble or otherwise reverse-engineer the code in question. Thankfully, mach_override is open source.

After spending about an hour reading the code, I concluded there was nothing wrong with mach_override, so I turned my attention to the handleOneTimeNotification function. There was nothing wrong with this function, but I did find something peculiar about a function that it called. It looked something like this.

void onlyCalledFromHandleOneTimeNotification()
{
   static int numTimesThisFunctionHasBeenCalled = 0;
    if (numTimesThisFunctionHasBeenCalled == 0)
    {
        ++numTimesThisFunctionHasBeenCalled;

        // Function body
    }
}

This check assured that the function body would only be executed once, as long as it wasn't called from multiple threads. Since handleOneTimeNotification was only supposed to be called once, this seemed odd. The check might not be necessary, but it got me thinking about what would happen if mach_override_ptr was called twice.

I concluded that if mach_override_ptr is called more than once with the same initial function and reentry function pointer, the reentry function will call the replacement function instead of the original function. I will explain why this happens in my follow-up post.

To test if calling mach_override_ptr twice would really cause the app to crash, I inserted a duplicate call to mach_override_ptr in handleOneTimeNotification. Sure enough, the app crashed with a stack trace identical to the users' stack traces.

Next, I reverted my changes and added a guard to handleOneTimeNotification to prevent it from being called twice. I also added some logging to determine how often handleOneTimeNotification was being called. Finally, I started my script and let it run for a couple days in a VM.

In the meantime, I asked my coworker, who wrote the check in onlyCalledFromHandleOneTimeNotification, about the history behind that check. He told me that the "one-time" notification does sometimes get sent twice when the app starts up, and that the check predates any use of mach_override in our app. There were also good reasons why we couldn't unregister our notification handler or prevent the notification from being sent twice.

When my test finished, it showed that the app did not crash after 5000 launches. Two of those launches called handleOneTimeNotification twice. I had proven that calling mach_override_ptr twice caused the app to crash, and that I had fixed that problem.

This debugging process won't fix all bugs. I was lucky enough to have access to the mach_override source code, as well as the developer who wrote the code I was working on. You have to adapt to the circumstances of the bug you're working on, but the same general approach will go a long way towards fixing any bug: gather as much information as possible, formulate hypotheses, and test all your assumptions.

Wednesday
Jul312013

Announcing Frank for Mac

I'm happy to announce that the Frank testing framework now supports testing Mac applications. I've been working to add support for Mac apps in my spare time for months, and I'm excited to share my work with the development community.

Mac support will ship with the next full release of Frank. In the meantime, you can install a prerelease version with Mac by typing gem install frank-cucumber -v 1.2.0.pre1 on the command-line.

Every effort has been made to make writing Mac tests similar to writing iOS tests, so most of the existing Frank documentation applies to the Mac. However, just as there are important differences between Cocoa and CocoaTouch, there are important differences to keep in mind while writing Mac tests.

Frank is complete enough to write most test cases, and should cover all of your simple testing needs. However, as Mac apps are wonderfully diverse, your app may need additional features added to Frank. If so, please get in touch via the Frank discussion group or file a feature request.

One of the main goals of this release is to gather feedback from a larger group of users with more diverse use cases. My plan is to direct future development based on what people actually need, rather than what I imagine they will need.

I sincerely hope Frank helps you write integration tests for your Mac apps. If you have any problems or questions, please do not hesitate to contact me through the discussion group. Happy testing!

Saturday
Sep082012

Making Sense of kAXMenuItemCmdModifiersAttribute

Anyone who needs to to read the keyboard shortut of a menu item using OS X's Accessibility API will need to be able to understand the kAXMenuItemCmdModifiersAttribute of the menu item. This attribute contains information about which modifier keys (Control, Option, Shift, and Command) are part of the shortcut. While the documentation correctly explains that this attribute is an integer, it does not explain how the information is stored in the integer. Unfortunately this attribute stores modifiers differently than any other API on OS X, leaving the user to figure it out themselves through testing. I recently did the work to figure this out myself, and since I can't find this information anywhere on the Internet, I'm posting this information so that it's availiable to others who have this problem.

The only documentation for kAXMenuItemCmdModifiersAttribute can be found in the Carbon Accessibility Reference. It is only one sentence. There is no additional information that can be found in the header files of HIServices.framework.

kAXMenuItemCmdModifiersAttribute

An integer mask that represents the modifier keys held down in the keyboard shortcut for the command represented by this accessibility object.

Because users of the Accessibility API often need to post Keyboard events, they might be inclined to guess that the integer mask is the same as a CGEventFlag, and write a method like this.

- (void) logModifiers: (int) bitmask
{    
    if (bitmask & kCGEventFlagMaskControl)
    {
        NSLog(@"The Control Key is present");
    }
    
    if (bitmask & kCGEventFlagMaskAlternate)
    {
        NSLog(@"The Option Key is present");
    }
    
    if (bitmask & kCGEventFlagMaskShift)
    {
        NSLog(@"The Shift Key is present");
    }
    
    if (bitmask & kCGEventFlagMaskCommand)
    {
        NSLog(@"The Command Key is present");
    }
}

But since the integer mask is not actually a CGEventMask, this will not work. The integer mask actually uses the lowest 4 bits to represent the modifier keys. For Control, Option and Shift, a set bit means that the key is present in the keyboard shortcut. However, for Command a set bit means that the Command key is not present in the shortcut. I was unable to find any constant definitions in the HIServices.framework headers which corresponded to these flags. The corrected method looks like this.

- (void) logModifiers: (int) bitmask
{
    NSLog(@"This is how the bitmask actually works");
    
    if (bitmask & 4)
    {
        NSLog(@"The Control Key is present");
    }
    
    if (bitmask & 2)
    {
        NSLog(@"The Option Key is present");
    }
    
    if (bitmask & 1)
    {
        NSLog(@"The Shift Key is present");
    }
    
    if (!(bitmask & 8))
    {
        NSLog(@"The Command Key is present");
    }
}

I have filed two radars with Apple related to this behavior. The first asks Apple to add a new attribute which returns a CGEventMask (rdar://12261141), and the second asks Apple to update the documentation for kAXMenuItemCmdModifiersAttribute (rdar://12261193).