Skip to content
This repository has been archived by the owner on Feb 19, 2020. It is now read-only.

Commit

Permalink
Merge branch 'release/3.7.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Andreas Linde committed Jun 23, 2015
2 parents 3c7f168 + b66fbcf commit 213b118
Show file tree
Hide file tree
Showing 72 changed files with 3,069 additions and 795 deletions.
33 changes: 33 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
language: objective-c
osx_image: beta-xcode6.3

env:
global:
- PROJECT="Support/HockeySDK.xcodeproj"
- SDK="iphonesimulator"
- CONFIGURATION="DEBUG"

matrix:
- SCHEME="HockeySDK" DESTINATION="OS=7.1,name=iPad 2" RUN_TESTS="YES"
- SCHEME="HockeySDK" DESTINATION="OS=7.1,name=iPhone 5" RUN_TESTS="YES"
- SCHEME="HockeySDK" DESTINATION="OS=8.1,name=iPad Air" RUN_TESTS="YES"
- SCHEME="HockeySDK" DESTINATION="OS=8.2,name=iPhone 6" RUN_TESTS="YES"
- SCHEME="HockeySDK" DESTINATION="OS=8.3,name=iPhone 6 Plus" RUN_TESTS="YES"
- SCHEME="HockeySDK Framework" DESTINATION="platform=iOS Simulator,name=iPhone 6" RUN_TESTS="YES"
- SCHEME="HockeySDK Distribution" RUN_TESTS="NO"

before_install:
- gem install cocoapods --no-rdoc --no-ri --no-document --quiet
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
- brew tap homebrew/versions
- brew install appledoc22
- brew link --force appledoc22

script:
- set -o pipefail
- COMMAND="xcodebuild -project '$PROJECT' -scheme '$SCHEME' -sdk '$SDK' -configuration '$CONFIGURATION'"
- if [ $RUN_TESTS == "YES" ]; then
COMMAND+=" -destination '$DESTINATION' clean test";
fi
- COMMAND+=" | xcpretty -c"
- eval $COMMAND
12 changes: 9 additions & 3 deletions Classes/BITAuthenticator.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,17 @@
*/


#import "BITAuthenticator.h"
#import "HockeySDK.h"

#if HOCKEYSDK_FEATURE_AUTHENTICATOR

#import "HockeySDKPrivate.h"
#import "BITAuthenticator_Private.h"
#import "BITAuthenticationViewController.h"
#import "BITHTTPOperation.h"
#import "BITHockeyAppClient.h"
#import "BITHockeyHelper.h"
#import "BITHockeyBaseManagerPrivate.h"

#include <sys/stat.h>

Expand Down Expand Up @@ -335,7 +339,7 @@ - (NSDictionary*) validationParameters {
NSParameterAssert(self.installationIdentifier);
NSParameterAssert(self.installationIdentifierParameterString);

NSString *installString = bit_appAnonID();
NSString *installString = bit_appAnonID(NO);
if (installString) {
return @{self.installationIdentifierParameterString : self.installationIdentifier, @"install_string": installString};
}
Expand Down Expand Up @@ -436,7 +440,7 @@ - (NSURLRequest *) requestForAuthenticationEmail:(NSString*) email password:(NSS
NSString *authenticationPath = [self authenticationPath];
NSMutableDictionary *params = [NSMutableDictionary dictionary];

NSString *installString = bit_appAnonID();
NSString *installString = bit_appAnonID(NO);
if (installString) {
params[@"install_string"] = installString;
}
Expand Down Expand Up @@ -908,3 +912,5 @@ - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)
}
}
@end

#endif
9 changes: 7 additions & 2 deletions Classes/BITAuthenticator_Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@
*/


#import "BITAuthenticator.h"
#import "BITHockeyBaseManagerPrivate.h"
#import "HockeySDK.h"

#if HOCKEYSDK_FEATURE_AUTHENTICATOR

#import "BITAuthenticationViewController.h"

@class BITHockeyAppClient;

@interface BITAuthenticator ()<BITAuthenticationViewControllerDelegate, UIAlertViewDelegate>
Expand Down Expand Up @@ -93,3 +96,5 @@
- (BOOL) needsValidation;
- (void) authenticate;
@end

#endif
49 changes: 49 additions & 0 deletions Classes/BITCrashCXXExceptionHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Author: Gwynne Raskind <[email protected]>
*
* Copyright (c) 2015 HockeyApp, Bit Stadium GmbH.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

#import <Foundation/Foundation.h>
#import "HockeySDKNullability.h"

typedef struct {
const void * __nullable exception;
const char * __nullable exception_type_name;
const char * __nullable exception_message;
uint32_t exception_frames_count;
const uintptr_t * __nonnull exception_frames;
} BITCrashUncaughtCXXExceptionInfo;

typedef void (*BITCrashUncaughtCXXExceptionHandler)(
const BITCrashUncaughtCXXExceptionInfo * __nonnull info
);

