软件测试之SDK开发(ios)——Cpp Exception捕获

ios虽然是用OC语言或Swift语言进行编程,但是它同时也支持c++语法,底层的动态库也基本上都是C++编写的。所以ios在运行的时候,可能会抛出C++异常,如果该C++异常可以被转换为NSException,就抛给OC异常的捕获机制。如果不能被转换,就继续C++的terminate流程,也就是default_terminate_handler。这个C++异常的默认terminate函数内部调用abort_message函数,最后触发了一个abort调用,系统产生一个SIGABRT信号。

通常情况下,在系统抛出C++异常后,如果被try/catch掉,再重新抛出的C++异常(因为要判断该C++异常是否可以被转换为NSException),异常的现场堆栈已经消失,所以上层通过捕获SIGABRT信号是无法还原发生异常时的场景,即通常我们说的异常堆栈缺失

为什么再重新抛出的C++异常的堆栈会消失,这个主要是因为try/cach语句内部会调用__cxa_rethrow()抛出异常,__cxa_rethrow()内部又会调用 unwindunwind可以简单理解为函数调用的逆调用,主要用来清理函数调用过程中每个函数生成的局部变量,一直到最外层的catch语句所在的函数,并把控制移交给catch语句,这就是C++异常的堆栈消失原因。

整个C++异常的触发和调用流程如下图所示:
在这里插入图片描述
可以使用std::set_terminate();设置崩溃回调,回调代码如下:

static void CPPExceptionTerminate(void){
    NSLog(@"Trapped c++ exception");
    const char* name = NULL;
    std::type_info* tinfo = __cxxabiv1::__cxa_current_exception_type();
    if(tinfo != NULL){
        name = tinfo->name();
    }
    if(name == NULL || strcmp(name, "NSException") != 0){
        
        char descriptionBuff[DESCRIPTION_BUFFER_LENGTH];
        const char* description = descriptionBuff;
        descriptionBuff[0] = 0;
        
        NSLog(@"Discovering what kind of exception was thrown.");
        
        captureStackTrace = false;
        
        try
        {
            throw;
        }
        catch(std::exception& exc)
        {
            strncpy(descriptionBuff, exc.what(), sizeof(descriptionBuff));
        }
#define CATCH_VALUE(TYPE, PRINTFTYPE) \
catch(TYPE value)\
{ \
snprintf(descriptionBuff, sizeof(descriptionBuff), "%" #PRINTFTYPE, value); \
}
        CATCH_VALUE(char,                 d)
        CATCH_VALUE(short,                d)
        CATCH_VALUE(int,                  d)
        CATCH_VALUE(long,                ld)
        CATCH_VALUE(long long,          lld)
        CATCH_VALUE(unsigned char,        u)
        CATCH_VALUE(unsigned short,       u)
        CATCH_VALUE(unsigned int,         u)
        CATCH_VALUE(unsigned long,       lu)
        CATCH_VALUE(unsigned long long, llu)
        CATCH_VALUE(float,                f)
        CATCH_VALUE(double,               f)
        CATCH_VALUE(long double,         Lf)
        CATCH_VALUE(char*,                s)
        catch(...)
        {
            description = NULL;
        }
        captureStackTrace = true;
        
        NSString * callStackSymbols = [BSBacktraceLogger bs_backtrace:backtraceBuffer backtraceLength:backtraceLength] ;
        
        NSString *date = [LLTool stringFromDate:[NSDate date]];
        NSArray *appInfos = [LLRoute appInfos];
        LLCrashModel *model = [[LLCrashModel alloc] initWithName:@"CPP Exception" reason:[NSString stringWithFormat:@"抛出异常:%@",description?[NSString stringWithUTF8String:description]:@"Unknown"] userInfo:nil stackSymbols:@[callStackSymbols] date:date userIdentity:[LLConfig sharedConfig].userIdentity appInfos:appInfos launchDate:[NSObject LL_launchDate]];
        [LLCrashSignalHelper sharedHelper].crashModel = model;
        [[LLStorageManager sharedManager] saveModel:model complete:^(BOOL result) {
            NSLog(@"Save mach model success");
        } synchronous:YES];
        
    }else{
        NSLog(@"Detected NSException. Letting the current NSException handler deal with it.");
    }
    
    NSLog(@"Calling original terminate handler.");
    
    originalTerminateHandler() ;
}

效果演示

C++异常如果通过signal机制进行捕获,会出现异常堆栈缺失问题。测试代码如下:

-(void)testCPPException{
   char* name= "测试Cpp Exception" ;
   throw name;
}

在这里插入图片描述
已经成功捕获了CPP Exception,该功能已经集成到了我开发的SDK里面,效果如下图所示:
在这里插入图片描述
通过CPP Exception的捕获成功将异常的堆栈进行还原,进入到Signal(SIGABRT),可以发现通过signal机制捕获的堆栈出现了异常堆栈缺失问题。如下图所示:
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
华睿相机和Basler相机都是工业相机,它们的SDK都是用于开发这些相机的应用程序。以下是一个简单的Basler相机SDK的C++例子,以打开相机、设置参数并捕获图像为例: ```c++ #include <pylon/PylonIncludes.h> #include <iostream> using namespace Pylon; using namespace std; int main() { // 初始化Pylon库 PylonInitialize(); try { // 创建一个Tl对象,可以用它来枚举连接的相机 CTlFactory& tlFactory = CTlFactory::GetInstance(); ITransportLayerPtr tl = tlFactory.CreateTl("BaslerGigE"); // 枚举连接的相机 DeviceInfoList_t devices; tl->EnumerateDevices(devices); if (devices.empty()) { throw RUNTIME_EXCEPTION("No camera present."); } // 创建一个相机对象 CInstantCamera camera(tl->CreateDevice(devices[0])); // 打开相机 camera.Open(); // 设置相机参数 camera.PixelFormat.SetValue(PixelFormat_Mono8); camera.Width.SetValue(640); camera.Height.SetValue(480); // 开始捕获图像 camera.StartGrabbing(); // 循环读取图像,直到用户按下键盘 while (camera.IsGrabbing()) { // 获取下一帧图像 CGrabResultPtr ptrGrabResult; camera.RetrieveResult(5000, ptrGrabResult, TimeoutHandling_ThrowException); // 检查图像是否有效 if (ptrGrabResult->GrabSucceeded()) { // 处理图像数据 // ... // 显示图像 cout << "Image grabbed." << endl; } } // 停止捕获图像 camera.StopGrabbing(); // 关闭相机 camera.Close(); } catch (const GenericException& e) { cerr << "An exception occurred: " << e.GetDescription() << endl; exitCode = 1; } // 释放Pylon库的资源 PylonTerminate(); return exitCode; } ``` 这个例子使用Pylon SDK来打开Basler相机,并设置像素格式、图像大小等参数,最后捕获图像并处理。你可以根据自己的需要修改这个例子来开发自己的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值