簡體   English   中英

在混合的Fortran / C程序中出現奇怪的崩潰

[英]Getting weird crashes in mixed fortran/C program

我正在嘗試在一組fortran程序中替換一些圖形代碼(而不是我自己的代碼)。 我得到了一個更簡單的代碼('psvdraw')可以正常工作,用C調用開羅庫(graphic_output.c)替換了fortran后記生成代碼。 我已經能夠成功解決跨語言調用,而沒有太多麻煩。

但是,當試圖使第二個更大的程序(“ pssect”)運行,調用相同的C代碼時,出現分段錯誤,或者在某些情況下,程序流返回到fortran例程“錯誤”(我確實不要在我的C代碼中調用此代碼或任何fortran例程)。

在嘗試診斷此問題時,我將一堆來自pssect的fortran代碼鏈接到psvdraw('biglib.f')中,並得到了相同的錯誤。 請注意,實際上沒有調用此添加的代碼! 錯誤也發生在從fortan到c代碼的第一次調用中。 因此:鏈接有biglib.f的psvdraw失敗,但沒有它的psvdraw成功。

這是makefile的相關位:

生成文件

COMP77 = gfortran

FFLAGS = -C -v -pedantic -Wunused -fno-underscoring

CC = gcc-4
CFLAGS = -v -pedantic -Wunused
CAIRO_INCLUDE = /sw/include/cairo
CAIRO_LIB = /sw/lib

# PSVDRAW Make setup that works:
psvdraw: psvdraw.o graphic_output.o tlib.o pscom.o
    $(COMP77) $(FFLAGS) $@.o graphic_output.o tlib.o pscom.o -L$(CAIRO_LIB) -lcairo -o $@

# PSVDRAW Make setup with errors:
#psvdraw: psvdraw.o graphic_output.o tlib.o pscom.o biglib.o
#   $(COMP77) $(FFLAGS) $@.o graphic_output.o  pscom.o tlib.o biglib.o -L$(CAIRO_LIB) -lcairo -o $@

pssect: pssect.o graphic_output.o pscom.o tlib.o biglib.o 
    $(COMP77) $(FFLAGS) $@.o graphic_output.o pscom.o tlib.o biglib.o -L$(CAIRO_LIB) -lcairo -o $@

pssect.o: pssect.f
    $(COMP77) $(FFLAGS) -c pssect.f
psvdraw.o: psvdraw.f
    $(COMP77) $(FFLAGS) -c psvdraw.f
pscom.o: pscom.f
    $(COMP77) $(FFLAGS) -c pscom.f
tlib.o: tlib.f
    $(COMP77) $(FFLAGS) -c tlib.f
biglib.o: biglib.f
    $(COMP77) $(FFLAGS) -c biglib.f

graphic_output.o: graphic_output.c
    $(CC) $(CFLAGS) $(INCL) -c -I$(CAIRO_INCLUDE) graphic_output.c

.c.o:
    $(CC) $(CFLAGS) $(INCL) -c $<

.f.o:
    $(FC) $(FFLAGS) $(INCL) -c $<

以下是令人討厭的fortran代碼:請注意,該問題就在程序開始時發生:

pssect.f的開頭:

PROGRAM PSSECT

implicit none

include 'perplex_parameters.h'

integer jop0, ier99

logical vertex, output, first

character*100 fname, yes*1

integer  iop0 
logical  debug
common / basic /iop0, debug

integer isec,icopt,ifull,imsg,io3p
common/ cst103 /isec,icopt,ifull,imsg,io3p
c----------------------------------------------------------------------
c   Look for the "debug_yes" file to turn on debugging messages
PRINT *,'Pre-PSOPEN1'
call psopen ('plot2')    
PRINT *,'Post-PSOPEN1'

這是被調用並產生錯誤的C代碼的一部分:

graphic_output.c的一部分:

char dmh_debug = 0;

#define DEBUGPRINT(x) if (dmh_debug) {printf x;};

void psopen(char *fname, int fnamelen) {

    printf("Debug opened\n");

    char *outFileName;
    char outputType[255];
    char pageWidthString[255];
    char pageHeightString[255];

    /* Set debug status based upon presence of file named 'debug_yes' in directory */
    FILE *debugFile = fopen("debug_yes", "r");
    if (debugFile == NULL) {
        dmh_debug = 0;
    } else {
        dmh_debug = 1;
    }
    fclose(debugFile);

    dmh_debug = 1;
    DEBUGPRINT(("Debug closed\n"));

    fname[fnamelen]='\0';
    fname = trim(fname);
    outFileName = malloc((strlen(fname) + 50) * sizeof(char));
    strcpy(outFileName, fname);
    DEBUGPRINT(("Found file name:%s of length: %lu\n", fname, strlen(fname)));
[...]

運行程序的結果

pnr-rethington:source dave$ ./pssect
 Pre-PSOPEN1
Debug opened
Segmentation fault

如果鏈接未使用的代碼觸發了問題,則可能表明在某個地方(在Fortran代碼或C代碼中)您正在覆蓋不應該覆蓋的內存。 嘗試在Valgrind下運行已編譯的程序-它應有助於查明發生這種情況的位置。

我仍然懷疑您在Fortran和C之間的某些調用有問題,從而導致不一致。 你怎么打電話? 我認為最可靠的方法是使用ISO C綁定向Fortran指定應如何調用C例程。

或者,您可以考慮具有Fortran界面或綁定的圖形包。 然后,您將不必在接口上工作,因為Fortran調用或Fortran接口已經存在。 我一直在使用DISLIN。 另一種可能是PLplot。

使用當前方法,我建議檢查C例程入口處的參數,以確保它們正確。

您正在使用單個參數從Fortran調用psopen,並且C例程需要兩個參數。 也許您的Fortran編譯器在每個字符串之后添加字符串的長度作為尾隨參數。 或者,也許您很幸運,但是第一次嘗試時,它恰好以C例程在堆棧中找到的“隨機”值工作。 在第二種情況下,在另一種情況下,可能會發生特殊的崩潰。 充其量,這是連接Fortran和C的一種不可移植的方法。您可以嘗試在Fortran調用中添加整數長度,然后看看會發生什么。 或打印或使用調試器在C例程的入口處查看第二個參數的值。

ISO C綁定效果更好。 許多編譯器(例如gfortran> = 4.3,ifort)都支持它,並且提供了一種定義的和可移植的連接Fortran和C的方式。您可以在Fortran代碼中指定一個“接口”,以便Fortran編譯器可以為Fortran生成正確的指令。打電話。

不過,使用已經提供了Fortran接口的繪圖程序包可能會更容易。

我從您的make文件中注意到您正在使用gfortran。 gfortran(> = 4.3)和gcc的組合支持ISO C綁定。 (Fortran 2003的一部分。)如果包括接口示例並使用兩個參數調用psopen,則它應該可以工作。 該接口進入Fortran程序的聲明,並且是C例程psopen的Fortran描述。 不能保證,因為我尚未測試過……字符串是一種特殊情況-您將Fortran程序中的縮放器字符串與接口中的字符串數組進行匹配,因為C參數是一個字符數組或一個指向字符

interface To_psopen

   subroutine psopen ( fname, fnamelen ) bind (C, name="psopen")

      use iso_c_binding

      implicit none

      character (kind=c_char, len=1), dimension (100), intent (inout) :: fname
      integer (c_int), value, intent (in) :: fnamelen

   end subroutine psopen

end interface To_psopen

在調試器( gdb )下運行應該告訴您segfault發生在哪里。 -O0 -g編譯所有代碼以獲取准確的信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM