Git Product home page Git Product logo

cwlpreconditiontesting's Introduction

CwlPreconditionTesting

A Mach exception handler, written in Swift and Objective-C, that allows EXC_BAD_INSTRUCTION (as raised by Swift's assertionFailure/preconditionFailure/fatalError) to be caught and tested.

For an extended discussion of this code, please see the Cocoa with Love article:

Partial functions in Swift, Part 2: Catching precondition failures

Usage

The short version is:

  1. In a subdirectory of your project's directory, run git clone https://github.com/mattgallagher/CwlPreconditionTesting.git
  2. Drag the "CwlPreconditionTesting.xcodeproj" file from the Finder into your project's file tree in Xcode
  3. Click on your project in the file tree to access project settings and click on the target to which you want to add CwlUtils.
  4. Click on the "Build Phases" tab and if you don't already have a "Copy Files" build phase with a "Destination: Frameworks", add one using the "+" in the top left of the tab.
  5. Still on the "Build Phases" tab, add "CwlPreconditionTesting.framework" to the "Copy Files, Destination: Frameworks" step. NOTE: there may be multiple "CwlPreconditionTesting.framework" files in the list, including one for macOS and one for iOS. You should select the "CwlPreconditionTesting.framework" that appears above the corresponding CwlPreconditionTesting macOS or iOS testing target.
  6. Optional step: Adding the "CwlPreconditionTesting.xcodeproj" file to your project's file tree will also add all of its schemes to your scheme list in Xcode. You can hide these from your scheme list from the menubar by selecting "Product" -> "Scheme" -> "Manage Schemes" (or typing Command-Shift-,) and unselecting the checkboxes in the "Show" column next to the CwlPreconditionTesting scheme names.
  7. In Swift files where you want to use CwlPreconditionTesting code, write import CwlPreconditionTesting at the top.

Project details

The "CwlPreconditionTesting.xcodeproj" contains two targets:

  • CwlPreconditionTesting_OSX
  • CwlPreconditionTesting_iOS

both build a framework named "CwlPreconditionTesting.framework". If you're linking manually, be certain to select the "CwlPreconditionTesting.framework" from the appropriate target.

Remember: the iOS build is useful only in the simulator. All Mach exception handling code will be conditionally excluded in any device build.

Static inclusion

Due to the complications associated with needing to call into and out of Objective-C, static inclusion in other projects is not a single file nor a quick drag and drop. There's at least 7 files and you'll need to add some project settings.

All of the following files:

  • CwlCatchBadInstruction.swift
  • CwlCatchBadInstruction.h
  • CwlCatchBadInstruction.m
  • CwlCatchException.swift
  • CwlCatchException.h
  • CwlCatchException.m

and either:

  • $(SDKROOT)/usr/include/mach/mach_exc.defs
  • mach_excServer.c

need to be added to the testing target for OS X projects or iOS projects, respectively.

Your target will also need to have the following macros defined in the "Apple LLVM - Preprocessing" โ†’ "Preprocessor Macros" build setting:

PRODUCT_NAME=$(PRODUCT_NAME)

This lets the Objective-C file generate the include directive for the autogenerated Swift header so it can call back into Swift during the Mach exception handler callbacks. This macro should stay in sync if you change the target name but if you do anything else in your project that changes the name of the autogenerated Swift header independent of the target name (or you want to add spaces or other command-line complications to the target name), you'll want to update "CwlCatchBadInstruction.m" directly with the correct include directive.

Additionally, you'll need a standard Objective-C "Bridging header" for your testing target and it will need to include the following import statements:

#if defined(__x86_64__)
#import <CwlPreconditionTesting/CwlCatchBadInstruction.h>
#endif

#import <CwlPreconditionTesting/CwlCatchException.h>

Using POSIX signals and setjmp/longjmp

For comparison or for anyone running this code on a platform without Mach exceptions or the Objective-C runtime, I've added a proof-of-concept implementation of catchBadInstruction that uses a POSIX SIGILL sigaction and setjmp/longjmp to perform the throw.

In Xcode, you can simply select the CwlPreconditionTesting_POSIX target (instead of the OSX or iOS targets). If you're building without Xcode: all you need is the CwlCatchBadInstructionPOSIX.swift file (compared to the Mach exception handler, the code is tiny doesn't have any weird Objective-C/MiG file dependencies).

Warning No. 1: on OS X, this approach can't be used when lldb is attached since lldb's Mach exception handler blocks the SIGILL from ever occurring (I've disabled the "Debug Executable" setting for the tests in Xcode - re-enable it to witness the problem).

Warning No. 2: if you're switching between the CwlPreconditionTesting_OSX and CwlPreconditionTesting_POSIX targets, Xcode (as of Xcode 7.2.1) will not detect the change and will not remove the old framework correctly so you'll need to clean your project otherwise the old framework will hang around.

Additional problems in decreasing severity include:

  • the signal handler is whole process (rather than correctly scoped to the thread where the "catch" occurs)
  • the signal handler doesn't deal with re-entrancy whereas the mach exception handler remains deterministic in the face of multiple fatal errors
  • the signal handler overwrites the "red zone" which is technically frowned upon in signal handlers (although unlikely to cause problems here)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.