2013-05-03 47 views
2

在OS X並行線程執行(http://www.opensource.apple.com/source/Libc/Libc-825.26/pthreads/thread_setup.c?txt)所提供的線程堆棧上的假返回地址(行140):Mac OS X的並行線程假回郵地址

ts->rip = (uintptr_t) routine; 

    /* 
    ** We need to simulate a 16-byte aligned stack frame as if we had 
    ** executed a call instruction. The stack should already be aligned 
    ** before it comes to us and we don't need to push any arguments, 
    ** so we shouldn't need to change it. 
    */ 

    ts->rdi = (uintptr_t) thread; /* argument to function */ 
    *--sp = 0;   /* fake return address */ 
    ts->rsp = (uintptr_t) sp; /* set stack pointer */ 

我不明白這是如何不會崩潰如果線程正在執行的函數調用'ret'並從堆棧中彈出返回地址,則使用非法指令/ segfault。任何人都可以解釋如何防止/處理?

回答

3

不看代碼的其餘部分,我只能大膽猜測。我的直覺說,被調用線程程序(用戶提供start_routine參數)應該從未返回給調用函數。

想一想:如果新線程確實返回了,那麼您將有兩個線程在相同的原始代碼路徑上運行。我想,線程函數是實際上稱爲是調用的包裝用戶提供start_routine。當start_routine返回時,包裝器將調用pthread_exit

(main thread) 
    v 
pthread_create 
    v 
thread_setup (sets up stack), and spawns new thread 
    v          | 
return to main thread      | 
              | 
              | 
              v 
             wrapper_function 
              v 
        user-supplied start_routine 
              | (returns) 
              v 
           wrapper_function calls 
              v 
            pthread_exit 

同樣,這只是一個猜測,但整個的一點是,新的線程應該從未返回到調用pthread_create的代碼。包裝的目的將是確保pthread_exit被調用。

我會看到他們在傳遞什麼作爲routinethread_setup

我的感情的事實,you don't have to call pthread_exit證實。

+2

事實上,傳遞給'_pthread_setup'的「例程」似乎總是「_pthread_body」(在該文件中搜索該標識符:http://www.opensource.apple.com/source/Libc/Libc-825.26/ pthreads/pthread.c),它完全符合你推測包裝會做的事情。 * actual *線程worker(最初傳遞給'pthread_create'的函數指針)隱藏在'pthread_t'對象內。我不知道爲什麼'thread_setup'在它自己的文件中,但是這種低級代碼往往是一團糟。 – zwol 2013-05-03 01:46:33

+2

,來到想起來了,「假返回地址」的'thread_setup'點可能是保證,如果包裝過不會返回(這將是在C庫中的缺陷,但仍),你會得到一個*可預測*崩潰,而不是跳轉到某個實際上可能有代碼的隨機地址。 – zwol 2013-05-03 01:49:05

+0

@Zack感謝您確認所有這些!我回答時沒有時間仔細研究,所以我很感激你跟進。 – 2013-05-03 05:21:16