Overflown on Solaris #122

Closed
craigmohrman opened this Issue Aug 9, 2013 · 14 comments

Comments

Projects
None yet
3 participants
I'm getting:
End:      Overflown (magic=0x00000000 instead of 0x4839762B)
even with the most trivial of code followed by a seg fault.
If I turn off opcache everything is fine.

I'm using php 5.3.27 compiled with the Solaris Studio compiler.
I've worked my way through these trivial problems:
https://bugs.php.net/bug.php?id=65207
As you can see I'm still 32-bit with most extensions turned off.
Any hints would be greatly appreciated.
Thanks much.

An update:  If I compile with gcc I can get somethings working.
Wordpress installs and seems to work but Joomla is giving
me mysql connect issues.
Using gcc to deliver php is not my first choice.  Sorry.

Update2: I've successfully compiled opcache with Solaris
Studio on SPARC and it works just fine.  Both Wordpress and Joomla
load and seem to work.
So Solaris Studio on Solaris SPARC works.
Solaris Studio on Solaris x86 fails as below.
gcc on Solaris x86 works.
Very bizzare.
I've noted the differences and tried applying those
to my failing Studio x86 but nothing helps.

$ cat simple.php
<?php

      function m_x_plus_b($m, $x, $b) {

            return $m*$x+$b;

      }

      $slope=1.5;

      $x=2;

      $b=3;

      echo "y = ".m_x_plus_b($slope,$x,$b)."\n<br>";
?>
cmohrman@msulliva-us2:~/Public/PHP$ 
cmohrman@msulliva-us2:~/Public/PHP$ php -f simple.php
File /home/cmohrman/Public/PHP/simple.php func m_x_plus_b
Block: 0-5 (6) unused
Block: 6-6 (1)
T0: 0
T1: 0
Opt Block: 0-5 (6)
T0: 0
T1: 0
Opt Block: 0-5 (6)
T0: 0
T1: 0
Opt Block: 0-5 (6)
T0: 0
T1: 0
Out Block: 0-5 (6)
File /home/cmohrman/Public/PHP/simple.php func main
Block: 0-11 (12) unused
T0: 0
T1: 0
T2: 0
T3: 0
T4: 0
T5: 0
[Fri Aug  9 11:10:45 2013]  Script:  '/home/cmohrman/Public/PHP/simple.php'
---------------------------------------
./Optimizer/block_pass.c(2053) : Block 0x0935e970 status:
Beginning:      OK (allocated on ./Optimizer/block_pass.c:1911, 6 bytes)
    Start:      OK
      End:      Overflown (magic=0x00000000 instead of 0x530646BC)
                1 byte(s) overflown
---------------------------------------
Opt Block: 0-11 (12)
[Fri Aug  9 11:10:45 2013]  Script:  '/home/cmohrman/Public/PHP/simple.php'
---------------------------------------
./Optimizer/block_pass.c(1220) : Block 0x0935fa70 status:
Beginning:      OK (allocated on ./Optimizer/block_pass.c:631, 24 bytes)
    Start:      OK
      End:      Overflown (magic=0xFFFFFFB4 instead of 0x530646BC)
                At least 4 bytes overflown
---------------------------------------
T0: 0
T1: 0
T2: 0
T3: 0
T4: 0
T5: 0
[Fri Aug  9 11:10:45 2013]  Script:  '/home/cmohrman/Public/PHP/simple.php'
---------------------------------------
./Optimizer/block_pass.c(2053) : Block 0x0935e9a8 status:
Beginning:      OK (allocated on ./Optimizer/block_pass.c:1911, 6 bytes)
    Start:      OK
      End:      Overflown (magic=0x00000000 instead of 0x530646BC)
                1 byte(s) overflown
---------------------------------------
Opt Block: 1-11 (11)
[Fri Aug  9 11:10:45 2013]  Script:  '/home/cmohrman/Public/PHP/simple.php'
---------------------------------------
./Optimizer/block_pass.c(1220) : Block 0x0935fc80 status:
Beginning:      OK (allocated on ./Optimizer/block_pass.c:631, 24 bytes)
    Start:      OK
      End:      Overflown (magic=0xFFFFFFB4 instead of 0x530646BC)
                At least 4 bytes overflown
