Unity c# 空指针

在公司比较闲,让帮忙改一个奇怪的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);
}