Unity c# 空指针

在公司比较闲,让帮忙改一个奇怪的crash,没有任何log,才搞半天,发现是由于LoadLevelAsync 的Thread Loading,在乱七八糟的android机器上出现问题了,空指针,访问没有loading完的Additive场景里的东西。

下面的代码在Galaxy S4上直接crash,而且没有任何log,太恶心人了,如果项目代码一大堆,用最原始的排除法也让你累吐血

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Boot : MonoBehaviour
{
    class TestNULL
    {
        public void Test()
        {
            Debug.Log("########## Test");
        }
    }
     
    TestNULL _test = null;
     
    void Start ()
    {
        _test.Test(); //没有NullPointer异常?!
    }

整理了下,写了个Unity Plugin,准确定位空指针crash

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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);
}

Posix semaphore blocked by Mac Store sandbox

sem_open无法在Mac Store App中使用,会被sandbox denied,需要额外的权限,为保险起见,还是不要使用,免得被Apple拒了

以下代码无法通过

1
2
3
4
5
6
7
#include <semaphore.h>
 
sem_t * pSemaphore = sem_open(name, O_CREAT, 0777, 1);
if (pSemaphore == (sem_t *)SEM_FAILED)
{
    //... 
}

用pthread_mutex替代

1
2
3
4
5
6
7
8
#include <pthread.h>
 
pthread_mutex_t* pSemaphore = (pthread_mutex_t *)BL_MALLOC(sizeof(pthread_mutex_t));
int ret = pthread_mutex_init(pSemaphore, NULL);
if (ret != 0)
{
    //... 
}