---------------------------------------
T0: 0
T1: 0
T2: 0
T3: 0
T4: 0
T5: 0
[Fri Aug  9 11:10:45 2013]  Script:  '/home/cmohrman/Public/PHP/simple.php'
---------------------------------------
./Optimizer/block_pass.c(2053) : Block 0x0935e9e0 status:
Beginning:      OK (allocated on ./Optimizer/block_pass.c:1911, 6 bytes)
    Start:      OK
      End:      Overflown (magic=0x00000000 instead of 0x530646BC)
                1 byte(s) overflown
---------------------------------------
Opt Block: 1-11 (11)
[Fri Aug  9 11:10:45 2013]  Script:  '/home/cmohrman/Public/PHP/simple.php'
---------------------------------------
./Optimizer/block_pass.c(1220) : Block 0x0935ea50 status:
Beginning:      OK (allocated on ./Optimizer/block_pass.c:631, 24 bytes)
    Start:      OK
      End:      Overflown (magic=0xFFFFFFB4 instead of 0x530646BC)
                At least 4 bytes overflown
---------------------------------------
T0: 0
T1: 0
T2: 0
T3: 0
T4: 0
T5: 0
[Fri Aug  9 11:10:45 2013]  Script:  '/home/cmohrman/Public/PHP/simple.php'
---------------------------------------
./Optimizer/block_pass.c(2053) : Block 0x0935ea18 status:
Beginning:      OK (allocated on ./Optimizer/block_pass.c:1911, 6 bytes)
    Start:      OK
      End:      Overflown (magic=0x00000000 instead of 0x530646BC)
                1 byte(s) overflown
---------------------------------------
Out Block: 0-10 (11)
Segmentation Fault (core dumped)
cmohrman@msulliva-us2:~/Public/PHP$ 
cmohrman@msulliva-us2:~/Public/PHP$ 
cmohrman@msulliva-us2:~/Public/PHP$ mdb core
Loading modules: [ libc.so.1 libuutil.so.1 libnvpair.so.1 ld.so.1 ]
> ::stack
opcache.so`optimize_temporary_variables+0x504(935cdf0, 0)
opcache.so`zend_optimizer+0x2c3d(935cdf0, 0)
opcache.so`accel_op_array_handler+0x80(935cdf0, 0, 4c, 8af6905)
php`zend_extension_op_array_handler+0x1b(93fc4e0, 935cdf0, fea392d8, 8af3d21)
php`zend_llist_apply_with_argument+0x31(91e7b60, 8af6a8c, 935cdf0, 8af6ac5)
php`pass_two+0xac(935cdf0, 0, fea39448, 8aa0e38)
php`compile_file+0x5d9(fea3a400, 8, fea39620, 86a67dc)
php`phar_compile_file+0x370(fea3a400, 8)
opcache.so`compile_and_cache_file+0x424(fea3a400, 8, f8764444, 26, fea39950, 
fea39954)
opcache.so`persistent_compile_file+0x750(fea3a400, 8, 8058b50, 8b16131)
php`zend_execute_scripts+0x2da(8, 0, 3, 0, fea3a400, 0)
php`php_execute_script+0x3a8(fea3a400, 918f000, fea3a8c8, 8c94507)
php`main+0x15d6(3, fea3a8fc, fea3a90c, f8aa9940)
_start+0x7d(3, fea3a9fc, fea3aa00, fea3aa03, 0, fea3aa0e)
> 

TerryE commented Aug 21, 2013

@craigmohrman Craig, could you do me a favour and edit your post to use MD syntax around your text insert (that's ``` before and after the insert so it's readable). Thanks.

I don't have a Solaris environment now, so I can't explore this further, but looking at your traceback, it is occurring in the Optimizer which is hooked in via the Zend extension op_array hander. Try opcache.optimization_level=0 to see if this is stable and if so opcache.optimization_level=0x2ff which turns off temporary variable optimization.

I've found this sort of crash is typically a double free somewhere, so even though the crash is occurring in the optimizer, there's no guarantee that the allocator corruption occured here.

