Edit report at https://bugs.php.net/bug.php?id=64233&edit=1

 ID:                 64233
 User updated by:    andreas dot lindemann at de dot bp dot com
 Reported by:        andreas dot lindemann at de dot bp dot com
 Summary:            Soapserver::fault bus error on Solaris CLI/CGI/FPM
-Status:             Open
+Status:             Closed
 Type:               Bug
 Package:            SOAP related
 Operating System:   Solaris 10
 PHP Version:        5.4.11
 Block user comment: N
 Private report:     N

 New Comment:

Fixed in versions 5.3.26 & 5.4.16 although not listed in Changelog.


Previous Comments:
------------------------------------------------------------------------
[2013-06-11 09:41:25] andreas dot lindemann at de dot bp dot com

This seems to have been fixed in a commit on git for PHP 5.3:
https://github.com/php/php-src/commit/fe21accfb4913bf309f26894ae27e9ad34fb5260

>From there it has been ported to PHP 5.4.

Why isn't this listed in the official Changelog for 5.3.26 and 5.4.16?

------------------------------------------------------------------------
[2013-05-27 10:12:20] andreas dot lindemann at de dot bp dot com

Seem to have found the main issue.

"new_len" is defined int in ext/soap/soap.c in function serialize_response_call:

int new_len;
xmlNodePtr node = xmlNewNode(NULL, BAD_CAST("faultcode"));
char *str = php_escape_html_entities((unsigned char*)Z_STRVAL_PP(tmp), 
Z_STRLEN_PP(tmp), &new_len, 0, 0, NULL TSRMLS_CC);

However, php_escape_html_entities() handles new_len as size_t.

PHPAPI char *php_escape_html_entities(unsigned char *old, size_t oldlen, size_t 
*newlen, int all, int flags, char *hint_charset TSRMLS_DC)

php_escape_html_entities_ex() tracks the string length in a 

size_t len

When assigning the size_t value to the int pointer, PHP crashes.
This can be reproduced by a very simple C program on Solaris 64 bit which just 
replicates this process:

----------------------
#include <stdio.h>

int testfunc(size_t *dummy)
{
  size_t len;
  len = 5;

  *dummy = len;
}

int main()
{
  int test;

  testfunc(&test);

  return 0;
}
----------------------

$ gcc -m64 test.c
test.c: In function 'main':
test.c:15:3: warning: passing argument 1 of 'testfunc' from incompatible 
pointer type [enabled by default]
test.c:3:5: note: expected 'size_t *' but argument is of type 'int *'

$ ./a.out
Bus Error (core dumped)

Note: On 64-bit Linux, this program runs without errors! So you cannot 
reproduce this issue on Linux!

There seem to be 2 ways to fix this:
1) Change new_len declaration to size_t in ext/soap/soap.c -> works fine, BUT 
new_len is also passed to xmlNodeSetContentLen, which expects this parameter to 
be int. Can use a cast to convert the size_t to int though, shouldn't matter 
unless your string exceeds MAX_INT?

2) Change php_escape_html_entities and php_escape_html_entities_ex in 
ext/standard/html.c to expect newlen as int and declare "len" as int as well.

To me, 1) sounds to be the easier solution which only impacts soap.c really, 
leaving other places where php_escape_html_entities is used untouched.

Sounds reasonable?

------------------------------------------------------------------------
[2013-05-27 06:49:23] andreas dot lindemann at de dot bp dot com

Now with php 5.4.14 and still trying to narrow this down.
So far, I've narrowed it down to a single line of code.
The issue seems to be caused in ext/standard/html.c at the very end of 
php_escape_html_entities_ex():

    replaced[len] = '\0';   // This seems to be fine
    *newlen = len;          // <-- This line crashes PHP

    return replaced;
}

It seems the issue occurs when accessing the "len" variable. If I add another 
line just before the *newlen = len; line, i.e. for getting the value of "len" 
out to the php logfile, PHP crashes on that new line as well:

Example (not a nice one):

            php_error_docref0(NULL TSRMLS_CC, E_STRICT, "debug 1");
    replaced[len] = '\0';
// Next line still goes to the log
            php_error_docref0(NULL TSRMLS_CC, E_STRICT, "debug 2");
// Next line crashes PHP
            php_error_docref0(NULL TSRMLS_CC, E_STRICT, (char*)len);
// This won't be executed:
    *newlen = len;
// And we'll never see this:
            php_error_docref0(NULL TSRMLS_CC, E_STRICT, "debug 3");

    return replaced;
}

Any ideas?

------------------------------------------------------------------------
[2013-03-19 09:29:57] andreas dot lindemann at de dot bp dot com

Any chance of fixing or reproducing this?
If I can be of assistance, i.e. running some debug build to give more insight 
into the issue or so, please let me know.

For now I've made a change to the soap extension to not run through the 
php_escape_html_entities_ex function. This is probably neither a good idea nor 
anywhere near a proper fix, considering that I've only got a very basic idea of 
C, but at least it throws the SoapFaults correctly to the client and doesn't 
crash the PHP process.

--- ext/soap/soap.c.orig        2013-01-16 08:10:30.000000000 +0100
+++ ext/soap/soap.c     2013-03-11 12:30:34.497971000 +0100
@@ -3881,7 +3881,8 @@
                        if (zend_hash_find(prop, "faultcode", 
sizeof("faultcode"), (void**)&tmp) == SUCCESS) {
                                int new_len;
                                xmlNodePtr node = xmlNewNode(NULL, 
BAD_CAST("faultcode"));
-                               char *str = php_escape_html_entities((unsigned 
char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), &new_len, 0, 0, NULL TSRMLS_CC);
+                               char *str = (unsigned char*)Z_STRVAL_PP(tmp);
                                xmlAddChild(param, node);
                                if (fault_ns) {
                                        xmlNsPtr nsptr = encode_add_ns(node, 
fault_ns);
@@ -3906,7 +3907,8 @@
                        if (zend_hash_find(prop, "faultcode", 
sizeof("faultcode"), (void**)&tmp) == SUCCESS) {
                                int new_len;
                                xmlNodePtr node = xmlNewChild(param, ns, 
BAD_CAST("Code"), NULL);
-                               char *str = php_escape_html_entities((unsigned 
char*)Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp), &new_len, 0, 0, NULL TSRMLS_CC);
+                               char *str = (unsigned char*)Z_STRVAL_PP(tmp);
                                node = xmlNewChild(node, ns, BAD_CAST("Value"), 
NULL);
                                if (fault_ns) {
                                        xmlNsPtr nsptr = encode_add_ns(node, 
fault_ns);

------------------------------------------------------------------------
[2013-02-21 06:09:23] andreas dot lindemann at de dot bp dot com

This may be specific to Solaris 64bit. 
I tried to reproduce on Linux 64bit (SuSE Linux Enterprise), but no issue there 
as well. 
However no problem to reproduce this on 5 of our Solaris Sparc servers, all are 
showing the same bus error and backtrace.

------------------------------------------------------------------------


The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at

    https://bugs.php.net/bug.php?id=64233


-- 
Edit this bug report at https://bugs.php.net/bug.php?id=64233&edit=1

Reply via email to