18:24 Sat, 04 Jul 2009 PDT -0700

Blocks Examples: NSOperationQueue and UIActionSheet

Introduction

On Friday, Plausible Labs released PLBlocks, an SDK that allows you to immediately begin experimenting with blocks (also known as closures) on Mac OS X 10.5 and iPhone OS 3.0. While the original announcement included a very brief introduction to blocks, I thought it might be worthwhile to provide some concrete examples of using blocks in your own code.

Example Code

All the sample code and implementation classes for this article are available via my block_samples github repository. You may download the repository as an archive (no git required) by pressing the "download" button next to the repository name.

To get started with the PLBlocks SDK, check out the download and installation instructions on the project page. Please note that PLBlocks is still in beta.

NSOperationQueue

On Mac OS X and iPhoneOS, there are a variety of ways to schedule operations on a background thread. One method that's often used is calling -[NSObject performSelectorInBackground:withObject:] to execute a method in the background, and then -[NSObject performSelectorOnMainThread:withObject:waitUntilDone:] to provide the results to the primary thread.

This works, but it's not as convenient as it could be:

Using blocks -- and a few small extensions to NSOperationQueue and NSThread -- we can instead encapsulate this full exchange in one method, using a block to run the background operation, and a nested block to handle the response directly on the main thread:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Allocated here for succinctness.
    NSOperationQueue *q = [[NSOperationQueue alloc] init];
 
    /* Data to process */
    NSData *data = [@"Hello, I'm a Block!" dataUsingEncoding: NSUTF8StringEncoding];
 
    /* Push an expensive computation to the operation queue, and then
     * display the response to the user on the main thread. */
    [q addOperationWithBlock: ^{
        /* Perform expensive processing with data on our background thread */
        NSString *string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
         
        /* This is the "expensive" part =) */
        sleep(5);
         
        /* Inform the user of the result on the main thread, where it's safe to play with the UI. */
        [[NSThread mainThread] performBlock: ^{
            NSAlert *alert = [[[NSAlert alloc] init] autorelease];
             
            [alert addButtonWithTitle: @"OK"];
            [alert setMessageText: [NSString stringWithFormat: @"Processing completed: %@", string]];
            [alert runModal];
        }];
 
        /* We don't need to hold a string reference anymore */
        [string release];
    }];
}

The first block is scheduled to run on the NSOperationQueue, and inside contains an additional nested block. When the operation has completed, it schedules its nested block to run on the main thread, where the result can be presented to the user, or passed on for further processing.

You can find the full NSOperationQueue and NSThread extensions -- including example usage -- here.

UIActionSheet

If you've done any iPhone development, you'll know that using UIActionSheet is a bit complicated -- more so if you want to share an action sheet implementation across view controllers, or display multiple UIActionSheets from a single view controller.

If you've used UIActionSheet in the past, you've had to do the following:

Using blocks, we can significant reduce the effort required to define and use a UIActionSheet. Instead of defining a delegate, and matching index values to your button actions, we can simply pass a block that implements the button's action directly:

- (void) displaySheet {
    PLActionSheet *sheet = [[PLActionSheet alloc] initWithTitle: @"Destination"];
    
    /* A re-usable block that simply displays an alert message */
    void (^alert)(NSString *) = ^(NSString *message) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"Destination Selected"
                                                        message: message
                                                       delegate: nil
                                              cancelButtonTitle: @"OK"
                                              otherButtonTitles: nil];
        
        [alert show];
        [alert release];
    };
    
    [sheet addButtonWithTitle: @"Work" block: ^{
        alert(@"Work selected");
    }];
    
    [sheet addButtonWithTitle: @"Home" block: ^{
        alert(@"Home selected");
    }];
    
    [sheet addButtonWithTitle: @"School" block: ^{
        alert(@"School selected");
    }];
    
    [sheet setCancelButtonWithTitle: @"Cancel" block: ^{}];
 
    [sheet showInView: self.window];
    [sheet release];
}

That's it -- there is nothing else. The blocks used for each button automatically have access to the enclosing method's variables, and we even use another block (alert) to avoid retyping the UIAlertView boilerplate or cluttering our class with an alert method.

You can find the full UIActionSheet wrapper -- including example usage -- here.

Conclusion

I hope you'll find these examples useful in experimenting with and incorporating blocks into your own software. There are quite a few other ways that blocks can be leveraged to decrease code size and complexity, and I'll plan on writing future articles on the subject.

If you'd like to discuss blocks, the PLBlocks implementation, or having any other questions, feel free to join the PLBlocks mailing list.

[/code/iphone] permanent link

21:49 Thu, 02 Jul 2009 PDT -0700

PLBlocks: Blocks for iPhoneOS 3.0 and Mac OS X 10.5