Thanks Terry.

I formatted my message.

The fix we found for the Solaris Studio compiler on x86 was modifying:

#define ZEND_MM_ALIGNMENT 8
#define ZEND_MM_ALIGNMENT_LOG2 3

to

#define ZEND_MM_ALIGNMENT 4
#define ZEND_MM_ALIGNMENT_LOG2 2

over in Zend/Zend.m4 in php. Didn't touch opcache.
Actually I patched:

LIBZEND_MM_ALIGN=4
LIBZEND_MM_ALIGN_LOG2=2

I got those values from using gcc 4.5.2 on Solaris x86.

And everything works great. Joomla and Wordpress
install and are working.

Now oddly on sparc BOTH compilers come up with 8, 3
but sparc works fine out of the box. No modifications.

Go figure.

TerryE commented Aug 21, 2013

Craig, IMO (i) this is nothing to do with opcache, so this issue need closing, but (ii) it is a valid Zend configuration issue, so we need to work out how to fix this properly -- i.e. not a patch which gets it working as a one-off for Solaris Studio C 32-bit x86 but breaks everything else -- and post a fix as a PHP bug report for Zend.

I am still a little confused here as

  • __alignof__ (mm_align_test) == __alignof__ (double) == 4 on 32bit x86 (== sizeof(void *)), but
  • sizeof((mm_align_test) == sizeof(double) == 8 (> sizeof(void *))

hence the 4, 2 vs. 8, 3. However, using 8 byte alignment on 32 bit systems might waste the odd word of memory, but shouldn't cause the memory overruns that you are seeing unless there is some other define defaulting to 4 and we've got a mismatch or equivalent. For example, zend_vm_stack_alloc() in zend_execute.h contains a test ZEND_MM_ALIGNMENT > sizeof(void*) and this is probably the only instance where this case evaluates to TRUE exposing this execution path and ditto zend_vm_stack_free().

I suspect that your patch is masking the error again, but let's discuss on the bugrep.

On 8/21/13 4:19 PM, Terry Ellison wrote:

Craig, IMO (i) this is nothing to do with opcache, so this issue need
closing, but(ii) it is a valid Zend configuration issue, so we need
to work out how to fix this properly -- i.e. not a patch which gets it
working as a one-off for Solaris Studio C 32-bit x86 but breaks
everything else -- and post a fix as a PHP bug report for Zend.

I am still a little confused here as

|__alignof__ (mm_align_test)|== |__alignof__ (double)|== 4 on
32bit x86 (== |sizeof(void *)|), but
|sizeof((mm_align_test)|== |sizeof(double)|== 8 (> |sizeof(void *)|

hence the 4, 2 vs. 8, 3. /However/, using 8 byte alignment on 32 bit
systems might waste the odd word of memory, but shouldn't cause the
memory overruns that you are seeing /unless/there is some other define
defaulting to 4 and we've got a mismatch or equivalent. For example,
|zend_vm_stack_alloc()|in |zend_execute.h|contains a test
|ZEND_MM_ALIGNMENT > sizeof(void_)|and this is probably the only
instance where this case evaluates to *TRUE_exposing this execution
path and ditto.

I suspect that your patch is masking the error again, but let's
discuss on the bugrep.


Reply to this email directly or view it on GitHub
#122 (comment).

Agree.
I'll file a bug against php and we'll talk there.

Thanks Terry.
craig

Owner

dstogov commented Aug 26, 2013

Thanks for report. Terry is absolutely right. The bigger value of ZEND_MM_ALIGNMENT must not make any harm except of memory waste. I tried to recompile PHP-5.5 and OPcache with ZEND_MM_ALIGNMENT=8 on x86 Linux and it works fine.

May be you compiled PHP and OPCache with different ZEND_MM_ALIGNMENT settings?

Thanks for responding Dmitry.

Sorry but no. I rechecked my build carefully and I am not changing the value of ZEND_MM_ALIGNMENT in the opcache build.

I just filed over on php.net:
Bug #65561 Zend Opcache on Solaris 11 x86 needs ZEND_MM_ALIGNMENT=4
as a place holder until I try out a newer version of php.

TerryE commented Aug 27, 2013

Like you Dmitry I tried this with a std PHP5.5 Linux/GCC on an i386 VM but patching the config to force the ZEND_MM_ALIGNMENT to 8, and this worked fine. I am going to try the same with 5.3.27. I'll feed back any comments to the report that Craig has raised, but can I suggest that we leave this issue open for a few days until I hunt down the bug?

Owner

dstogov commented Aug 27, 2013

No problem. I'll keep it open for a while. Thank you Terry for looking into it.

TerryE commented Aug 28, 2013

Unfortunately, this is definitely a bug in the OPcache optimizer. block_pass.c:585 allocates a dynamic vector of op_array->T pointers (zend_op *). This is subsequently updated by the SET_VAR_SOURCE() macro at line 1164. However the computed index, VAR_NUM(ZEND_RESULT(opline).var)), can fall outside the range 0..(op_array->T-1) with the PHP 5.3 variant macros. I've traced this though to confirm this.

The block _pass.c macros (5.3 variant) assume that the temp variables are consecutively stored in sizeof(temp_variable) fields whereas Zend uses ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)), that is 20 bytes vs 24 bytes for the Solaris compiled code. I'll work through the code to work out the macro fixes, test, verify, then report back with a fix patch.

