2012-12-12 63 views
2

編輯:找到的解決方案(參見下圖)Strsep我的Mac OS X x86_64系統上就返回一個32位指針

我試圖構建一個軟件包(owfs)在Mac OS X 10.8 x86_64的系統上。這個軟件包大部分是在Linux上開發的,但我已經得到了一箇舊版本來編譯和運行正確,並且在運行各種版本的人們的互聯網上有很多帖子,所以我希望這是可能的。我已經能夠成功完成編譯過程,但是當我嘗試運行它時,程序會出現段錯誤。我調查了GDB,這裏是我發現:

違規的一段代碼:

void FS_dir_entry_aliased(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn) 
{ 
if ((pn->state & ePS_unaliased) == 0) { 
    // Want alias substituted 
    struct parsedname s_pn_copy ; 
    struct parsedname * pn_copy = & s_pn_copy ; 

    ASCII path[PATH_MAX+3] ; 
    ASCII * path_pointer = path ; // current location in original path 

    // Shallow copy 
    memcpy(pn_copy, pn, sizeof(struct parsedname)) ; 
    pn_copy->path[0] = '\0' ; 

    // path copy to use for separation 
    strcpy(path, pn->path) ; 

    // copy segments of path (delimitted by "/") to copy 
    while(path_pointer != NULL) { 
        ASCII * path_segment = NULL; 
     path_segment = strsep(&path_pointer, "/") ; 
     BYTE sn[SERIAL_NUMBER_SIZE] ; 

     if (PATH_MAX < strlen(pn_copy->path) + strlen(path_segment)) { 

因爲path_segment是越界,地址在ifstrlen(path_segment)調用失敗。

把事情一步一步與GDB,這是我找到的。進入初始化path_segmentstrsep通話,GDB給我:

path_pointer = (ASCII *) 0x7fff5fbf99a5 "/uncached/bus.0/interface" 

我執行下一行後,path_pointer擁有先進的,因爲我希望:

path_pointer = (ASCII *) 0x7fff5fbf99a6 "uncached/bus.0/interface" 

但GDB報告:

path_segment = (ASCII *) 0x5fbf99a5 <Address 0x5fbf99a5 out of bounds> 

這是地址的正確「開始」,但它是一個32位指針地址。由於我的系統是一個64位系統,因此當調用strlen時,我得到一個EXC_BAD_ACCESS。

我知道這裏有很多事情要做,如果問題深深隱藏在包構建過程中,我還沒有提供足夠的信息。在我看來,這可能有一個簡單的解決方案,因爲函數基本上正常工作,但只是返回錯誤的大小指針。儘管我對64位和32位系統錯綜複雜的經驗很少,所以我想知道是否有人能夠發現一些明顯的東西,或者提供下一步調試問題的說明。有趣的是,當我在gdb(p (ASCII *) strsep (&path_pointer, "/"))中手動運行strsep命令時,它們看起來工作正常,給了我64位指針,它與我所期望的匹配。

最後,在情況下,它是非常有用的,這是我相信都爲strsep呼叫裝配線:

0x0000000100036eee <FS_dir_entry_aliased+318>: callq 0x1000a56a0 <dyld_stub_strsep> 
0x0000000100036ef3 <FS_dir_entry_aliased+323>: mov %eax,%ecx 
0x0000000100036ef5 <FS_dir_entry_aliased+325>: movslq %ecx,%rcx 
0x0000000100036ef8 <FS_dir_entry_aliased+328>: mov %rcx,-0x1d10(%rbp) 

和拆卸,這是在那個callq地址strsep:

0x00007fff915c0fc7 <strsep+0>: push %rbp 
0x00007fff915c0fc8 <strsep+1>: mov %rsp,%rbp 
0x00007fff915c0fcb <strsep+4>: mov (%rdi),%r8 
0x00007fff915c0fce <strsep+7>: xor %eax,%eax 
0x00007fff915c0fd0 <strsep+9>: test %r8,%r8 
0x00007fff915c0fd3 <strsep+12>: je  0x7fff915c1007 <strsep+64> 
0x00007fff915c0fd5 <strsep+14>: mov %r8,%r10 
0x00007fff915c0fd8 <strsep+17>: jmp 0x7fff915c0fe4 <strsep+29> 
0x00007fff915c0fda <strsep+19>: inc %rdx 
0x00007fff915c0fdd <strsep+22>: test %al,%al 
0x00007fff915c0fdf <strsep+24>: jne 0x7fff915c0fee <strsep+39> 
0x00007fff915c0fe1 <strsep+26>: mov %r9,%r10 
0x00007fff915c0fe4 <strsep+29>: mov (%r10),%cl 
0x00007fff915c0fe7 <strsep+32>: lea 0x1(%r10),%r9 
0x00007fff915c0feb <strsep+36>: mov %rsi,%rdx 
0x00007fff915c0fee <strsep+39>: mov (%rdx),%al 
0x00007fff915c0ff0 <strsep+41>: cmp %cl,%al 
0x00007fff915c0ff2 <strsep+43>: jne 0x7fff915c0fda <strsep+19> 
0x00007fff915c0ff4 <strsep+45>: xor %edx,%edx 
0x00007fff915c0ff6 <strsep+47>: test %cl,%cl 
0x00007fff915c0ff8 <strsep+49>: je  0x7fff915c1001 <strsep+58> 
0x00007fff915c0ffa <strsep+51>: movb $0x0,(%r10) 
0x00007fff915c0ffe <strsep+55>: mov %r9,%rdx 
0x00007fff915c1001 <strsep+58>: mov %rdx,(%rdi) 
0x00007fff915c1004 <strsep+61>: mov %r8,%rax 
0x00007fff915c1007 <strsep+64>: pop %rbp 
0x00007fff915c1008 <strsep+65>: retq 

編輯: string.h肯定被包含在內,有一個包含它的系統範圍的包含文件,但只是爲了確保我試圖添加它這個特定的文件。 -D_BSD_SOURCE=1是自動添加的編譯器選項之一,因此正在發生。默認情況下,還有一個編譯器選項-D_ISOC99_SOURCE=1。我試着加入-std=gnu99(我的編譯器,llvm-gcc 4.2,不喜歡-std=gnu90),但它沒有修復它。我得到以下編譯器錯誤:

以下是編譯器警告,我得到了這個文件:

ow_alias.c: In function 'ReadAliasFile': 
ow_alias.c:40: warning: implicit declaration of function 'getline' 
ow_alias.c:48: warning: implicit declaration of function 'strsep' 
ow_alias.c:48: warning: assignment makes pointer from integer without a cast 
ow_alias.c:64: warning: assignment makes pointer from integer without a cast 
ow_alias.c: In function 'FS_dir_entry_aliased': 
ow_alias.c:177: warning: initialization makes pointer from integer without a cast 

第二個編輯:(!感謝gcc -E | grep strsep TIP) 做多一點挖後,我發現問題是編譯器標誌-D_POSIX_C_SOURCE=200112L。此編譯器標誌阻止了strsep的定義,從而使編譯器進行了隱式聲明。我從配置腳本中刪除了這一切,似乎一切正常。謝謝您的幫助!

+3

是否違規編譯單元'#include '?如果是這樣,cc -E |是什麼grep strsep'顯示'strsep'被聲明爲? – user4815162342

+0

使用'gcc -I./module/owlib/src/include -I/opt/local/include -I./src/include -E module/owlib/src/c/ow_alias.c | grep strsep',我得到strsep聲明爲'char * strsep(char **,const char *);',這看起來是正確的。但是在完整的Make過程中,我在編輯上面得到編譯器警告...... – bencpeters

回答

5

您需要確保包含string.h

如果這已經完成,您還需要定義一個特徵測試宏以啓用strsep()的聲明。添加-D_GNU_SOURCE-D_BSD_SOURCE應該做的伎倆。但是,您可能想要了解如何配置當前的配置 - 默認情況下啓用_BSD_SOURCE。也許你正在告訴gcc使用-std=c90-std=c99進行編譯,這將關閉許多功能測試宏。改爲使用-std=gnu90-std=gnu99

你看到警告,例如「初始化使得沒有轉換的整型指針」或「隱式函數聲明」?

+1

+1;反彙編顯示編譯器認爲'strsep'返回一個32位值(例如一個int)。 –

+0

這似乎是在正確的軌道上,但我仍然無法使其工作。看我的編輯原始問題 - 我試過'-std = c99'和'D_BSD_SOURCE'已經發生。編譯器的警告確認發生了什麼,編譯器認爲strsep正在返回一個int,而不是size_t指針。 – bencpeters