Over the weekend (and for some of the week) I've been working on back-porting block support from the Snow Leopard toolchain, with the goal of leveraging blocks for our iPhone and Mac OS X 10.5 development at Plausible Labs.

If you're unfamiliar with blocks, they're an implementation of closures for C, Objective-C, and provisionally C++. The full language specification and ABI specification are available from the LLVM/Clang project.

I've now published an initial beta release with support for iPhone OS 3.0 (armv6), and Mac OS X 10.5 (i386, x86-64, ppc) -- you can find the full announcement -- including download and usage instructions -- here.

[/code/iphone] permanent link

17:16 Wed, 20 May 2009 PDT -0700

New Plausible Labs Website

We just released a new design for the Plausible Labs website, home of the fine worker-owned cooperative that keeps me gainfully employed so that I can spend my free time (such as it exists) working on open source software.

[/work] permanent link

20:15 Mon, 18 May 2009 PDT -0700

Critical Mac OS X Java Vulnerabilities

Introduction

Five months ago, CVE-2008-5353 and other vulnerabilities were publicly disclosed, and fixed by Sun.

CVE-2008-5353 allows malicious code to escape the Java sandbox and run arbitrary commands with the permissions of the executing user. This may result in untrusted Java applets executing arbitrary code merely by visiting a web page hosting the applet. The issue is trivially exploitable.

Unfortunately, these vulnerabilities remain in Apple's shipping JVMs, as well as Soylatte 1.0.3. As Soylatte does not provide browser plugins, the impact of the vulnerability is reduced. The recent release of OpenJDK6/Mac OS X is not affected by CVE-2008-5353.

Work-Arounds

Patch

Update 06-15-2009: Apple has released Java for Mac OS X 10.5 Update 4, which contains a fix for this issue.

To update your system, run "Software Update" from the Apple menu.

Note: Safari users should leave 'Open "safe" files after download' permanently disabled. Similarly critical vulnerabilities unrelated to Java remain in Safari's handling of "Safe" files.

Proof of Concept

Unfortunately, it seems that many Mac OS X security issues are ignored if the severity of the issue is not adequately demonstrated. Due to the fact that an exploit for this issue is available in the wild, and the vulnerability has been public knowledge for six months, I have decided to release a my own proof of concept to demonstrate the issue.

If you visit the following page, "/usr/bin/say" will be executed on your system by a Java applet, with your current user permissions. This link will execute code on your system with your current user permissions. The proof of concept runs on fully-patched PowerPC and Intel Mac OS X systems.

Credit

Thanks to Jeffrey Czerniak for bringing this issue to my attention.

Update: Julien Tinnes e-mailed with a link to his in-depth discussion regarding the vulnerability available here.

[/code/macosx] permanent link

15:15 Sun, 17 May 2009 PDT -0700

OpenJDK 6 for Mac OS X

As part of the OpenJDK project, various organizations have been working on OpenJDK 6, a freely distributable Java 6 implementation based on the open source OpenJDK 7 code base. Most Linux distributions are now shipping OpenJDK 6 binaries.

Soylatte (Java 6 Port for Mac OS X) was originally based on the BSD port of the JRL licensed Java 6 code base, which significantly constrains end-user usage and distribution rights. With Sun's approved re-licensing of the BSD changes for use in OpenJDK 7, a backport to OpenJDK 6 was made possible.

I've added support for OpenJDK 6 on Mac OS X, based on Brian Gardner's work backporting the OpenJDK 7 BSD changes to OpenJDK6/FreeBSD. Unlike the legacy Soylatte builds, OpenJDK 6 is:

The initial beta release is available for testing via the MacPorts openjdk6 port (Leopard only), or as a binary from the Soylatte web page (Leopard/Tiger, untested on Tiger). My ability to provide 10.4 support is constrained without access to a 10.4 machine, and any testing/development assistance is most welcome.

[/code/java] permanent link

12:38 Fri, 13 Feb 2009 PST -0800

iPhone: Preventing Piracy

There's a lot of talk lately about preventing application piracy on the iPhone. Automated tools have been released to strip Apple's DRM, and a new anti-piracy product (which charges royalty fees on your sales) has been released.

As an iPhone developer, you have no access to the purchasing process. You can't issue (or revoke) serial numbers, implement an activation scheme, or provide any other fully independent copy protection. The only way to differentiate between a purchased copy of your application and a pirated one is to implement your own code to introspect the DRM that Apple has applied to your application.

On the phone, purchased applications are shipped to the user with a variety of meta-data that is readable by the application. The information potentially useful for implementing additional copy protection includes:

Using this information, it is possible to implement additional copy protection. The signature can be checked, the application encryption can be verified, etc. However, there's a problem -- none of this is documented by Apple. While most of the APIs and file formats are public, the actual distribution format is not. Apple could change the signature format, the meta-data plist, or any other distribution component at any time, at which point your copy protection may raise a false positive, and your paying customers will be wondering why you're wasting their time.