TerryE commented Aug 28, 2013

--- a/ext/opcache/Optimizer/zend_optimizer_internal.h   2013-08-15 12:24:55.809204678 +0100
+++ b/ext/opcache/Optimizer/zend_optimizer_internal.h   2013-08-28 21:42:04.000000000 +0100
@@ -28,8 +28,8 @@
 # define VAR_NUM(v) ((zend_uint)(EX_TMP_VAR_NUM(0, 0) - EX_TMP_VAR(0, v)))
 # define NUM_VAR(v) ((zend_uint)(zend_uintptr_t)EX_TMP_VAR_NUM(0, v))
 #else
-# define VAR_NUM(v) ((v)/(sizeof(temp_variable)))
-# define NUM_VAR(v) ((v)*(sizeof(temp_variable)))
+# define VAR_NUM(v) ((v)/ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)))
+# define NUM_VAR(v) ((v)*ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)))
 #endif

 #define INV_COND(op)       ((op) == ZEND_JMPZ    ? ZEND_JMPNZ    : ZEND_JMPZ)
Owner

dstogov commented Aug 29, 2013

Thank you Terry. It's much better that it's just a bug in OPCache,
especially when it's found and fixed :)
I'll commit it today.

On Wed, Aug 28, 2013 at 10:48 PM, Terry Ellison notifications@github.comwrote:

--- a/ext/opcache/Optimizer/zend_optimizer_internal.h 2013-08-28 12:24:55.809204678 +0100+++ b/ext/opcache/Optimizer/zend_optimizer_internal.h 2013-08-15 21:42:04.000000000 +0100@@ -28,8 +28,8 @@

define VAR_NUM(v) ((zend_uint)(EX_TMP_VAR_NUM(0, 0) - EX_TMP_VAR(0, v)))

define NUM_VAR(v) ((zend_uint)(zend_uintptr_t)EX_TMP_VAR_NUM(0, v))

#else-# define VAR_NUM(v) ((v)/(sizeof(temp_variable)))-# define NUM_VAR(v) ((v)_(sizeof(temp_variable)))+# define VAR_NUM(v) ((v)/ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)))+# define NUM_VAR(v) ((v)_ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable)))
#endif

#define INV_COND(op) ((op) == ZEND_JMPZ ? ZEND_JMPNZ : ZEND_JMPZ)


Reply to this email directly or view it on GitHubhttps://github.com/zendtech/ZendOptimizerPlus/issues/122#issuecomment-23438068
.

Owner

dstogov commented Aug 29, 2013

I've committed the fix.

dstogov closed this Aug 29, 2013

I have verified Terry's patch above.
Zend Opcache is now working just fine without my Zend/Zend.m4 hack.
So Zend Opcache is working just fine on Solaris 11 compiled with Solaris Studio 12.1 32-bit on both
sparc and x86.
The built in tests all pass.
Joomla and Wordpress install and work fine.
Thank you Terry!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment