2012-08-15 39 views
0

我一直在研究一個在專用Linux CentOS系統上工作正常的項目。在虛擬機中使用GDB來調試Python ctypes segfaults

總的想法是,有一個Python的工作流程管理器比用C寫的使用ctypes的調用共享庫。它工作正常。

然而,需要我有項目用於開發目的的本地實例已經上來了。我在Windows 7下設置了VMWare的Linux Mint虛擬機。大多數情況下,一切正常。

的問題是一個模塊與分段故障時調用的共享庫中的一個的功能崩潰。通常情況下,這是可以的,在專用的Linux機器上,使用諸如「gdb python corename」之類的東西,可以讓我確切地看到它墜毀的位置並解決問題。

但是,在本地設置我有問題。我最關注的是GDB不報告正確的內存地址。這是一個龐大的工程,所以我不能發佈所有的代碼,但我會給出一個破敗:

Python模塊創建一個「FILE_PATH」變量,一個字符串。它首先將它傳遞給某個共享庫來加載文件。如果我執行命令,在python

hex(id(file_path)) 

它會返回類似'46cb4ec'的東西。在第一個共享庫,它是C,I啓動它不與

printf("file_pathaddress = %x\n", &file_path[0]); 

並輸出「FILE_PATH地址= 46cb4ec」,這是相同的我通過Python的「的id()」函數得到。我猜這是預期的...?

不管怎麼說..我這個相同的變量發送到另一個共享庫,但它在這一呼籲立即崩潰。如果我分析核心文件,它顯示它在函數調用本身上崩潰,而不是函數內的一行。奇怪的是,它的輸出是這樣的:

Program terminated with signal 11, Segmentation fault. 
#0 0x00007f124448c9fc in seam_processor (irm_filename=<error reading variable: Cannot access memory at address 0x7fff5fab51b8>, 
seam_data_path=<error reading variable: Cannot access memory at address 0x7fff5fab51b0>, 
    full_data_path=<error reading variable: Cannot access memory at address 0x7fff5fab51a8>, ranges=<error reading variable: Cannot access memory at address 0x7fff5fab51a0>, 
    job_id=<error reading variable: Cannot access memory at address 0x7fff5fab519c>, job_owner=<error reading variable: Cannot access memory at address 0x7fff5fab5198>, 
    y_tile_in=1, x_tile_in=1, fc_int=10650000000, atmos_props=..., surf_props=..., extra_props=<error reading variable: Cannot access memory at address 0x7fff5fab5190>, 
    gascalc_ftype=513, len_gas_sectrum=16, vect_spec_fq=<error reading variable: Cannot access memory at address 0x7fff5fab5188>, surfscat_theta_inc_vector_size=6, 
    surfscat_theta_inc_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5180>, surfscat_phi_inc_vector_size=6, 
    surfscat_phi_inc_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5178>, surfscat_theta_scat_vector_size=6, 
    surfscat_theta_scat_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5170>, surfscat_phi_scat_vector_size=6, 
    surfscat_phi_scat_vector=<error reading variable: Cannot access memory at address 0x7fff5fab5168>) at src/seam_processor.c:47 

所以,我不明白爲什麼GDB報告這些內存地址是這樣的。在這種情況下,'irm_filename'變量是Python作爲'file_path'傳入的內容,因此其地址應該是其他庫和id()函數報告的內容0x46CB4EC。爲什麼不同?然而,奇怪的是有些變量很好,比如'y_tile_in'。如果我在gdb:

所以,雖然它可以讀取該內存地址,這是不一樣的東西Python的ID()將報告,或者什麼類似C的printf()的地址將報告在一個不會崩潰的庫中。而且,這些內存地址真的很大,比我目前的內存量還要大......他們的真正含義是什麼?

那麼我的問題是這裏究竟發生了什麼?這是否正在虛擬機中運行?有一些映射正在進行嗎?我一直沒能找到任何關於網上一些不同的事情我不得不如果在虛擬機用gdb做的,所以我在虧損...

