Home » Php » c – SEG Fault in PHP extension

c – SEG Fault in PHP extension

Posted by: admin July 12, 2020 Leave a comment

Questions:

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

How to&Answers:

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!

Answer:

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.