Given the risks, I've decided against implementing any further copy protection in my applications -- I believe it's Apple's problem to solve, and don't think it's worth risking false positives and annoyed customers. That said, if you'd like to take the plunge, here is some example code to get you started. For further reading, I suggest starting with Apple's Mac OS X Code Signing In Depth and Amit Singh's Understanding Apple's Binary Protection in Mac OS X.

The current process of cracking an application relies on stripping the application of encryption by attaching a debugger to the application on a jailbroken phone, dumping the text section containing the program code, and reinserting it into the original binary. The below code checks for the existence of LC_ENCRYPTION_INFO, and verifies that encryption is still enabled. There are, of course, a number of ways to defeat this check, but that's the nature of copy protection:

#import <dlfcn.h>
#import <mach-o/dyld.h>
#import <TargetConditionals.h>
 
/* The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from the iPhoneOS or
 * Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just provide the definitions here. */
#if TARGET_IPHONE_SIMULATOR && !defined(LC_ENCRYPTION_INFO)
#define LC_ENCRYPTION_INFO 0x21
struct encryption_info_command {
    uint32_t cmd;
    uint32_t cmdsize;
    uint32_t cryptoff;
    uint32_t cryptsize;
    uint32_t cryptid;
};
#endif
  
int main (int argc, char *argv[]);
  
static BOOL is_encrypted () {
    const struct mach_header *header;
    Dl_info dlinfo;
      
    /* Fetch the dlinfo for main() */
    if (dladdr(main, &dlinfo) == 0 || dlinfo.dli_fbase == NULL) {
        NSLog(@"Could not find main() symbol (very odd)");
        return NO;
    }
    header = dlinfo.dli_fbase;
 
    /* Compute the image size and search for a UUID */
    struct load_command *cmd = (struct load_command *) (header+1);
     
    for (uint32_t i = 0; cmd != NULL && i < header->ncmds; i++) {
        /* Encryption info segment */
        if (cmd->cmd == LC_ENCRYPTION_INFO) {
            struct encryption_info_command *crypt_cmd = (struct encryption_info_command *) cmd;
            /* Check if binary encryption is enabled */
            if (crypt_cmd->cryptid < 1) {
                /* Disabled, probably pirated */
                return NO;
            }
             
            /* Probably not pirated? */
            return YES;
        }
         
        cmd = (struct load_command *) ((uint8_t *) cmd + cmd->cmdsize);
    }
     
    /* Encryption info not found */
    return NO;
}

[/code/iphone] permanent link

16:19 Thu, 29 Jan 2009 PST -0800

Open Source Crash Reporter for iPhone (and Mac OS X)

Introduction

Despite my best efforts to the contrary, I ship software with bugs.

After unit testing and integration testing, the bugs that tend to slip through are tricky ones -- race conditions, crashes triggered by bugs in platform vendor's implementation, and issues that only appear in specific configurations, such as a user synchronizing their iPhone's Address Book with Microsoft Outlook.

These are the types of issues that you hope to catch in beta testing. If you don't, however, these bugs leak into the wild.

On the iPhone, Apple generates crash logs for every third-party application crash. These plain text logs include backtraces, thread state, and other information to help you debug your crashes. Unfortunately, these crash logs are not actually readable by third party applications. As a software developer, you're reliant on users to report the bug (rather than, say, simply delete your application), and then at your behest, synchronize their iPhone, locate the (correct!) crash log on disk, and send it to you.

Plausible Crash Reporter

To solve this problem, I decided to implement our own Crash Reporter. It sports the following features:

If your application crashes, a crash report will be written. When the application is next run, you may check for a pending crash report, submit the report to your own HTTP server, send an e-mail, or even introspect the report locally. Additionally, I hope to add support for services like getexceptional to automatically handle uploading, notification, and tracking of crashing issues.

Crash Report Format

Crash logs are encoded using google protobuf, and may be decoded using the PLCrashReport API. Additionally, the included plcrashutil handles conversion of binary crash reports to the symbolicate-compatible iPhone text format.

Example iPhone Usage

/**
 * Called to handle a pending crash report.
 */
- (void) handleCrashReport {
    PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
    NSData *crashData;
    NSError *error;
  
    /* Try loading the crash report */
    crashData = [crashReporter loadPendingCrashReportDataAndReturnError: &error];
    if (crashData == nil) {
        NSLog(@"Could not load crash report: %@", error);
        goto finish;
    }
  
    /* We could send the report from here, but we'll just print out
     * some debugging info instead */
    PLCrashReport *report = [[[PLCrashReport alloc] initWithData: crashData error: &error] autorelease];
    if (report == nil) {
        NSLog(@"Could not parse crash report");
        goto finish;
    }
  
    NSLog(@"Crashed on %@", report.systemInfo.timestamp);
    NSLog(@"Crashed with signal %@ (code %@, address=0x%" PRIx64 ")", report.signalInfo.name,
          report.signalInfo.code, report.signalInfo.address);
 
    /* Purge the report */
finish:
    [crashReporter purgePendingCrashReport];
    return;
}
 
