2015-04-05 49 views
0

這是「APUE」第8章練習(習題8.2,第2版)。全部解釋爲:在函數中調用vfork(),對結果感到困惑

回想一下圖7.6中的典型內存排列。由於與每個函數調用相對應的堆棧幀 通常存儲在堆棧中,並且因爲子進程在父級的地址空間中運行,所以如果調用vfork 來自除main之外的函數並且孩子在vfork之後會從這個函數返回嗎?編寫一個測試程序來驗證這一點,並畫出發生的事情。

在我的程序:

static void f1(void), f2(void); 

int main(void) { 
    printf("main address: %d\n", main); 
    f1(); 
    f2(); 
    _exit(0); 
} 

static void f1(void) { 
    printf("f1 address: %d\n", f1); 
    pid_t pid; 

    if ((pid = vfork()) < 0) 
     err_sys("vfork error"); 
} 

static void f2(void) { 
    printf("f2 address: %d\n", f2); 
    char buf[1000]; 
    int i; 

    for (i = 0; i < sizeof(buf); ++i) 
     buf[i] = 0; 
} 

我運行程序,輸出:

main address: 4196560 
f1 address: 4196604 
f2 address: 4196663 
f1 address: 4196604 
[1] 12929 segmentation fault ./a.out 

我感到困惑的輸出。

  1. print f1 address: xxx,我們調用vfork(),子進程先運行。
  2. print f2 address: xxx,然後子進程調用_exit(0)。
  3. f1()的主進度返回值,f1的堆棧幀被f2修改,可能導致分段錯誤。

但是爲什麼打印f1 address: 4196604兩次,爲什麼f1和f2的地址不一樣?

+0

'buf'未初始化所以'strlen的(BUF)'是未定義的行爲(也可能是段錯誤的原因)。那是故意的嗎? – rici 2015-04-05 05:23:08

+0

是vfork在您的平臺上fork()的別名? – hd1 2015-04-05 05:40:03

+0

@rici sizeof(buf)是一樣的 – 2015-04-05 05:51:23

回答

0

我不確定你的意思是「f1的靜止幀被f2改變了」。

f2()中的代碼在任何情況下都可能出現分段錯誤,無論是vfork()buf未初始化。沒有理由相信它包含以空字符結尾的字符串。因此,撥打strlen()可能會讀取緩衝區的末尾。

無論如何,我不確定你期望循環做什麼。在第一次迭代中,i爲0.如果strlen()的調用不是segfault,則循環體在buf[0]中存儲0。因此,在循環的下一次迭代中,strlen(buf)將爲0,i將爲1(不小於0),因此循環將終止。

f1 address: 4196604的第二個打印是當父進程在vfork()ed子進程退出後繼續。父進程繼續並調用f1()來打印它。

打印的數字是f1f2自己的地址。你爲什麼期望f1的地址與f2的地址相同?他們不是,所以他們打印不同的地址。

另一方面,f1的地址在父進程和子進程中是相同的,因爲子進程共享父進程的地址空間。因此,兩次都打印相同的地址爲f1

+0

我用sizeof()更改strlen()。該代碼是「UNIX環境下的高級編程」的練習。 – 2015-04-05 05:57:03

+0

而且,在做出改變之後,它是否仍然存在分段錯誤? – 2015-04-05 18:45:03

+0

我更新了問題,你可以看看。更改後,仍然存在分段錯誤。 – 2015-04-06 14:15:37

0

根據vforkdocumentation,你不應該從當前函數返回。

的vfork()從叉不同(2)在調用線程被掛起 直到子終止(或者通常,通過調用_exit(2),或 異常,輸送致命信號之後),或者致電 execve(2)。在那之前,孩子與父母共享所有內存,包括堆棧。 孩子不得從 當前函數返回或調用退出(3),但可能會調用_exit(2)

另外,請注意:

的vfork()是克隆的特殊情況(2)。它是用於創建新的 進程而不復制父進程的頁表。它 可能是有用的性能敏感的應用程序,其中一個孩子是 創建,然後立即發出execve(2)。

由於vfork不會從父級複製頁表,所以不會從當前函數返回很多意義。當孩子退出時,它會將家長的堆棧框架搞亂。

您還可以查看following answer