Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SEG Fault in PHP extension

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

like image 201
Matt Avatar asked Jan 02 '13 15:01

Matt


People also ask

What causes PHP segmentation fault?

A segmentation fault occurs because of the Memory Access Violation. Means, the error occurs when a program tries to access a block of memory which you are not allowed to access. Or to make it concise, you are approaching memory location which doesn't belong to you. In short, it is also known as a segfault.

What is a seg fault error?

A segmentation fault (aka segfault) is a common condition that causes programs to crash; they are often associated with a file named core . Segfaults are caused by a program trying to read or write an illegal memory location.

Can free () cause seg fault?

Writing to freed (or out-of-scope) memory might cause a segmentation fault or corrupt data if the memory is recycled and reused. In certain cases, writing malicious data to freed memory can result in arbitrary code execution.

Why does seg fault happen?

A segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (for example, attempting to write to a read-only location, or to overwrite part of the operating system).


1 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!

like image 194
Matt Avatar answered Nov 14 '22 22:11

Matt