@interface BITCrashUncaughtCXXExceptionHandlerManager : NSObject

+ (void)addCXXExceptionHandler:(nonnull BITCrashUncaughtCXXExceptionHandler)handler;
+ (void)removeCXXExceptionHandler:(nonnull BITCrashUncaughtCXXExceptionHandler)handler;

@end
233 changes: 233 additions & 0 deletions Classes/BITCrashCXXExceptionHandler.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
/*
* Author: Gwynne Raskind <[email protected]>
*
* Copyright (c) 2015 HockeyApp, Bit Stadium GmbH.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

#import "BITCrashCXXExceptionHandler.h"
#import <vector>
#import <cxxabi.h>
#import <exception>
#import <stdexcept>
#import <typeinfo>
#import <string>
#import <pthread.h>
#import <dlfcn.h>
#import <execinfo.h>
#import <libkern/OSAtomic.h>

typedef std::vector<BITCrashUncaughtCXXExceptionHandler> BITCrashUncaughtCXXExceptionHandlerList;
typedef struct
{
void *exception_object;
uintptr_t call_stack[128];
uint32_t num_frames;
} BITCrashCXXExceptionTSInfo;

static bool _BITCrashIsOurTerminateHandlerInstalled = false;
static std::terminate_handler _BITCrashOriginalTerminateHandler = nullptr;
static BITCrashUncaughtCXXExceptionHandlerList _BITCrashUncaughtExceptionHandlerList;
static OSSpinLock _BITCrashCXXExceptionHandlingLock = OS_SPINLOCK_INIT;
static pthread_key_t _BITCrashCXXExceptionInfoTSDKey = 0;

@implementation BITCrashUncaughtCXXExceptionHandlerManager

extern "C" void LIBCXXABI_NORETURN __cxa_throw(void *exception_object, std::type_info *tinfo, void (*dest)(void *))
{
// Purposely do not take a lock in this function. The aim is to be as fast as
// possible. While we could really use some of the info set up by the real
// __cxa_throw, if we call through we never get control back - the function is
// noreturn and jumps to landing pads. Most of the stuff in __cxxabiv1 also
// won't work yet. We therefore have to do these checks by hand.

// The technique for distinguishing Objective-C exceptions is based on the
// implementation of objc_exception_throw(). It's weird, but it's fast. The
// explicit symbol load and NULL checks should guard against the
// implementation changing in a future version. (Or not existing in an earlier
// version).

typedef void (*cxa_throw_func)(void *, std::type_info *, void (*)(void *)) LIBCXXABI_NORETURN;
static dispatch_once_t predicate = 0;
static cxa_throw_func __original__cxa_throw = nullptr;
static const void **__real_objc_ehtype_vtable = nullptr;

dispatch_once(&predicate, ^ {
__original__cxa_throw = reinterpret_cast<cxa_throw_func>(dlsym(RTLD_NEXT, "__cxa_throw"));
__real_objc_ehtype_vtable = reinterpret_cast<const void **>(dlsym(RTLD_DEFAULT, "objc_ehtype_vtable"));
});

// Actually check for Objective-C exceptions.
if (tinfo && __real_objc_ehtype_vtable && // Guard from an ABI change
*reinterpret_cast<void **>(tinfo) == __real_objc_ehtype_vtable + 2) {
goto callthrough;
}

// Any other exception that came here has to be C++, since Objective-C is the
// only (known) runtime that hijacks the C++ ABI this way. We need to save off
// a backtrace.
// Invariant: If the terminate handler is installed, the TSD key must also be
// initialized.
if (_BITCrashIsOurTerminateHandlerInstalled) {
BITCrashCXXExceptionTSInfo *info = static_cast<BITCrashCXXExceptionTSInfo *>(pthread_getspecific(_BITCrashCXXExceptionInfoTSDKey));

if (!info) {
info = reinterpret_cast<BITCrashCXXExceptionTSInfo *>(calloc(1, sizeof(BITCrashCXXExceptionTSInfo)));
pthread_setspecific(_BITCrashCXXExceptionInfoTSDKey, info);
}
info->exception_object = exception_object;
// XXX: All significant time in this call is spent right here.
info->num_frames = backtrace(reinterpret_cast<void **>(&info->call_stack[0]), sizeof(info->call_stack) / sizeof(info->call_stack[0]));
}

callthrough:
if (__original__cxa_throw) {
__original__cxa_throw(exception_object, tinfo, dest);
} else {
abort();
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
__builtin_unreachable();
#pragma clang diagnostic pop
}

__attribute__((always_inline))
static inline void BITCrashIterateExceptionHandlers_unlocked(const BITCrashUncaughtCXXExceptionInfo &info)
{
for (const auto &handler : _BITCrashUncaughtExceptionHandlerList) {
handler(&info);
}
}

static void BITCrashUncaughtCXXTerminateHandler(void)
{
BITCrashUncaughtCXXExceptionInfo info = {
.exception = nullptr,
.exception_type_name = nullptr,
.exception_message = nullptr,
.exception_frames_count = 0,
.exception_frames = nullptr,
};
auto p = std::current_exception();

OSSpinLockLock(&_BITCrashCXXExceptionHandlingLock); {
if (p) { // explicit operator bool
info.exception = reinterpret_cast<const void *>(&p);
info.exception_type_name = __cxxabiv1::__cxa_current_exception_type()->name();

BITCrashCXXExceptionTSInfo *recorded_info = reinterpret_cast<BITCrashCXXExceptionTSInfo *>(pthread_getspecific(_BITCrashCXXExceptionInfoTSDKey));

if (recorded_info) {
info.exception_frames_count = recorded_info->num_frames - 1;
info.exception_frames = &recorded_info->call_stack[1];
} else {
// There's no backtrace, grab this function's trace instead. Probably
// means the exception came from a dynamically loaded library.
void *frames[128] = { nullptr };

info.exception_frames_count = backtrace(&frames[0], sizeof(frames) / sizeof(frames[0])) - 1;
info.exception_frames = reinterpret_cast<uintptr_t *>(&frames[1]);
}

try {
std::rethrow_exception(p);
} catch (const std::exception &e) { // C++ exception.
info.exception_message = e.what();
BITCrashIterateExceptionHandlers_unlocked(info);
} catch (const std::exception *e) { // C++ exception by pointer.
info.exception_message = e->what();
BITCrashIterateExceptionHandlers_unlocked(info);
} catch (const std::string &e) { // C++ string as exception.
info.exception_message = e.c_str();
BITCrashIterateExceptionHandlers_unlocked(info);
} catch (const std::string *e) { // C++ string pointer as exception.
info.exception_message = e->c_str();
BITCrashIterateExceptionHandlers_unlocked(info);
} catch (const char *e) { // Plain string as exception.
info.exception_message = e;
BITCrashIterateExceptionHandlers_unlocked(info);
} catch (id e) { // Objective-C exception. Pass it on to Foundation.
OSSpinLockUnlock(&_BITCrashCXXExceptionHandlingLock);
if (_BITCrashOriginalTerminateHandler != nullptr) {
_BITCrashOriginalTerminateHandler();
}
return;
} catch (...) { // Any other kind of exception. No message.
BITCrashIterateExceptionHandlers_unlocked(info);
}
}
} OSSpinLockUnlock(&_BITCrashCXXExceptionHandlingLock); // In case terminate is called reentrantly by pasing it on

if (_BITCrashOriginalTerminateHandler != nullptr) {
_BITCrashOriginalTerminateHandler();
} else {
abort();
}
}

+ (void)addCXXExceptionHandler:(BITCrashUncaughtCXXExceptionHandler)handler
{
static dispatch_once_t key_predicate = 0;

// This only EVER has to be done once, since we don't delete the TSD later
// (there's no reason to delete it).
dispatch_once(&key_predicate, ^ {
pthread_key_create(&_BITCrashCXXExceptionInfoTSDKey, free);
});

OSSpinLockLock(&_BITCrashCXXExceptionHandlingLock); {
if (!_BITCrashIsOurTerminateHandlerInstalled) {
_BITCrashOriginalTerminateHandler = std::set_terminate(BITCrashUncaughtCXXTerminateHandler);
_BITCrashIsOurTerminateHandlerInstalled = true;
}
_BITCrashUncaughtExceptionHandlerList.push_back(handler);
} OSSpinLockUnlock(&_BITCrashCXXExceptionHandlingLock);
}

+ (void)removeCXXExceptionHandler:(BITCrashUncaughtCXXExceptionHandler)handler
{
OSSpinLockLock(&_BITCrashCXXExceptionHandlingLock); {
auto i = std::find(_BITCrashUncaughtExceptionHandlerList.begin(), _BITCrashUncaughtExceptionHandlerList.end(), handler);

if (i != _BITCrashUncaughtExceptionHandlerList.end()) {
_BITCrashUncaughtExceptionHandlerList.erase(i);
}

if (_BITCrashIsOurTerminateHandlerInstalled) {
if (_BITCrashUncaughtExceptionHandlerList.empty()) {
std::terminate_handler previous_handler = std::set_terminate(_BITCrashOriginalTerminateHandler);

if (previous_handler != BITCrashUncaughtCXXTerminateHandler) {
std::set_terminate(previous_handler);
} else {
_BITCrashIsOurTerminateHandlerInstalled = false;
_BITCrashOriginalTerminateHandler = nullptr;
}
}
}
} OSSpinLockUnlock(&_BITCrashCXXExceptionHandlingLock);
}

@end
Loading

0 comments on commit 213b118

Please sign in to comment.