任何人都知道這是怎麼回事?

謝謝。

編輯

所以,這個問題已經變得陌生。基本上,我將庫中的所有代碼都註釋掉了,並且調用了相同的函數。當我這樣做並使用斷點在gdb中運行它時,它在函數調用中打印的所有內存地址都是正常的,匹配Python id()函數並匹配地址上的printf()。

我開始取消註釋代碼以查看問題的原因。問題是與聲明:

double nrcs_h_d[MAX_NINC_S*MAX_SCAT_S]; 
double nrcs_v_d[MAX_NINC_S*MAX_SCAT_S]; 

如果我註釋掉兩條線,沒有崩潰。如果我只評論第二行,那就沒有崩潰。如果沒有行被註釋掉,但它會崩潰。

奇怪的是,MAX_NINC_S和MAX_SCAT_S都等於500.所以,這些數組的大小隻有幾兆字節......其他幾百兆字節的代碼數組分配得很好。

另外,如果我用替換上述行:

double *nrcs_h_d, *nrcs_v_d; 
nrcs_h_d = (double *)malloc(MAX_NINC_S*MAX_SCAT_S*sizeof(double)); 
nrcs_v_d = (double *)malloc(MAX_NINC_S*MAX_SCAT_S*sizeof(double)); 

這似乎很好地工作......因此很明顯,這個問題是有關試圖分配過多的堆棧。

所以,問題變成了:

爲什麼GDB沒有顯示這是那裏的分割發生故障的代碼行,而是說,這是函數調用?

爲什麼核心轉儲文件的內存地址似乎全部搞砸了?

謝謝。

+0

僅在win7機器上的segfault還是兩者兼而有之?你用什麼版本的C編譯器來編譯C模塊? – 2012-08-15 19:48:37

回答

0

回想一下,堆空間向下增長,而堆空間向上增長;靠近虛擬內存空間頂部的地址(例如0x7fff5fab51b0)是堆棧分配變量,而接近底部的地址(例如0x46cb4ec)是堆分配變量。請注意,虛擬內存空間通常比物理內存大得多,它看起來像您的操作系統和體系結構支持高達128 GiB的虛擬內存。

由於Python在很大程度上依賴於動態內存分配,它最終會將其對象放在堆上,這就是爲什麼id()傾向於返回偏低地址的原因。如果C代碼將任何值複製到堆棧分配的變量,然後嘗試使用這些本地副本調用函數,則會再次看到高端地址。

有一個行號提供:src/seam_processor.c:47 那裏有什麼有趣的嗎? GDB抱怨的各種內存地址是堆棧上的各種內存地址,它們都是順序的,幾乎所有這些地址本身看起來都是指針(因爲它們都是8個字節寬)。

(這是我可以給出的最好的答案,隨時提供修改或提供更多信息。)

+0

謝謝。行號只是函數聲明的一行,這就是爲什麼很難找出導致錯誤的原因。因爲gdb顯示了所有這些無效的內存地址,並且它說它在函數聲明的行中崩潰,而不是該數組被分配的行誤導了我。 – tuttleorbuttle 2012-08-15 20:49:47

+0

@ user1601315好的。現在工作嗎?讓我知道你是否需要清理其他任何東西。 – atomicinf 2012-08-15 20:59:32

0

一種可能的解釋是,在執行某個函數中的任何代碼之前,函數中的局部變量的數據分配發生。

編譯器計算所需的堆棧空間量並在獲取函數中的語句之前分配它。所以,你的函數的實際執行去有點像這樣:

  1. 分配存儲量爲所有本地函數變量,
  2. 開始執行報表功能

這樣一來,當你調用另一個來自fucntion1的函數2時,函數1的局部變量不會受到函數2中局部變量的數據干擾。

因此,在您的情況下,本地數據變量所需的空間大於堆棧的可用空間,並且在功能代碼開始執行之前的某個時間點引發異常。