PHP扩展中的SEG错误

8
我写了一个PHP扩展来访问静态库中的函数,我将PHP构建为CGI,一切似乎都正常工作了(经过几天的努力..)。
当所有东西都能够工作时,我非常兴奋,于是重新编译了没有调试信息的PHP。(php_printf("here111"); .... php_printf("sending arguments...");
然后,它就停止工作了。我正在调用静态库中的函数,通过从另一个可执行文件中直接调用进行了测试。
我使用了调试符号(--enable-debug)构建了PHP,并且可以在gdb中进行某种程度的调试。
我仍在努力找出问题所在。似乎库中的函数(diffFst)无法读取输入参数。
268     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssssssd",
269        &filA, &filA_len,
270        &nomvarA, &nomvarA_len,
271        &filB, &filB_len,
272        &nomvarB, &nomvarB_len,
273        &filO, &filO_len,
274        &newnomvar, &newnomvar_len,
275        &mult
276        ) == FAILURE) {
277         RETURN_LONG(-100);
278     }
279 
280     php_printf("Read arguments:\nfilA: %s, nomvara: %s\nfilB: %s, nomvarB: %s\nfilO: %s, nomvarO: %s\nMult: %0.3f\n",
281        filA,nomvarA, filB,nomvarB, filO,newnomvar, mult);
282 
285     ier = difffst_(filA,nomvarA, filB,nomvarB, filO,newnomvar, mult);

当我调用这个函数时,php_printf()语句可以输出正确的值。然而当我让它调用difffst_函数时,在试图读取输入变量时会出现段错误。
diffFst函数是用Fortran编写的:
  5 function diffFst(filA, nomvara, filB, nomvarb, filO, newnomvar, change, write_tictac, in_verbose) result(ier)
 10     implicit none
 11 

 12     character (len=*), intent(IN) :: filA, filB, filO
 13     character (len=*), intent(IN) :: nomvara, nomvarb, newnomvar
 14 
 16     real, intent(IN) :: change
 17     logical, intent(IN) :: write_tictac
 18 
 19     logical, intent(IN), optional :: in_verbose
 21     logical :: verbose = .false.
 27     integer :: ier
...
117     ier = fstouv(iuna, 'RND')
118     IF (ier < 0) THEN
119         if (verbose) write(stderr,'(2A)') "Could not fstouv FST file ", trim(filA)
120     ELSE
121         nmax = fstnbr(iuna);
122         if (verbose) write(stdout,'(3A,I6,A)') "Succesfully opened ", trim(filA), ' with ', nmax, ' records'
123         allocate(liste(nmax))
124     END IF

具体来说,当它尝试读取filA时(根据调试器),它在第122行失败了。
我不知道为什么,我已经尝试过:
- 将函数作为子例程 - 将函数作为Fortran函数 - 使函数成为“纯”函数 - 有返回值(现在就是这样,即ier =..) - 在代码中使用return语句,删除return语句 - 尝试将输出打印到stdout和日志文件中
似乎数据没有被正确传递。即使在调试器中,我也无法读取参数。
令人沮丧的是,这个问题曾经可以解决。我已经检查了文件权限、检查了路径等等。我可以从Fortran包装器可执行文件中成功运行该函数。
我是否漏掉了什么技巧?
谢谢。

为什么不将更改还原到上一个工作版本呢?如果您有多个提交,还可以尝试确定哪个提交特别引入了问题。 - hakre
@hakre - 很不幸,我没有经常提交。我是git的新手,并且遇到了问题(具体来说,这个问题是因为我的OSX框上的git版本而在github上得到403)。所以...我的第一个提交是在我遇到这个错误之后很久才进行的。(通常我每隔几分钟就提交一次) - Matt
哦,代码丢失了吗?我不擅长C语言,所以在这方面你真的不能问我太多。也许PHP频道的其他人可以帮助你。 - hakre
@hakre - 令人沮丧的是,我相当确定唯一的更改是注释掉C代码中的第280行。但是当我把它放回去时,它仍然没有帮助。我担心这是隐藏的问题,所以我已经执行了make clean,重新构建等操作。 - Matt
我认为问题出在character(len=*)上,C语言传递了一个指针,而Fortran无法读取它。正在努力解决中,一旦解决将会立即发布。 - Matt
2个回答

2

花了一些时间,还需要额外的帮助(像这样的问题

基本上有两件事情需要改变:

  • 通过引用传递整数
  • 正确接受字符串

第一个很容易,只需使用ier=func(..., &integer_var, ...)

第二个涉及传递字符串的长度。可能有更简单的方法来做到这一点(通过查找\0来感知字符串长度),但它们没有成功。所以现在我传递

ier = func(str,strlen,...)

然后在Fortran中,我将字符串接受为
character(kind=c_char,len=strlen), intent(IN) :: str

上述Fortran代码的具体更改如下:
11     use, intrinsic :: iso_c_binding
12     use interfaces_rmnutils
13     implicit none
16     integer(kind=c_int), intent(IN) :: len_filA, len_filB, len_filO
17     character (kind=c_char,len=len_filA), intent(IN) :: filA
18     character (kind=c_char,len=len_filB), intent(IN) :: filB
19     character (kind=c_char,len=len_filO), intent(IN) :: filO

当它工作时,一定是在我尝试将字符串读入为(len=*)之前,并且整数被传递为引用,因此它们基本上具有随机值。
感谢其他所有人!

你应该将你的答案标记为已接受。接受一个问题的答案可以获得2个积分,问题将不再显示为未回答,并且你的接受率会提高。三赢。 - Beska

1
你的程序似乎破坏了堆栈。堆栈破坏通常是由于指针的不当使用而引起的。在可疑的函数调用之前仔细检查(使用调试器或简单的足迹调查变量内容)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接