SEG Fault in PHP extension
Asked Answered
H

2

8

I wrote a PHP extension to access functions in a static lib, I built PHP as a CGI, and everything seemed to work (after days of working on it..)

Thrilled once everything worked, I re-compiled PHP without debugging messages I had in it. (php_printf("here111"); .... php_printf("sending arguments...");)

Then, it just stopped working. The function I'm calling in the static lib works, I've tested it by calling it directly from another executable.

I built PHP with debugging symbols (--enable-debug) and can debug it to a certain degree in gdb.

I'm still struggling to figure out what's wrong. It seems that the function in the lib (diffFst) cannot seem to read the input arguments.

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);

When I call this function, the php_printf() statement works and prints out the right values. When I let it call the difffst_ function however, I get a segfault when it tries to read the input variables.

The diffFst function is written in 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

Specifically, it fails at line 122 (according to the debugger) when it tries to read filA.

I have no idea why, I've tried:

  • Making the function a subroutine
  • Making the function a fortran function
  • Making the function a 'pure' function
  • Having return values (that's what is there now, the ier = ..)
  • Having return statements in the code, removing the return statements
  • Tried printing things out to stdout, and to log files

It just seems like the data isn't being passed properly. Even in the debugger, I can't read the arguments.

The frustrating thing is, at one point this just worked.. I've checked file permissions, checked paths, etc.. And I can run the function from a fortran wrapper executable just fine.

Is there a trick I'm missing?

Thanks

Hillman answered 2/1, 2013 at 15:36 Comment(5)
Why don't you revert the changes to the last working version? If you had multiple commits you can also try which of the commits did introduce the problem specifically.Inspissate
@Inspissate - Unfortunately I wasn't committing regularly. I'm new to git, and was having issue (specifically this one where I was getting a 403 on github because of my git version on my OSX box) So.. My first commit was well after I was getting this error. (Normally I commit every few minutes)Hillman
Oh doman, so the working code is lost? I'm not good with C, so you really can't ask me much here. Maybe some others from the PHP channel can you help you.Inspissate
@Inspissate - The frustrating thing is, I'm pretty sure the only change was commenting out line 280 in the C code.. But when I put it back in, it still didn't help. I'm worried it's something hidden, so I've make clean'ed, re-built.. etc.Hillman
I think the problem is the character (len=*), C is passing a pointer and fortran can't read it. Working on a solution, will post as soon as I can get it working.Hillman
H
2

Took a while, and needed additional help (issues like this)

Basically two things had to change:

  • Pass integers by reference
  • Accept strings properly

The first is easy, simply ier=func(..., &integer_var, ...)

The second involved passing the length of the string. There may have been an easier way to do this (sensing string length by looking for the \0) but they didn't work out. So, now I pass

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

Then in Fortran, I accept the string as

character(kind=c_char,len=strlen), intent(IN) :: str

The specific changes to the fortran code above are

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

When it was working, it must have been before I attempted to read in the strings as (len=*), and integers were being passed in as references, so they'd have had random values essentially.

Thanks for everyone's else!

Hillman answered 3/1, 2013 at 4:57 Comment(1)
You should mark your answer as accepted. You'll get 2 points for accepting an answer to your question, the question will no longer show up as unanswered, and your accept percentage will improve. Win-win-win.Satiety
B
1

Your program, seems, currupts the stack. Stack corruption usually comes with improper usage of pointers. Check carefully (investigate contents of variables using debugger or simple footprints) right before suspicious function calls.

Boehmenist answered 8/1, 2013 at 15:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.