// from UIApplicationDelegate protocol
- (void) applicationDidFinishLaunching: (UIApplication *) application {
    PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
    NSError *error;
 
    /* Check if we previously crashed */
    if ([crashReporter hasPendingCrashReport])
        [self handleCrashReport];
 
    /* Enable the Crash Reporter */
    if (![crashReporter enableCrashReporterAndReturnError: &error])
        NSLog(@"Warning: Could not enable crash reporter: %@", error);
 
    ...
}

The first beta release is now available as open source (MIT licensed) from the PLCrashReporter Project Page. This is intended for developer testing, and your feedback is most appreciated.

If you're interested in additional functionality, integration support, or other development services, feel free to drop me a line. We also gladly accept donations to support our open source development efforts: Donate via Paypal

[/code/iphone] permanent link

12:56 Thu, 29 Jan 2009 PST -0800

Plausible Jukebox

Plausible Labs' clone of Apple's CoverFlow™ is now available for off-the-shelf licensing.

You can also download a demonstration version of the library (limited to rendering every other cover) to try it out for yourself.

I would (perhaps unsurprisingly) perfer to release the library as open source, but R&D has to be funded! =)

[/code/iphone] permanent link

21:13 Mon, 05 Jan 2009 PST -0800

iPhone: Application Piracy

Within a few hours of its 1.0 release, our iPhone application was stripped of its DRM by a customer, and made available via http://appulo.us for use on jailbroken iPhones. Appulo.us serves as a comprehensive repository of pirated iPhone applications, with screen shots, application descriptions, and, of course, links to pirated copies.

The process of stripping DRM from iPhone applications has even been automated.

According to the Appulo.us FAQ, this software piracy serves as a solution to a "flawed app store". In providing pirated copies of our applications, Appulo.us claims that they are providing a justifiable service to our customers -- providing unlimited demos of our applications.

This justification is remarkably prevalent in the community of users that pirate software, as noted in James Bossert's recent blog post of his conversation with an iPhone software pirate:

When i crack an app, any app, i do not do it to hurt developers.
Without you we wouldn’t even have our community =) I do this so people
would know is an app worth their money.

I agree that Apple should allow demo applications -- users would be better served by the opportunity to test the application. However, this attempted justification does not hold water for one simple reason: as the copyright holder, I am perfectly capable of releasing a demo version of our application for jailbroken phones.

So I will. If you'd like to give Peeps a try on your jailbroken phone, you can download a demo .ipa or app. This version is identical to the latest release, but will display a "Please Purchase Peeps" dialog for 10 seconds when the application launches. (Note! You must have a jailbroken phone to run this Peeps Demo. Sorry!).

This is an experiment. If you like the application, please consider purchasing it. If you don't, let us know what you'd like to see improved. However, please don't distribute pirated versions of our software.

[/code/iphone] permanent link

15:39 Wed, 24 Dec 2008 PST -0800

iPhone: Testing your Application with Valgrind

On other platforms, I've found valgrind to be indispensable when it comes to discovering and fixing bugs. With Greg Parker's port of valgrind for Mac OS X now available, it's now possible to test your Mac and iPhone applications with valgrind.

Valgrind does not support ARM, but it is capable of executing i386 binaries built against the iPhone Simulator SDK. The only difficulty is that you can't run valgrind from the command line -- GUI iPhone Simulator binaries must be registered and run by Xcode, which uses the private iPhoneSimulatorRemoteClient framework to start and stop Simulator sessions.

To work around this, I wrote a small "re-exec" handler in my application's main(). It looks like this:

#define VALGRIND "/usr/local/valgrind/bin/valgrind"
 
int main(int argc, char *argv[]) {
#ifdef VALGRIND_REXEC
    /* Using the valgrind build config, rexec ourself
     * in valgrind */
    if (argc < 2 || (argc >= 2 && strcmp(argv[1], "-valgrind") != 0)) {
        execl(VALGRIND, VALGRIND, "--leak-check=full", argv[0], "-valgrind",
              NULL);
    }
#endif
  
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, @"PeepsAppDelegate");
    [pool release];
    return retVal;
}

To enable this code, I added a 'valgrind' build configuration to my project which defines VALGRIND_REXEC. After switching to the valgrind configuration, my application will run in the Simulator, under valgrind:

[Session started at 2008-12-24 15:27:47 -0800.]
==38596== Memcheck, a memory error detector.
==38596== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.

Running our code under valgrind has greatly facilitated the resolution of otherwise difficult to find or entirely unknown bugs.

[/code/iphone] permanent link