diff --git a/lib/Decompiler.class.php b/lib/Decompiler.class.php index 82f24c8..59c8a23 100644 --- a/lib/Decompiler.class.php +++ b/lib/Decompiler.class.php @@ -566,6 +566,7 @@ class Decompiler XC_ASSIGN => "=", XC_ASSIGN_REF => "= &", XC_JMP_SET => "?:", + XC_JMP_SET_VAR => "?:", XC_JMPZ_EX => "&&", XC_JMPNZ_EX => "||", ); @@ -595,6 +596,7 @@ class Decompiler // }}} function stripNamespace($name) // {{{ { + $name = str($name); $len = strlen($this->namespace) + 1; if (substr($name, 0, $len) == $this->namespace . '\\') { return substr($name, $len); @@ -663,6 +665,9 @@ class Decompiler case XC_IS_VAR: case XC_IS_TMP_VAR: $T = &$EX['Ts']; + if (!isset($T[$op['var']])) { + printBacktrace(); + } $ret = $T[$op['var']]; if ($free && empty($this->keepTs)) { unset($T[$op['var']]); @@ -833,12 +838,12 @@ class Decompiler return false; } // }}} - // {{{ ?: excluding JMP_SET + // {{{ ?: excluding JMP_SET/JMP_SET_VAR if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts']) && $range[1] >= $range[0] + 3 - && $opcodes[$firstOp['jmpouts'][0] - 2]['opcode'] == XC_QM_ASSIGN + && ($opcodes[$firstOp['jmpouts'][0] - 2]['opcode'] == XC_QM_ASSIGN || $opcodes[$firstOp['jmpouts'][0] - 2]['opcode'] == XC_QM_ASSIGN_VAR) && $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_JMP && $opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'][0] == $range[1] + 1 - && $lastOp['opcode'] == XC_QM_ASSIGN + && ($lastOp['opcode'] == XC_QM_ASSIGN || $lastOp['opcode'] == XC_QM_ASSIGN_VAR) ) { $trueRange = array($range[0] + 1, $firstOp['jmpouts'][0] - 2); $falseRange = array($firstOp['jmpouts'][0], $range[1]); @@ -1013,9 +1018,9 @@ class Decompiler $this->dasmBasicBlock($EX, array($catchFirst, $catchOpLine)); $catchOp = &$opcodes[$catchOpLine]; echo $indent, 'catch (' - , isset($catchOp['op1']['constant']) ? $catchOp['op1']['constant'] : str($this->getOpVal($catchOp['op1'], $EX)) + , $this->stripNamespace(isset($catchOp['op1']['constant']) ? $catchOp['op1']['constant'] : str($this->getOpVal($catchOp['op1'], $EX))) , ' ' - , str($this->getOpVal($catchOp['op2'], $EX)) + , isset($catchOp['op2']['constant']) ? '$' . $catchOp['op2']['constant'] : str($this->getOpVal($catchOp['op2'], $EX)) , ") {", PHP_EOL; unset($catchOp); @@ -1314,6 +1319,7 @@ class Decompiler case XC_JMPZ_EX: case XC_JMPNZ_EX: // case XC_JMP_SET: + // case XC_JMP_SET_VAR: // case XC_FE_RESET: case XC_FE_FETCH: // case XC_JMP_NO_CTOR: @@ -1474,7 +1480,7 @@ class Decompiler array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope'])); $EX['object'] = (int) $res['var']; $EX['called_scope'] = null; - $EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX); + $EX['fbc'] = 'new ' . $this->stripNamespace($this->getOpVal($op1, $EX)); break; // }}} case XC_THROW: // {{{ @@ -1489,7 +1495,7 @@ class Decompiler break; // }}} case XC_INSTANCEOF: // {{{ - $resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . str($this->getOpVal($op2, $EX)); + $resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . $this->stripNamespace($this->getOpVal($op2, $EX)); break; // }}} case XC_FETCH_CLASS: // {{{ @@ -1536,27 +1542,37 @@ class Decompiler case XC_FETCH_FUNC_ARG: case XC_FETCH_UNSET: case XC_FETCH_IS: - case XC_UNSET_VAR: - $rvalue = $this->getOpVal($op1, $EX); - $fetchtype = defined('ZEND_FETCH_TYPE_MASK') ? ($ext & ZEND_FETCH_TYPE_MASK) : $op2['EA.type']; - if ($fetchtype == ZEND_FETCH_STATIC_MEMBER) { - $rvalue = $this->stripNamespace($op2['constant']) . '::$' . unquoteName($rvalue, $EX); + $fetchType = defined('ZEND_FETCH_TYPE_MASK') ? ($ext & ZEND_FETCH_TYPE_MASK) : $op2['EA.type']; + $name = isset($op1['constant']) ? $op1['constant'] : unquoteName($this->getOpVal($op1, $EX), $EX); + if ($fetchType == ZEND_FETCH_STATIC_MEMBER) { + $class = isset($op2['constant']) ? $op2['constant'] : $this->getOpVal($op2, $EX); + $rvalue = $this->stripNamespace($class) . '::$' . $name; } - else if ($opc != XC_UNSET_VAR) { - $name = unquoteName($rvalue, $EX); + else { + $rvalue = $this->getOpVal($op1, $EX); $globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]"; - $rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname); + $rvalue = new Decompiler_Fetch($rvalue, $fetchType, $globalname); } - if ($opc == XC_UNSET_VAR) { - $op['php'] = "unset(" . str($rvalue, $EX) . ")"; - $lastphpop = &$op; - } - else if ($res['op_type'] != XC_IS_UNUSED) { + if ($res['op_type'] != XC_IS_UNUSED) { $resvar = $rvalue; } break; // }}} + case XC_UNSET_VAR: // {{{ + $fetchType = defined('ZEND_FETCH_TYPE_MASK') ? ($ext & ZEND_FETCH_TYPE_MASK) : $op2['EA.type']; + if ($fetchType == ZEND_FETCH_STATIC_MEMBER) { + $class = isset($op2['constant']) ? $op2['constant'] /* PHP5.3- */ : $this->getOpVal($op2, $EX); + $rvalue = $this->stripNamespace($class) . '::$' . $op1['constant']; + } + else { + $rvalue = $this->getOpVal($op1, $EX); + } + + $op['php'] = "unset(" . str($rvalue, $EX) . ")"; + $lastphpop = &$op; + break; + // }}} // {{{ case FETCH_DIM_* case XC_FETCH_DIM_TMP_VAR: case XC_FETCH_DIM_R: @@ -1737,7 +1753,8 @@ class Decompiler } $fetchtype = defined('ZEND_FETCH_TYPE_MASK') ? ($ext & ZEND_FETCH_TYPE_MASK) : $op2['EA.type']; if ($fetchtype == ZEND_FETCH_STATIC_MEMBER) { - $rvalue = $this->stripNamespace($op2['constant']) . '::' . unquoteName($rvalue, $EX); + $class = isset($op2['constant']) ? $op2['constant'] : $this->getOpVal($op2, $EX); + $rvalue = $this->stripNamespace($class) . '::' . unquoteName($rvalue, $EX); } } else if ($opc == XC_ISSET_ISEMPTY) { @@ -2049,9 +2066,6 @@ class Decompiler // }}} case XC_JMP_NO_CTOR: break; - case XC_JMP_SET: // ?: - $resvar = new Decompiler_Binop($this, $this->getOpVal($op1, $EX), XC_JMP_SET, null); - break; case XC_JMPZ_EX: // and case XC_JMPNZ_EX: // or $resvar = $this->getOpVal($op1, $EX); @@ -2468,7 +2482,7 @@ class Decompiler } echo $isInterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']); if ($class['parent']) { - echo ' extends ', $class['parent']; + echo ' extends ', $this->stripNamespace($class['parent']); } /* TODO */ if (!empty($class['interfaces'])) { @@ -2856,6 +2870,7 @@ foreach (array ( 'XC_ISSET_ISEMPTY' => -1, 'XC_JMP_NO_CTOR' => -1, 'XC_JMP_SET' => -1, + 'XC_JMP_SET_VAR' => -1, 'XC_QM_ASSIGN_VAR' => -1, 'XC_UNSET_DIM_OBJ' => -1, ) as $k => $v) { diff --git a/mod_disassembler/sample.php b/mod_disassembler/sample.php index b0297cc..faeaa85 100644 --- a/mod_disassembler/sample.php +++ b/mod_disassembler/sample.php @@ -36,24 +36,49 @@ abstract class ClassName { echo CONST_VALUE; echo ClassName::CONST_VALUE; - unset(ClassName::$classProp1); + empty(ClassName::$classProp); + isset(ClassName::$classProp); + unset(ClassName::$classProp); + ClassName::$classProp = 1; + echo ClassName::$classProp; + empty($obj->objProp); + isset($obj->objProp); unset($obj->objProp); + $obj->objProp = 1; + echo $obj->objProp; + empty($this->thisProp); + isset($this->thisProp); unset($this->thisProp); + $this->thisProp = 1; + echo $this->thisProp; unset($array['index']->valueProp); unset($obj->array['index']); unset($this->array['index']); - isset($GLOBALS['a']); - empty($GLOBALS['a']); - unset($GLOBALS['a']); - isset(ClassName::$a); - empty(ClassName::$a); - unset(ClassName::$a); - echo $GLOBALS['a']; - $obj->objProp = 1; - $this->thisProp = 1; - $array['index']->valueProp = 1; + empty($_GET['get']); + isset($_GET['get']); + unset($_GET['get']); + $_GET['get'] = 1; + echo $_GET['get']; + isset($GLOBALS['global']); + empty($GLOBALS['global']); + unset($GLOBALS['global']); + $GLOBALS['global'] = 1; + echo $GLOBALS['global']; + empty($array['index']); + isset($array['index']); + unset($array['index']); $array['index'] = 1; - $array[1] = 1; + echo $array['index']; + empty($array['index']->indexProp); + isset($array['index']->indexProp); + unset($array['index']->indexProp); + $array['index']->indexProp = 1; + echo $array['index']->indexProp; + empty($GLOBALS['var']->indexProp); + isset($GLOBALS['var']->indexProp); + unset($GLOBALS['var']->indexProp); + $GLOBALS['var']->indexProp = 1; + echo $GLOBALS['var']->indexProp; } /** doc */ @@ -437,6 +462,7 @@ $obj::__construct(); $a = $b ?: $d; $a = ($b ?: $d) + $c; $a = f1() ?: f2(); +$a = C::f1() ?: C::f2(); $a = ($b ? $c : $d); $a = ($b ? $c : $d) + $c; $a = (f1() ? f3() : f2()); diff --git a/xcache/xc_opcode_spec.c b/xcache/xc_opcode_spec.c index b563181..5043506 100644 --- a/xcache/xc_opcode_spec.c +++ b/xcache/xc_opcode_spec.c @@ -5,6 +5,10 @@ /* {{{ opcode_spec */ #define OPSPEC(ext, op1, op2, res) { OPSPEC_##ext, OPSPEC_##op1, OPSPEC_##op2, OPSPEC_##res }, #define OPSPEC_VAR_2 OPSPEC_STD +#ifdef ZEND_ENGINE_2_4 +#undef OPSPEC_FETCH +#define OPSPEC_FETCH OPSPEC_STD +#endif #include "xc_opcode_spec_def.h" zend_uchar xc_get_opcode_spec_count() diff --git a/xcache/xc_opcode_spec_def.h b/xcache/xc_opcode_spec_def.h index 13dd0f1..1ab75a5 100644 --- a/xcache/xc_opcode_spec_def.h +++ b/xcache/xc_opcode_spec_def.h @@ -79,11 +79,7 @@ static const xc_opcode_spec_t xc_opcode_spec[] = { OPSPEC( UNUSED, STD, INCLUDE, VAR) /* 73 INCLUDE_OR_EVAL */ #ifdef ZEND_ENGINE_2_1 /* php 5.1 and up */ -# ifdef ZEND_ENGINE_2_4 - OPSPEC( UNUSED, STD, STD, UNUSED) /* 74 UNSET_VAR */ -# else OPSPEC( UNUSED, STD, FETCH, UNUSED) /* 74 UNSET_VAR */ -# endif OPSPEC( STD, STD, STD, UNUSED) /* 75 UNSET_DIM */ OPSPEC( STD, STD, STD, UNUSED) /* 76 UNSET_OBJ */ OPSPEC( BIT, STD, OPLINE, VAR) /* 77 FE_RESET */ @@ -153,11 +149,7 @@ static const xc_opcode_spec_t xc_opcode_spec[] = { #else OPSPEC( UNUSED, UCLASS, STD, UNUSED) /* 113 INIT_STATIC_METHOD_CALL */ #endif -#ifdef ZEND_ENGINE_2_4 - OPSPEC( ISSET, STD, STD, TMP) /* 114 ISSET_ISEMPTY_VAR */ -#else OPSPEC( ISSET, STD, FETCH, TMP) /* 114 ISSET_ISEMPTY_VAR */ -#endif OPSPEC( ISSET, STD, STD, TMP) /* 115 ISSET_ISEMPTY_DIM_OBJ */ OPSPEC( UNUSED, CLASS, STD, UNUSED) /* 116 IMPORT_FUNCTION */