#include <signal.h>
#include <execinfo.h>
void handleExceptions(NSException *exception) {
NSLog(@"*****************************************************************");
NSLog(@"exception 0000000000000 = %@",exception);
NSLog(@"*****************************************************************");
NSLog(@"callStackSymbols 11111111111111 = %@",[exception callStackSymbols]);
NSLog(@"*****************************************************************");
}
void signalHandler(int sig) {
//最好不要写,可能会打印太多内容
NSLog(@"*****************************************************************");
NSLog(@"signal 22222222222 = %d", sig);
NSLog(@"*****************************************************************");
}
- (void)initHandler {
struct sigaction newSignalAction;
memset(&newSignalAction, 0,sizeof(newSignalAction));
newSignalAction.sa_handler = &signalHandler;
sigaction(SIGABRT, &newSignalAction, NULL);
sigaction(SIGILL, &newSignalAction, NULL);
sigaction(SIGSEGV, &newSignalAction, NULL);
sigaction(SIGFPE, &newSignalAction, NULL);
sigaction(SIGBUS, &newSignalAction, NULL);
sigaction(SIGPIPE, &newSignalAction, NULL);
//异常时调用的函数
NSSetUncaughtExceptionHandler(&handleExceptions);
}
memset(&newSignalAction, 0,sizeof(newSignalAction));
给newSignalAction 结构体设置初始值
sigaction(SIGABRT, &newSignalAction, NULL);
sigaction(SIGILL, &newSignalAction, NULL);
sigaction(SIGSEGV, &newSignalAction, NULL);
sigaction(SIGFPE, &newSignalAction, NULL);
sigaction(SIGBUS, &newSignalAction, NULL);
sigaction(SIGPIPE, &newSignalAction, NULL);
标记需要捕获的crash类型
NSSetUncaughtExceptionHandler(NSUncaughtExceptionHandler *handler)
{
_NSUncaughtExceptionHandler = handler;
}
传入的 handler 被NSException类对象持有
接着callUncaughtHandler会调用_NSUncaughtExceptionHandler
static void
callUncaughtHandler(id value)
{
if (_NSUncaughtExceptionHandler != NULL)
{
(*_NSUncaughtExceptionHandler)(value);
}
_NSFoundationUncaughtExceptionHandler(value);
}
且NSException 初始化时也会注册调用对应的方法
+ (void) initialize
{
if (self == [NSException class])
{
#if defined(_NATIVE_OBJC_EXCEPTIONS)
# ifdef HAVE_SET_UNCAUGHT_EXCEPTION_HANDLER
objc_setUncaughtExceptionHandler(callUncaughtHandler);
# elif defined(HAVE_UNEXPECTED)
_objc_unexpected_exception = callUncaughtHandler;
# elif defined(HAVE_SET_UNEXPECTED)
objc_set_unexpected(callUncaughtHandler);
# endif
#endif
}
}
调用 [NSException raise: NSGenericException format: @"Terminate"];
NSException *obj;
NSMutableArray *testObjs = [[NSMutableArray alloc] init];
NSAutoreleasePool *arp = [NSAutoreleasePool new];
test_alloc_only(@"NSException");
obj = [NSException exceptionWithName: NSGenericException
reason: nil
userInfo: nil];
PASS((obj != nil), "can create an exception");
PASS(([[obj name] isEqualToString: NSGenericException]), "name works");
obj = [NSException exceptionWithName: NSGenericException
reason: nil
userInfo: nil];
[testObjs addObject: obj];
test_NSObject(@"NSException", testObjs);
NS_DURING
[MyClass testAbc];
NS_HANDLER
{
NSArray *addresses = [localException callStackReturnAddresses];
NSArray *a = [localException callStackSymbols];
NSEnumerator *e = [a objectEnumerator];
NSString *s = nil;
PASS([addresses count] > 0, "call stack addresses is not empty");
PASS([addresses count] == [a count], "addresses and symbols match");
NSLog(@"Got %@", a);
while ((s = [e nextObject]) != nil)
if ([s rangeOfString: @"testAbc"].length > 0)
break;
testHopeful = YES;
PASS(s != nil, "working callStackSymbols ... if this has failed it is probably due to a lack of support for objective-c method names (local symbols) in the backtrace_symbols() function of your libc. If so, you might lobby your operating system provider for a fix.");
testHopeful = NO;
}
NS_ENDHANDLER
PASS(NSGetUncaughtExceptionHandler() == 0, "default handler is null");
NSSetUncaughtExceptionHandler(handler);
PASS(NSGetUncaughtExceptionHandler() == handler, "setting handler works");
fprintf(stderr, "We expect a single FAIL without any explanation as\n"
"the test is terminated by an uncaught exception ...\n");
[NSException raise: NSGenericException format: @"Terminate"];
PASS(NO, "shouldn't get here ... exception should have terminated process");
[arp release]; arp = nil;
接着会来到调用:
(void) raise: (NSString)name
format: (NSString)format,...
(void) raise: (NSString)name
format: (NSString)format
arguments: (va_list)argList
+ (void) raise: (NSString*)name
format: (NSString*)format,...
{
va_list args;
va_start(args, format);
[self raise: name format: format arguments: args];
// This probably doesn't matter, but va_end won't get called
va_end(args);
while (1); // does not return
}
+ (void) raise: (NSString*)name
format: (NSString*)format
arguments: (va_list)argList
{
NSString *reason;
NSException *except;
reason = [NSString stringWithFormat: format arguments: argList];
except = [self exceptionWithName: name reason: reason userInfo: nil];
[except raise];
while (1); // does not return
}
其中:[except raise]; 里面会调用 callUncaughtHandler(self);
- (void) raise
{
if (_reserved == 0)
{
_reserved = NSZoneCalloc([self zone], 2, sizeof(id));
}
if (nil == _e_stack)
{
// Only set the stack when first raised
_e_stack = [GSStackTrace new];
[_e_stack trace];
}
#if defined(_NATIVE_OBJC_EXCEPTIONS)
@throw self;
#else
{
NSThread *thread;
NSHandler *handler;
thread = GSCurrentThread();
handler = thread->_exception_handler;
if (NULL == handler)
{
static int recursion = 0;
/*
* Set/check a counter to prevent recursive uncaught exceptions.
* Allow a little recursion in case we have different handlers
* being tried.
*/
if (recursion++ > 3)
{
fprintf(stderr,
"recursion encountered handling uncaught exception\n");
fflush(stderr); /* NEEDED UNDER MINGW */
_terminate();
}
/*
* Call the uncaught exception handler (if there is one).
* The calls the built-in default handler to terminate the program!
*/
callUncaughtHandler(self);
}
else
{
thread->_exception_handler = handler->next;
handler->exception = self;
longjmp(handler->jumpState, 1);
}
}
#endif
while (1); // does not return
}
最后:callUncaughtHandler 会调用会上层函数的回调监听: NSSetUncaughtExceptionHandler(&handleExceptions);
那么问题来了:如何触发异常捕获调用呢?
查看NSObject 对象的底层实现,会有一些不合法的判断,在不合法的地方调用
+ (void) raise: (NSString*)name
format: (NSString*)format,...
if (anObject == nil)
[NSException raise: NSInvalidArgumentException
format: @"Attempt to add nil to an array"];
- (NSArray*) arrayByAddingObject: (id)anObject
{
id na;
NSUInteger c = [self count];
if (anObject == nil)
[NSException raise: NSInvalidArgumentException
format: @"Attempt to add nil to an array"];
if (c == 0)
{
na = [[GSArrayClass allocWithZone: NSDefaultMallocZone()]
initWithObjects: &anObject count: 1];
}
else
{
GS_BEGINIDBUF(objects, c+1);
[self getObjects: objects];
objects[c] = anObject;
na = [[GSArrayClass allocWithZone: NSDefaultMallocZone()]
initWithObjects: objects count: c+1];
GS_ENDIDBUF();
}
return AUTORELEASE(na);
}
符号表的调用
获取符号表 由 GSStackTrace 类对象调用symbols 获得
- (NSArray*) symbols
{
if (nil == symbols && numReturns > FrameOffset)
{
NSInteger count = numReturns - FrameOffset;
NSUInteger i;
#if defined(USE_BFD)
void **ptrs = (void**)&returns[FrameOffset];
NSMutableArray *a;
a = [[NSMutableArray alloc] initWithCapacity: count];
for (i = 0; i < count; i++)
{
GSFunctionInfo *aFrame = nil;
void *address = (void*)*ptrs++;
void *base;
NSString *modulePath;
GSBinaryFileInfo *bfi;
modulePath = GSPrivateBaseAddress(address, &base);
if (modulePath != nil && (bfi = GSLoadModule(modulePath)) != nil)
{
aFrame = [bfi functionForAddress: (void*)(address - base)];
if (aFrame == nil)
{
/* We know we have the right module but function lookup
* failed ... perhaps we need to use the absolute
* address rather than offest by 'base' in this case.
*/
aFrame = [bfi functionForAddress: address];
}
}
else
{
NSArray *modules;
int j;
int m;
modules = GSListModules();
m = [modules count];
for (j = 0; j < m; j++)
{
bfi = [modules objectAtIndex: j];
if ((id)bfi != (id)[NSNull null])
{
aFrame = [bfi functionForAddress: address];
if (aFrame != nil)
{
break;
}
}
}
}
// not found (?!), add an 'unknown' function
if (aFrame == nil)
{
aFrame = [GSFunctionInfo alloc];
[aFrame initWithModule: nil
address: address
file: nil
function: nil
line: 0];
[aFrame autorelease];
}
[a addObject: [aFrame description]];
}
symbols = [a copy];
[a release];
#elif defined(_WIN32)
void **ptrs = (void**)&returns[FrameOffset];
SYMBOL_INFO *symbol;
NSString *syms[MAXFRAMES];
symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO)
+ 1024 * sizeof(char), 1);
symbol->MaxNameLen = 1024;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
(void)pthread_mutex_lock(&traceLock);
for (i = 0; i < count; i++)
{
NSUInteger addr = (NSUInteger)*ptrs++;
if ((fromSym)(hProcess, (DWORD64)addr, 0, symbol))
{
syms[i] = [NSString stringWithFormat:
@"%s - %p", symbol->Name, addr];
}
else
{
syms[i] = [NSString stringWithFormat:
@"unknown - %p", symbol->Name, addr];
}
}
(void)pthread_mutex_unlock(&traceLock);
free(symbol);
symbols = [[NSArray alloc] initWithObjects: syms count: count];
#elif defined(HAVE_BACKTRACE)
void **ptrs = (void**)&returns[FrameOffset];
char **strs;
NSString **symbolArray;
strs = backtrace_symbols(ptrs, count);
symbolArray = alloca(count * sizeof(NSString*));
for (i = 0; i < count; i++)
{
symbolArray[i] = [NSString stringWithUTF8String: strs[i]];
}
symbols = [[NSArray alloc] initWithObjects: symbolArray count: count];
free(strs);
#elif defined(WITH_UNWIND)
void **ptrs = (void**)&returns[FrameOffset];
NSString **symbolArray;
symbolArray = alloca(count * sizeof(NSString*));
for (i = 0; i < count; i++)
{
const void *addr = ptrs[i];
Dl_info info;
if (dladdr(addr, &info)) {
const char *libname = "unknown";
if (info.dli_fname) {
// strip library path
char *delim = strrchr(info.dli_fname, '/');
libname = delim ? delim + 1 : info.dli_fname;
}
if (info.dli_sname) {
symbolArray[i] = [NSString stringWithFormat:
@"%lu: %p %s %s + %d", (unsigned long)i, addr, libname,
info.dli_sname, (int)(addr - info.dli_saddr)];
} else {
symbolArray[i] = [NSString stringWithFormat:
@"%lu: %p %s unknown", (unsigned long)i, addr, libname];
}
} else {
symbolArray[i] = [NSString stringWithFormat:
@"%lu: %p unknown", (unsigned long)i, addr];
}
}
symbols = [[NSArray alloc] initWithObjects: symbolArray count: count];
#else
NSMutableArray *a;
symbols = a = [[self addresses] mutableCopy];
for (i = 0; i < count; i++)
{
NSString *s;
s = [[NSString alloc] initWithFormat: @"%p: symbol not available",
[[a objectAtIndex: i] pointerValue]];
[a replaceObjectAtIndex: i withObject: s];
RELEASE(s);
}
#endif
}
return symbols;
}
我正在尝试使用ruby编写一个双线程客户端,一个线程从套接字读取数据并将其打印出来,另一个线程读取本地数据并将其发送到远程服务器。我发现的问题是Ruby似乎无法捕获线程内的错误,这是一个示例:#!/usr/bin/rubyThread.new{loop{$stdout.puts"hi"abc.putsefsleep1}}loop{sleep1}显然,如果我在线程外键入abc.putsef,代码将永远不会运行,因为Ruby将报告“undefinedvariableabc”。但是,如果它在一个线程内,则没有错误报告。我的问题是,如何让Ruby捕获这样的错误?或者至少,报告线程中的错误?
我在使用自定义RailsFormBuilder时遇到了问题,从昨天晚上开始我就发疯了。基本上我想对我的构建器方法之一有一个可选block,以便我可以在我的主要content_tag中显示其他内容。:defform_field(method,&block)content_tag(:div,class:'field')doconcatlabel(method,"Label#{method}")concattext_field(method)capture(&block)ifblock_given?endend当我在我的一个Slim模板中调用该方法时,如下所示:=f.form_field:e
我想从rubyrake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调
我有一个像这样的ruby类:require'logger'classTdefdo_somethinglog=Logger.new(STDERR)log.info("Hereisaninfomessage")endend测试脚本行如下:#!/usr/bin/envrubygem"minitest"require'minitest/autorun'require_relative't'classTestMailProcessorClasses当我运行这个测试时,out和err都是空字符串。我看到消息打印在stderr上(在终端上)。有没有办法让Logger和capture_io一起玩得
关于SSHkit-Github它说:Allbackendssupporttheexecute(*args),test(*args)&capture(*args)来自SSHkit-Rubydoc,我明白execute实际上是test的别名?test之间有什么区别?,execute,capture在Capistrano/SSHKit中我应该什么时候使用? 最佳答案 执行只是执行命令。使用非0退出引发错误。测试方法的行为与execute完全相同,但是它返回bool值(true如果命令以0退出,而false否则)。它通常用于控制任务中的流程
我们如何捕获或/和处理ruby中所有未处理的异常?例如,这样做的动机可能是将某种异常记录到不同的文件或发送电子邮件给系统管理。在Java中我们会做Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandlerex);在Node.js中process.on('uncaughtException',function(error){/*code*/});在PHP中register_shutdown_function('errorHandler');functionerrorHandler(){$error=error_
这就是我做的a="%span.rockets#diamonds.ribbons.forever"a=a.match(/(^\%\w+)([\.|\#]\w+)+/)putsa.inspect这是我得到的#这就是我想要的#帮助?我尝试过但失败了:( 最佳答案 通常,您不能获得任意数量的捕获组,但如果您使用扫描,您可以为您想要捕获的每个标记获得一个匹配:a="%span.rockets#diamonds.ribbons.forever"a=a.scan(/^%\w+|\G[.|#]\w+/)putsa.inspect["%span","
我希望访问我机器上的所有HTTP流量(我的Windows机器-不是服务器)。据我了解,拥有一个本地代理是所有流量路线的必经之路。我一直在谷歌搜索但未能找到任何资源(关于Ruby)来帮助我。非常感谢任何提示或链接。 最佳答案 WEBrick中有一个HTTP代理(Rubystdlib的一部分)和here's一个实现示例。如果你喜欢生活在边缘,还有em-proxy伊利亚·格里戈里克。这postIlya暗示它似乎确实需要一些调整来解决您的问题。 关于ruby-如何捕获所有HTTP流量(本地代理)
我目前可以将stdout重定向到ruby/rails中的字符串变量,只需在bash中运行命令并将结果设置为我的字符串变量,如下所示。val=%x[#{cmd}]其中cmd是表示bash命令的字符串。但是,这仅捕获stdout,因为我想捕获stderr并将其设置为ruby中的字符串——有什么想法吗? 最佳答案 简单地重定向它:val=%x[#{cmd}2>&1]如果您只想从stderr捕获输出,请在将其复制到fd2后关闭stdout的文件描述符。val=%x[#{cmd}2>&1>/dev/null]
是否可以在Ruby上使用正则表达式捕获字符串中所有相同数字的grous?我不熟悉正则表达式。我的意思是:"1112234444"上的正则表达式将生成["111","22","3","4444"]我知道,我可以使用(\d)(\1*),但它在每场比赛中只给我2个组。["1","11"],["2","2"],["3",-],["4","444"]如何在每场比赛中获得一组?谢谢。 最佳答案 在这里,试一试:((\d)\2*) 关于ruby-正则表达式在Ruby中捕获相同数字的组,我们在Stack