在公司比较闲,让帮忙改一个奇怪的crash,没有任何log,才搞半天,发现是由于LoadLevelAsync 的Thread Loading,在乱七八糟的android机器上出现问题了,空指针,访问没有loading完的Additive场景里的东西。
下面的代码在Galaxy S4上直接crash,而且没有任何log,太恶心人了,如果项目代码一大堆,用最原始的排除法也让你累吐血
public class Boot : MonoBehaviour
{
class TestNULL
{
public void Test()
{
Debug.Log("########## Test");
}
}
TestNULL _test = null;
void Start ()
{
_test.Test(); //没有NullPointer异常?!
}
整理了下,写了个Unity Plugin,准确定位空指针crash
void print_stack(void* ptr)
{
ucontext_t *ucontext = (ucontext_t*)ptr;
sigcontext& sig = ucontext->uc_mcontext;
gprintf("reg[fp]: %p", sig.arm_fp);
gprintf("reg[ip]: %p", sig.arm_ip);
gprintf("reg[sp]: %p", sig.arm_sp);
gprintf("reg[lr]: %p", sig.arm_lr);
gprintf("reg[pc]: %p", sig.arm_pc);
if(hasMono)
{
MonoDomain* domain = mono_get_root_domain();
mono_thread_attach(domain);
gprintf("mono trace:");
gprintf("%s", mono_pmip((void*)sig.arm_pc));
MonoJitInfo* jit = mono_jit_info_table_find(domain, (char*)sig.arm_pc);
if(jit)
{
uint32_t code_offset = (uint32_t)((uint8_t*)sig.arm_pc - (uint8_t*)jit->code_start);
MonoDebugSourceLocation* source = mono_debug_lookup_source_location (jit->method, code_offset, domain);
if (source) gprintf("\t %s:%d", source->source_file, source->row);
}
}
}
void signal_handler(int signum, siginfo_t *info, void * ptr)
{
if (info->si_addr == NULL)
{
gprintf("================NullPointerException Begin====================");
gprintf("\n");
print_stack(ptr);
gprintf("\n");
gprintf("================NullPointerException End====================");
}
else
{
gprintf("================UnKnownException Begin====================");
gprintf("\n");
print_stack(ptr);
gprintf("\n");
gprintf("================UnKnownException End====================");
}
signal(signum, SIG_DFL);
//kill(getpid(), signum);
}