From 48de97461e88ed5c4177d97da4b5cfd067209780 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 1 Apr 2020 10:25:22 +0200 Subject: [PATCH] Make numeric operations on resources, arrays and objects type errors --- Zend/tests/add_003.phpt | 4 - Zend/tests/bug54305.phpt | 17 +- Zend/tests/bug73337.phpt | 5 +- Zend/tests/compound_assign_failure.phpt | 66 +- Zend/tests/decrement_001_64bit.phpt | 13 +- Zend/tests/gc_038.phpt | 68 +- Zend/tests/mod_001.phpt | 6 +- Zend/tests/not_002.phpt | 4 +- Zend/tests/operator_unsupported_types.phpt | 860 ++++++++++++++++++ Zend/tests/xor_001.phpt | 9 +- Zend/zend_compile.c | 8 +- Zend/zend_operators.c | 188 ++-- ext/opcache/Optimizer/zend_inference.c | 19 +- ext/opcache/jit/zend_jit.c | 3 +- ext/opcache/jit/zend_jit_trace.c | 3 +- ext/opcache/jit/zend_jit_x86.dasc | 5 +- .../tests/math/pow_variation1_64bit.phpt | 4 +- ext/standard/tests/math/pow_variation2.phpt | 4 +- 18 files changed, 1120 insertions(+), 166 deletions(-) create mode 100644 Zend/tests/operator_unsupported_types.phpt diff --git a/Zend/tests/add_003.phpt b/Zend/tests/add_003.phpt index 0f03f550e0282..69edb7cb1ec0e 100644 --- a/Zend/tests/add_003.phpt +++ b/Zend/tests/add_003.phpt @@ -20,12 +20,8 @@ var_dump($c); echo "Done\n"; ?> --EXPECTF-- -Notice: Object of class stdClass could not be converted to number in %sadd_003.php on line %d - Exception: Unsupported operand types: object + array -Notice: Object of class stdClass could not be converted to number in %s on line %d - Fatal error: Uncaught TypeError: Unsupported operand types: object + array in %s:%d Stack trace: #0 {main} diff --git a/Zend/tests/bug54305.phpt b/Zend/tests/bug54305.phpt index 8e85d2be58ec1..a443d480ec569 100644 --- a/Zend/tests/bug54305.phpt +++ b/Zend/tests/bug54305.phpt @@ -9,14 +9,11 @@ class TestClass { abstract class AbstractClass { } $methodWithArgs = new ReflectionMethod('TestClass', 'methodWithArgs'); -echo $methodWithArgs++; -?> ---EXPECTF-- -Method [ public method methodWithArgs ] { - @@ %sbug54305.php %d - %d - - - Parameters [2] { - Parameter #0 [ $a ] - Parameter #1 [ $b ] - } +try { + echo $methodWithArgs++; +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; } +?> +--EXPECT-- +Cannot increment object diff --git a/Zend/tests/bug73337.phpt b/Zend/tests/bug73337.phpt index 53ce963c529fa..a338aa605c781 100644 --- a/Zend/tests/bug73337.phpt +++ b/Zend/tests/bug73337.phpt @@ -5,8 +5,5 @@ Bug #73337 (try/catch not working with two exceptions inside a same operation) class d { function __destruct() { throw new Exception; } } try { new d + new d; } catch (Exception $e) { print "Exception properly caught\n"; } ?> ---EXPECTF-- -Notice: Object of class d could not be converted to number in %sbug73337.php on line 3 - -Notice: Object of class d could not be converted to number in %sbug73337.php on line 3 +--EXPECT-- Exception properly caught diff --git a/Zend/tests/compound_assign_failure.phpt b/Zend/tests/compound_assign_failure.phpt index 1780725d93dce..0dc9af85f2530 100644 --- a/Zend/tests/compound_assign_failure.phpt +++ b/Zend/tests/compound_assign_failure.phpt @@ -34,167 +34,167 @@ try { $x = new stdClass; try { $x += 1; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = 1; try { $x += new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = "foo"; try { $x += new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = new stdClass; try { $x -= 1; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = 1; try { $x -= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = "foo"; try { $x -= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = new stdClass; try { $x *= 1; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = 1; try { $x *= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = "foo"; try { $x *= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = new stdClass; try { $x /= 1; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = 1; try { $x /= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = "foo"; try { $x /= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = new stdClass; try { $x %= 1; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = 1; try { $x %= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = "foo"; try { $x %= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = new stdClass; try { $x **= 1; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = 1; try { $x **= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = "foo"; try { $x **= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = new stdClass; try { $x ^= 1; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = 1; try { $x ^= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = "foo"; try { $x ^= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = new stdClass; try { $x &= 1; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = 1; try { $x &= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = "foo"; try { $x &= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = new stdClass; try { $x |= 1; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = 1; try { $x |= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = "foo"; try { $x |= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = new stdClass; try { $x <<= 1; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = 1; try { $x <<= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = "foo"; try { $x <<= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = new stdClass; try { $x >>= 1; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = 1; try { $x >>= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); $x = "foo"; try { $x >>= new stdClass; } -catch (Exception $e) {} +catch (Throwable $e) {} var_dump($x); ?> diff --git a/Zend/tests/decrement_001_64bit.phpt b/Zend/tests/decrement_001_64bit.phpt index 2b2100932a3c1..a96d8cbd0712f 100644 --- a/Zend/tests/decrement_001_64bit.phpt +++ b/Zend/tests/decrement_001_64bit.phpt @@ -26,13 +26,18 @@ $a = array( ); foreach ($a as $var) { - $var--; + try { + $var--; + } catch (TypeError $e) { + echo $e->getMessage(), "\n"; + } var_dump($var); } echo "Done\n"; ?> ---EXPECTF-- +--EXPECT-- +Cannot decrement array array(3) { [0]=> int(1) @@ -51,8 +56,10 @@ float(1.5) NULL bool(true) bool(false) -object(stdClass)#%d (0) { +Cannot decrement object +object(stdClass)#1 (0) { } +Cannot decrement array array(0) { } float(-9.223372036854776E+18) diff --git a/Zend/tests/gc_038.phpt b/Zend/tests/gc_038.phpt index d3219531d6152..91f22bf154b30 100644 --- a/Zend/tests/gc_038.phpt +++ b/Zend/tests/gc_038.phpt @@ -6,8 +6,10 @@ zend.enable_gc = 1 x= $x; - @$x += 5; + $x->x = $x; + try { + $x += 5; + } catch (TypeError $e) { unset($x); } $n = gc_collect_cycles(); echo "+=\t$n\n"; } @@ -15,8 +17,10 @@ test_add(); function test_sub() { $x = new stdClass; - $x->x= $x; - @$x -= 5; + $x->x = $x; + try { + $x -= 5; + } catch (TypeError $e) { unset($x); } $n = gc_collect_cycles(); echo "-=\t$n\n"; } @@ -24,8 +28,10 @@ test_sub(); function test_mul() { $x = new stdClass; - $x->x= $x; - @$x *= 5; + $x->x = $x; + try { + $x *= 5; + } catch (TypeError $e) { unset($x); } $n = gc_collect_cycles(); echo "*=\t$n\n"; } @@ -33,8 +39,10 @@ test_mul(); function test_div() { $x = new stdClass; - $x->x= $x; - @$x /= 5; + $x->x = $x; + try { + $x /= 5; + } catch (TypeError $e) { unset($x); } $n = gc_collect_cycles(); echo "/=\t$n\n"; } @@ -42,8 +50,10 @@ test_div(); function test_mod() { $x = new stdClass; - $x->x= $x; - @$x %= 5; + $x->x = $x; + try { + $x %= 5; + } catch (TypeError $e) { unset($x); } $n = gc_collect_cycles(); echo "%=\t$n\n"; } @@ -51,8 +61,10 @@ test_mod(); function test_sl() { $x = new stdClass; - $x->x= $x; - @$x <<= 5; + $x->x = $x; + try { + $x <<= 5; + } catch (TypeError $e) { unset($x); } $n = gc_collect_cycles(); echo "<<=\t$n\n"; } @@ -60,8 +72,10 @@ test_sl(); function test_sr() { $x = new stdClass; - $x->x= $x; - @$x >>= 5; + $x->x = $x; + try { + $x >>= 5; + } catch (TypeError $e) { unset($x); } $n = gc_collect_cycles(); echo ">>=\t$n\n"; } @@ -69,8 +83,10 @@ test_sr(); function test_or() { $x = new stdClass; - $x->x= $x; - @$x |= 1; + $x->x = $x; + try { + $x |= 5; + } catch (TypeError $e) { unset($x); } $n = gc_collect_cycles(); echo "|=\t$n\n"; } @@ -78,8 +94,10 @@ test_or(); function test_and() { $x = new stdClass; - $x->x= $x; - @$x &= 1; + $x->x = $x; + try { + $x &= 5; + } catch (TypeError $e) { unset($x); } $n = gc_collect_cycles(); echo "&=\t$n\n"; } @@ -87,8 +105,10 @@ test_and(); function test_xor() { $x = new stdClass; - $x->x= $x; - @$x ^= 1; + $x->x = $x; + try { + $x ^= 5; + } catch (TypeError $e) { unset($x); } $n = gc_collect_cycles(); echo "^=\t$n\n"; } @@ -96,8 +116,10 @@ test_xor(); function test_pow() { $x = new stdClass; - $x->x= $x; - @$x **= 1; + $x->x = $x; + try { + $x **= 5; + } catch (TypeError $e) { unset($x); } $n = gc_collect_cycles(); echo "**=\t$n\n"; } @@ -117,7 +139,7 @@ function test_concat() { } test_concat(); ?> ---EXPECT-- +--EXPECTF-- += 1 -= 1 *= 1 diff --git a/Zend/tests/mod_001.phpt b/Zend/tests/mod_001.phpt index a393a4364486a..5c543a26192c2 100644 --- a/Zend/tests/mod_001.phpt +++ b/Zend/tests/mod_001.phpt @@ -9,12 +9,12 @@ $b = array(); try { $c = $a % $b; var_dump($c); -} catch (DivisionByZeroError $e) { +} catch (TypeError $e) { echo "Exception: " . $e->getMessage() . "\n"; } echo "Done\n"; ?> ---EXPECT-- -Exception: Modulo by zero +--EXPECTF-- +Exception: Unsupported operand types: array % array Done diff --git a/Zend/tests/not_002.phpt b/Zend/tests/not_002.phpt index 38691a1a510ea..3282053b6b9d0 100644 --- a/Zend/tests/not_002.phpt +++ b/Zend/tests/not_002.phpt @@ -18,9 +18,9 @@ var_dump($a); echo "Done\n"; ?> --EXPECTF-- -Exception: Unsupported operand types +Exception: Cannot perform bitwise not on array -Fatal error: Uncaught Error: Unsupported operand types in %s:%d +Fatal error: Uncaught TypeError: Cannot perform bitwise not on array in %s:%d Stack trace: #0 {main} thrown in %s on line %d diff --git a/Zend/tests/operator_unsupported_types.phpt b/Zend/tests/operator_unsupported_types.phpt new file mode 100644 index 0000000000000..8b250eac0ae4c --- /dev/null +++ b/Zend/tests/operator_unsupported_types.phpt @@ -0,0 +1,860 @@ +--TEST-- +Using unsupported types with operators +--FILE-- +>', + '&', + '|', + '^', + // Works on booleans, never errors. + 'xor', + // Only generates errors that string conversion emits. + '.', +]; +$illegalValues = [ + '[]', + 'new stdClass', + 'STDOUT', +]; +$legalValues = [ + 'null', + 'true', + 'false', + '2', + '3.5', + '"123"', + '"foo"', // Semi-legal. +]; + +function evalBinOp(string $op, string $value1, string $value2) { + try { + eval("return $value1 $op $value2;"); + echo "No error for $value1 $op $value2\n"; + } catch (Throwable $e) { + echo $e->getMessage() . "\n"; + } +} + +echo "BINOP:\n"; +foreach ($binops as $op) { + foreach ($illegalValues as $illegalValue1) { + foreach ($illegalValues as $illegalValue2) { + evalBinOp($op, $illegalValue1, $illegalValue2); + } + } + foreach ($illegalValues as $illegalValue) { + foreach ($legalValues as $legalValue) { + evalBinOp($op, $illegalValue, $legalValue); + evalBinOp($op, $legalValue, $illegalValue); + } + } +} + +echo "\n\nUNOP:\n"; +foreach ($illegalValues as $illegalValue) { + try { + eval("return ~$illegalValue;"); + echo "No error for ~$copy\n"; + } catch (TypeError $e) { + echo $e->getMessage() . "\n"; + } +} + +echo "\n\nINCDEC:\n"; +foreach ($illegalValues as $illegalValue) { + $copy = eval("return $illegalValue;"); + try { + $copy++; + echo "No error for $copy++\n"; + } catch (TypeError $e) { + echo $e->getMessage() . "\n"; + } + $copy = eval("return $illegalValue;"); + try { + $copy--; + echo "No error for $copy--\n"; + } catch (TypeError $e) { + echo $e->getMessage() . "\n"; + } +} + +?> +--EXPECTF-- +BINOP: +No error for [] + [] +Unsupported operand types: array + object +Unsupported operand types: array + resource +Unsupported operand types: object + array +Unsupported operand types: object + object +Unsupported operand types: object + resource +Unsupported operand types: resource + array +Unsupported operand types: resource + object +Unsupported operand types: resource + resource +Unsupported operand types: array + null +Unsupported operand types: null + array +Unsupported operand types: array + bool +Unsupported operand types: bool + array +Unsupported operand types: array + bool +Unsupported operand types: bool + array +Unsupported operand types: array + int +Unsupported operand types: int + array +Unsupported operand types: array + float +Unsupported operand types: float + array +Unsupported operand types: array + string +Unsupported operand types: string + array +Unsupported operand types: array + string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string + array +Unsupported operand types: object + null +Unsupported operand types: null + object +Unsupported operand types: object + bool +Unsupported operand types: bool + object +Unsupported operand types: object + bool +Unsupported operand types: bool + object +Unsupported operand types: object + int +Unsupported operand types: int + object +Unsupported operand types: object + float +Unsupported operand types: float + object +Unsupported operand types: object + string +Unsupported operand types: string + object +Unsupported operand types: object + string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string + object +Unsupported operand types: resource + null +Unsupported operand types: null + resource +Unsupported operand types: resource + bool +Unsupported operand types: bool + resource +Unsupported operand types: resource + bool +Unsupported operand types: bool + resource +Unsupported operand types: resource + int +Unsupported operand types: int + resource +Unsupported operand types: resource + float +Unsupported operand types: float + resource +Unsupported operand types: resource + string +Unsupported operand types: string + resource +Unsupported operand types: resource + string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string + resource +Unsupported operand types: array - array +Unsupported operand types: array - object +Unsupported operand types: array - resource +Unsupported operand types: object - array +Unsupported operand types: object - object +Unsupported operand types: object - resource +Unsupported operand types: resource - array +Unsupported operand types: resource - object +Unsupported operand types: resource - resource +Unsupported operand types: array - null +Unsupported operand types: null - array +Unsupported operand types: array - bool +Unsupported operand types: bool - array +Unsupported operand types: array - bool +Unsupported operand types: bool - array +Unsupported operand types: array - int +Unsupported operand types: int - array +Unsupported operand types: array - float +Unsupported operand types: float - array +Unsupported operand types: array - string +Unsupported operand types: string - array +Unsupported operand types: array - string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string - array +Unsupported operand types: object - null +Unsupported operand types: null - object +Unsupported operand types: object - bool +Unsupported operand types: bool - object +Unsupported operand types: object - bool +Unsupported operand types: bool - object +Unsupported operand types: object - int +Unsupported operand types: int - object +Unsupported operand types: object - float +Unsupported operand types: float - object +Unsupported operand types: object - string +Unsupported operand types: string - object +Unsupported operand types: object - string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string - object +Unsupported operand types: resource - null +Unsupported operand types: null - resource +Unsupported operand types: resource - bool +Unsupported operand types: bool - resource +Unsupported operand types: resource - bool +Unsupported operand types: bool - resource +Unsupported operand types: resource - int +Unsupported operand types: int - resource +Unsupported operand types: resource - float +Unsupported operand types: float - resource +Unsupported operand types: resource - string +Unsupported operand types: string - resource +Unsupported operand types: resource - string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string - resource +Unsupported operand types: array * array +Unsupported operand types: object * array +Unsupported operand types: resource * array +Unsupported operand types: object * array +Unsupported operand types: object * object +Unsupported operand types: object * resource +Unsupported operand types: resource * array +Unsupported operand types: object * resource +Unsupported operand types: resource * resource +Unsupported operand types: array * null +Unsupported operand types: null * array +Unsupported operand types: array * bool +Unsupported operand types: bool * array +Unsupported operand types: array * bool +Unsupported operand types: bool * array +Unsupported operand types: array * int +Unsupported operand types: int * array +Unsupported operand types: array * float +Unsupported operand types: float * array +Unsupported operand types: array * string +Unsupported operand types: string * array +Unsupported operand types: array * string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string * array +Unsupported operand types: object * null +Unsupported operand types: object * null +Unsupported operand types: object * bool +Unsupported operand types: object * bool +Unsupported operand types: object * bool +Unsupported operand types: object * bool +Unsupported operand types: object * int +Unsupported operand types: object * int +Unsupported operand types: object * float +Unsupported operand types: object * float +Unsupported operand types: object * string +Unsupported operand types: object * string +Unsupported operand types: object * string +Unsupported operand types: object * string +Unsupported operand types: resource * null +Unsupported operand types: resource * null +Unsupported operand types: resource * bool +Unsupported operand types: resource * bool +Unsupported operand types: resource * bool +Unsupported operand types: resource * bool +Unsupported operand types: resource * int +Unsupported operand types: resource * int +Unsupported operand types: resource * float +Unsupported operand types: resource * float +Unsupported operand types: resource * string +Unsupported operand types: resource * string +Unsupported operand types: resource * string +Unsupported operand types: resource * string +Unsupported operand types: array / array +Unsupported operand types: array / object +Unsupported operand types: array / resource +Unsupported operand types: object / array +Unsupported operand types: object / object +Unsupported operand types: object / resource +Unsupported operand types: resource / array +Unsupported operand types: resource / object +Unsupported operand types: resource / resource +Unsupported operand types: array / null +Unsupported operand types: null / array +Unsupported operand types: array / bool +Unsupported operand types: bool / array +Unsupported operand types: array / bool +Unsupported operand types: bool / array +Unsupported operand types: array / int +Unsupported operand types: int / array +Unsupported operand types: array / float +Unsupported operand types: float / array +Unsupported operand types: array / string +Unsupported operand types: string / array +Unsupported operand types: array / string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string / array +Unsupported operand types: object / null +Unsupported operand types: null / object +Unsupported operand types: object / bool +Unsupported operand types: bool / object +Unsupported operand types: object / bool +Unsupported operand types: bool / object +Unsupported operand types: object / int +Unsupported operand types: int / object +Unsupported operand types: object / float +Unsupported operand types: float / object +Unsupported operand types: object / string +Unsupported operand types: string / object +Unsupported operand types: object / string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string / object +Unsupported operand types: resource / null +Unsupported operand types: null / resource +Unsupported operand types: resource / bool +Unsupported operand types: bool / resource +Unsupported operand types: resource / bool +Unsupported operand types: bool / resource +Unsupported operand types: resource / int +Unsupported operand types: int / resource +Unsupported operand types: resource / float +Unsupported operand types: float / resource +Unsupported operand types: resource / string +Unsupported operand types: string / resource +Unsupported operand types: resource / string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string / resource +Unsupported operand types: array % array +Unsupported operand types: array % object +Unsupported operand types: array % resource +Unsupported operand types: object % array +Unsupported operand types: object % object +Unsupported operand types: object % resource +Unsupported operand types: resource % array +Unsupported operand types: resource % object +Unsupported operand types: resource % resource +Unsupported operand types: array % null +Unsupported operand types: null % array +Unsupported operand types: array % bool +Unsupported operand types: bool % array +Unsupported operand types: array % bool +Unsupported operand types: bool % array +Unsupported operand types: array % int +Unsupported operand types: int % array +Unsupported operand types: array % float +Unsupported operand types: float % array +Unsupported operand types: array % string +Unsupported operand types: string % array +Unsupported operand types: array % string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string % array +Unsupported operand types: object % null +Unsupported operand types: null % object +Unsupported operand types: object % bool +Unsupported operand types: bool % object +Unsupported operand types: object % bool +Unsupported operand types: bool % object +Unsupported operand types: object % int +Unsupported operand types: int % object +Unsupported operand types: object % float +Unsupported operand types: float % object +Unsupported operand types: object % string +Unsupported operand types: string % object +Unsupported operand types: object % string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string % object +Unsupported operand types: resource % null +Unsupported operand types: null % resource +Unsupported operand types: resource % bool +Unsupported operand types: bool % resource +Unsupported operand types: resource % bool +Unsupported operand types: bool % resource +Unsupported operand types: resource % int +Unsupported operand types: int % resource +Unsupported operand types: resource % float +Unsupported operand types: float % resource +Unsupported operand types: resource % string +Unsupported operand types: string % resource +Unsupported operand types: resource % string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string % resource +Unsupported operand types: array ** array +Unsupported operand types: array ** object +Unsupported operand types: array ** resource +Unsupported operand types: object ** array +Unsupported operand types: object ** object +Unsupported operand types: object ** resource +Unsupported operand types: resource ** array +Unsupported operand types: resource ** object +Unsupported operand types: resource ** resource +Unsupported operand types: array ** null +Unsupported operand types: null ** array +Unsupported operand types: array ** bool +Unsupported operand types: bool ** array +Unsupported operand types: array ** bool +Unsupported operand types: bool ** array +Unsupported operand types: array ** int +Unsupported operand types: int ** array +Unsupported operand types: array ** float +Unsupported operand types: float ** array +Unsupported operand types: array ** string +Unsupported operand types: string ** array +Unsupported operand types: array ** string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string ** array +Unsupported operand types: object ** null +Unsupported operand types: null ** object +Unsupported operand types: object ** bool +Unsupported operand types: bool ** object +Unsupported operand types: object ** bool +Unsupported operand types: bool ** object +Unsupported operand types: object ** int +Unsupported operand types: int ** object +Unsupported operand types: object ** float +Unsupported operand types: float ** object +Unsupported operand types: object ** string +Unsupported operand types: string ** object +Unsupported operand types: object ** string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string ** object +Unsupported operand types: resource ** null +Unsupported operand types: null ** resource +Unsupported operand types: resource ** bool +Unsupported operand types: bool ** resource +Unsupported operand types: resource ** bool +Unsupported operand types: bool ** resource +Unsupported operand types: resource ** int +Unsupported operand types: int ** resource +Unsupported operand types: resource ** float +Unsupported operand types: float ** resource +Unsupported operand types: resource ** string +Unsupported operand types: string ** resource +Unsupported operand types: resource ** string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string ** resource +Unsupported operand types: array << array +Unsupported operand types: array << object +Unsupported operand types: array << resource +Unsupported operand types: object << array +Unsupported operand types: object << object +Unsupported operand types: object << resource +Unsupported operand types: resource << array +Unsupported operand types: resource << object +Unsupported operand types: resource << resource +Unsupported operand types: array << null +Unsupported operand types: null << array +Unsupported operand types: array << bool +Unsupported operand types: bool << array +Unsupported operand types: array << bool +Unsupported operand types: bool << array +Unsupported operand types: array << int +Unsupported operand types: int << array +Unsupported operand types: array << float +Unsupported operand types: float << array +Unsupported operand types: array << string +Unsupported operand types: string << array +Unsupported operand types: array << string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string << array +Unsupported operand types: object << null +Unsupported operand types: null << object +Unsupported operand types: object << bool +Unsupported operand types: bool << object +Unsupported operand types: object << bool +Unsupported operand types: bool << object +Unsupported operand types: object << int +Unsupported operand types: int << object +Unsupported operand types: object << float +Unsupported operand types: float << object +Unsupported operand types: object << string +Unsupported operand types: string << object +Unsupported operand types: object << string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string << object +Unsupported operand types: resource << null +Unsupported operand types: null << resource +Unsupported operand types: resource << bool +Unsupported operand types: bool << resource +Unsupported operand types: resource << bool +Unsupported operand types: bool << resource +Unsupported operand types: resource << int +Unsupported operand types: int << resource +Unsupported operand types: resource << float +Unsupported operand types: float << resource +Unsupported operand types: resource << string +Unsupported operand types: string << resource +Unsupported operand types: resource << string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string << resource +Unsupported operand types: array >> array +Unsupported operand types: array >> object +Unsupported operand types: array >> resource +Unsupported operand types: object >> array +Unsupported operand types: object >> object +Unsupported operand types: object >> resource +Unsupported operand types: resource >> array +Unsupported operand types: resource >> object +Unsupported operand types: resource >> resource +Unsupported operand types: array >> null +Unsupported operand types: null >> array +Unsupported operand types: array >> bool +Unsupported operand types: bool >> array +Unsupported operand types: array >> bool +Unsupported operand types: bool >> array +Unsupported operand types: array >> int +Unsupported operand types: int >> array +Unsupported operand types: array >> float +Unsupported operand types: float >> array +Unsupported operand types: array >> string +Unsupported operand types: string >> array +Unsupported operand types: array >> string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string >> array +Unsupported operand types: object >> null +Unsupported operand types: null >> object +Unsupported operand types: object >> bool +Unsupported operand types: bool >> object +Unsupported operand types: object >> bool +Unsupported operand types: bool >> object +Unsupported operand types: object >> int +Unsupported operand types: int >> object +Unsupported operand types: object >> float +Unsupported operand types: float >> object +Unsupported operand types: object >> string +Unsupported operand types: string >> object +Unsupported operand types: object >> string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string >> object +Unsupported operand types: resource >> null +Unsupported operand types: null >> resource +Unsupported operand types: resource >> bool +Unsupported operand types: bool >> resource +Unsupported operand types: resource >> bool +Unsupported operand types: bool >> resource +Unsupported operand types: resource >> int +Unsupported operand types: int >> resource +Unsupported operand types: resource >> float +Unsupported operand types: float >> resource +Unsupported operand types: resource >> string +Unsupported operand types: string >> resource +Unsupported operand types: resource >> string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string >> resource +Unsupported operand types: array & array +Unsupported operand types: object & array +Unsupported operand types: resource & array +Unsupported operand types: object & array +Unsupported operand types: object & object +Unsupported operand types: object & resource +Unsupported operand types: resource & array +Unsupported operand types: object & resource +Unsupported operand types: resource & resource +Unsupported operand types: array & null +Unsupported operand types: null & array +Unsupported operand types: array & bool +Unsupported operand types: bool & array +Unsupported operand types: array & bool +Unsupported operand types: bool & array +Unsupported operand types: array & int +Unsupported operand types: int & array +Unsupported operand types: array & float +Unsupported operand types: float & array +Unsupported operand types: array & string +Unsupported operand types: string & array +Unsupported operand types: array & string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string & array +Unsupported operand types: object & null +Unsupported operand types: object & null +Unsupported operand types: object & bool +Unsupported operand types: object & bool +Unsupported operand types: object & bool +Unsupported operand types: object & bool +Unsupported operand types: object & int +Unsupported operand types: object & int +Unsupported operand types: object & float +Unsupported operand types: object & float +Unsupported operand types: object & string +Unsupported operand types: object & string +Unsupported operand types: object & string +Unsupported operand types: object & string +Unsupported operand types: resource & null +Unsupported operand types: resource & null +Unsupported operand types: resource & bool +Unsupported operand types: resource & bool +Unsupported operand types: resource & bool +Unsupported operand types: resource & bool +Unsupported operand types: resource & int +Unsupported operand types: resource & int +Unsupported operand types: resource & float +Unsupported operand types: resource & float +Unsupported operand types: resource & string +Unsupported operand types: resource & string +Unsupported operand types: resource & string +Unsupported operand types: resource & string +Unsupported operand types: array | array +Unsupported operand types: object | array +Unsupported operand types: resource | array +Unsupported operand types: object | array +Unsupported operand types: object | object +Unsupported operand types: object | resource +Unsupported operand types: resource | array +Unsupported operand types: object | resource +Unsupported operand types: resource | resource +Unsupported operand types: array | null +Unsupported operand types: null | array +Unsupported operand types: array | bool +Unsupported operand types: bool | array +Unsupported operand types: array | bool +Unsupported operand types: bool | array +Unsupported operand types: array | int +Unsupported operand types: int | array +Unsupported operand types: array | float +Unsupported operand types: float | array +Unsupported operand types: array | string +Unsupported operand types: string | array +Unsupported operand types: array | string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string | array +Unsupported operand types: object | null +Unsupported operand types: object | null +Unsupported operand types: object | bool +Unsupported operand types: object | bool +Unsupported operand types: object | bool +Unsupported operand types: object | bool +Unsupported operand types: object | int +Unsupported operand types: object | int +Unsupported operand types: object | float +Unsupported operand types: object | float +Unsupported operand types: object | string +Unsupported operand types: object | string +Unsupported operand types: object | string +Unsupported operand types: object | string +Unsupported operand types: resource | null +Unsupported operand types: resource | null +Unsupported operand types: resource | bool +Unsupported operand types: resource | bool +Unsupported operand types: resource | bool +Unsupported operand types: resource | bool +Unsupported operand types: resource | int +Unsupported operand types: resource | int +Unsupported operand types: resource | float +Unsupported operand types: resource | float +Unsupported operand types: resource | string +Unsupported operand types: resource | string +Unsupported operand types: resource | string +Unsupported operand types: resource | string +Unsupported operand types: array ^ array +Unsupported operand types: object ^ array +Unsupported operand types: resource ^ array +Unsupported operand types: object ^ array +Unsupported operand types: object ^ object +Unsupported operand types: object ^ resource +Unsupported operand types: resource ^ array +Unsupported operand types: object ^ resource +Unsupported operand types: resource ^ resource +Unsupported operand types: array ^ null +Unsupported operand types: null ^ array +Unsupported operand types: array ^ bool +Unsupported operand types: bool ^ array +Unsupported operand types: array ^ bool +Unsupported operand types: bool ^ array +Unsupported operand types: array ^ int +Unsupported operand types: int ^ array +Unsupported operand types: array ^ float +Unsupported operand types: float ^ array +Unsupported operand types: array ^ string +Unsupported operand types: string ^ array +Unsupported operand types: array ^ string + +Warning: A non-numeric value encountered in %s on line %d +Unsupported operand types: string ^ array +Unsupported operand types: object ^ null +Unsupported operand types: object ^ null +Unsupported operand types: object ^ bool +Unsupported operand types: object ^ bool +Unsupported operand types: object ^ bool +Unsupported operand types: object ^ bool +Unsupported operand types: object ^ int +Unsupported operand types: object ^ int +Unsupported operand types: object ^ float +Unsupported operand types: object ^ float +Unsupported operand types: object ^ string +Unsupported operand types: object ^ string +Unsupported operand types: object ^ string +Unsupported operand types: object ^ string +Unsupported operand types: resource ^ null +Unsupported operand types: resource ^ null +Unsupported operand types: resource ^ bool +Unsupported operand types: resource ^ bool +Unsupported operand types: resource ^ bool +Unsupported operand types: resource ^ bool +Unsupported operand types: resource ^ int +Unsupported operand types: resource ^ int +Unsupported operand types: resource ^ float +Unsupported operand types: resource ^ float +Unsupported operand types: resource ^ string +Unsupported operand types: resource ^ string +Unsupported operand types: resource ^ string +Unsupported operand types: resource ^ string +No error for [] xor [] +No error for [] xor new stdClass +No error for [] xor STDOUT +No error for new stdClass xor [] +No error for new stdClass xor new stdClass +No error for new stdClass xor STDOUT +No error for STDOUT xor [] +No error for STDOUT xor new stdClass +No error for STDOUT xor STDOUT +No error for [] xor null +No error for null xor [] +No error for [] xor true +No error for true xor [] +No error for [] xor false +No error for false xor [] +No error for [] xor 2 +No error for 2 xor [] +No error for [] xor 3.5 +No error for 3.5 xor [] +No error for [] xor "123" +No error for "123" xor [] +No error for [] xor "foo" +No error for "foo" xor [] +No error for new stdClass xor null +No error for null xor new stdClass +No error for new stdClass xor true +No error for true xor new stdClass +No error for new stdClass xor false +No error for false xor new stdClass +No error for new stdClass xor 2 +No error for 2 xor new stdClass +No error for new stdClass xor 3.5 +No error for 3.5 xor new stdClass +No error for new stdClass xor "123" +No error for "123" xor new stdClass +No error for new stdClass xor "foo" +No error for "foo" xor new stdClass +No error for STDOUT xor null +No error for null xor STDOUT +No error for STDOUT xor true +No error for true xor STDOUT +No error for STDOUT xor false +No error for false xor STDOUT +No error for STDOUT xor 2 +No error for 2 xor STDOUT +No error for STDOUT xor 3.5 +No error for 3.5 xor STDOUT +No error for STDOUT xor "123" +No error for "123" xor STDOUT +No error for STDOUT xor "foo" +No error for "foo" xor STDOUT + +Warning: Array to string conversion in %s on line %d + +Warning: Array to string conversion in %s on line %d +No error for [] . [] + +Warning: Array to string conversion in %s on line %d +Object of class stdClass could not be converted to string + +Warning: Array to string conversion in %s on line %d +No error for [] . STDOUT + +Warning: Array to string conversion in %s on line %d +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string + +Warning: Array to string conversion in %s on line %d +No error for STDOUT . [] +Object of class stdClass could not be converted to string +No error for STDOUT . STDOUT + +Warning: Array to string conversion in %s on line %d +No error for [] . null + +Warning: Array to string conversion in %s on line %d +No error for null . [] + +Warning: Array to string conversion in %s on line %d +No error for [] . true + +Warning: Array to string conversion in %s on line %d +No error for true . [] + +Warning: Array to string conversion in %s on line %d +No error for [] . false + +Warning: Array to string conversion in %s on line %d +No error for false . [] + +Warning: Array to string conversion in %s on line %d +No error for [] . 2 + +Warning: Array to string conversion in %s on line %d +No error for 2 . [] + +Warning: Array to string conversion in %s on line %d +No error for [] . 3.5 + +Warning: Array to string conversion in %s on line %d +No error for 3.5 . [] + +Warning: Array to string conversion in %s on line %d +No error for [] . "123" + +Warning: Array to string conversion in %s on line %d +No error for "123" . [] + +Warning: Array to string conversion in %s on line %d +No error for [] . "foo" + +Warning: Array to string conversion in %s on line %d +No error for "foo" . [] +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +Object of class stdClass could not be converted to string +No error for STDOUT . null +No error for null . STDOUT +No error for STDOUT . true +No error for true . STDOUT +No error for STDOUT . false +No error for false . STDOUT +No error for STDOUT . 2 +No error for 2 . STDOUT +No error for STDOUT . 3.5 +No error for 3.5 . STDOUT +No error for STDOUT . "123" +No error for "123" . STDOUT +No error for STDOUT . "foo" +No error for "foo" . STDOUT + + +UNOP: +Cannot perform bitwise not on array +Cannot perform bitwise not on object +Cannot perform bitwise not on resource + + +INCDEC: +Cannot increment array +Cannot decrement array +Cannot increment object +Cannot decrement object +Cannot increment resource +Cannot decrement resource diff --git a/Zend/tests/xor_001.phpt b/Zend/tests/xor_001.phpt index 1a6d0fb6333c3..9678af16b5f71 100644 --- a/Zend/tests/xor_001.phpt +++ b/Zend/tests/xor_001.phpt @@ -6,11 +6,14 @@ XORing arrays $a = array(1,2,3); $b = array(); -$c = $a ^ $b; -var_dump($c); +try { + $c = $a ^ $b; +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} echo "Done\n"; ?> --EXPECT-- -int(1) +Unsupported operand types: array ^ array Done diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 1f0c6325bd2dc..7eb6a69d7e078 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7235,11 +7235,9 @@ ZEND_API zend_bool zend_binary_op_produces_error(uint32_t opcode, zval *op1, zva /* Adding two arrays is allowed. */ return 0; } - if (opcode == ZEND_ADD || opcode == ZEND_SUB || opcode == ZEND_MUL || opcode == ZEND_POW - || opcode == ZEND_DIV) { - /* These operators throw when one of the operands is an array. */ - return 1; - } + + /* Numeric operators throw when one of the operands is an array. */ + return 1; } /* While basic arithmetic operators always produce numeric string errors, diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index b4be563bac7bc..304274c03cef2 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -248,20 +248,17 @@ static zend_never_inline int ZEND_FASTCALL _zendi_try_convert_scalar_to_number(z } } return SUCCESS; - case IS_RESOURCE: - ZVAL_LONG(holder, Z_RES_HANDLE_P(op)); - return SUCCESS; case IS_OBJECT: - convert_object_to_type(op, holder, _IS_NUMBER); - if (UNEXPECTED(EG(exception))) { + if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), holder, _IS_NUMBER) == FAILURE + || EG(exception)) { return FAILURE; } - if (UNEXPECTED(Z_TYPE_P(holder) != IS_LONG && Z_TYPE_P(holder) != IS_DOUBLE)) { - ZVAL_LONG(holder, 1); - } + ZEND_ASSERT(Z_TYPE_P(holder) == IS_LONG || Z_TYPE_P(holder) == IS_DOUBLE); return SUCCESS; - default: + case IS_RESOURCE: + case IS_ARRAY: return FAILURE; + EMPTY_SWITCH_DEFAULT_CASE() } } /* }}} */ @@ -276,6 +273,59 @@ static zend_always_inline int zendi_try_convert_scalar_to_number(zval *op, zval } } +static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(zval *op, zend_bool *failed) /* {{{ */ +{ + *failed = 0; + switch (Z_TYPE_P(op)) { + case IS_NULL: + case IS_FALSE: + return 0; + case IS_TRUE: + return 1; + case IS_DOUBLE: + return zend_dval_to_lval(Z_DVAL_P(op)); + case IS_STRING: + { + zend_uchar type; + zend_long lval; + double dval; + if (0 == (type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval, -1))) { + zend_error(E_WARNING, "A non-numeric value encountered"); + if (UNEXPECTED(EG(exception))) { + *failed = 1; + } + return 0; + } else if (EXPECTED(type == IS_LONG)) { + return lval; + } else { + /* Previously we used strtol here, not is_numeric_string, + * and strtol gives you LONG_MAX/_MIN on overflow. + * We use use saturating conversion to emulate strtol()'s + * behaviour. + */ + return zend_dval_to_lval_cap(dval); + } + } + case IS_OBJECT: + { + zval dst; + if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), &dst, IS_LONG) == FAILURE + || EG(exception)) { + *failed = 1; + return 0; + } + ZEND_ASSERT(Z_TYPE(dst) == IS_LONG); + return Z_LVAL(dst); + } + case IS_RESOURCE: + case IS_ARRAY: + *failed = 1; + return 0; + EMPTY_SWITCH_DEFAULT_CASE() + } +} +/* }}} */ + #define ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(opcode) \ if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT) \ && UNEXPECTED(Z_OBJ_HANDLER_P(op1, do_operation))) { \ @@ -303,9 +353,10 @@ static zend_always_inline int zendi_try_convert_scalar_to_number(zval *op, zval return SUCCESS; \ } -#define convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, op) \ +#define convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, opcode, sigil) \ do { \ if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { \ + zend_bool failed; \ if (Z_ISREF_P(op1)) { \ op1 = Z_REFVAL_P(op1); \ if (Z_TYPE_P(op1) == IS_LONG) { \ @@ -313,9 +364,10 @@ static zend_always_inline int zendi_try_convert_scalar_to_number(zval *op, zval break; \ } \ } \ - ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(op); \ - op1_lval = _zval_get_long_func_noisy(op1); \ - if (UNEXPECTED(EG(exception))) { \ + ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(opcode); \ + op1_lval = zendi_try_get_long(op1, &failed); \ + if (UNEXPECTED(failed)) { \ + zend_binop_error(sigil, op1, op2); \ if (result != op1) { \ ZVAL_UNDEF(result); \ } \ @@ -327,6 +379,7 @@ static zend_always_inline int zendi_try_convert_scalar_to_number(zval *op, zval } while (0); \ do { \ if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { \ + zend_bool failed; \ if (Z_ISREF_P(op2)) { \ op2 = Z_REFVAL_P(op2); \ if (Z_TYPE_P(op2) == IS_LONG) { \ @@ -334,9 +387,10 @@ static zend_always_inline int zendi_try_convert_scalar_to_number(zval *op, zval break; \ } \ } \ - ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(op); \ - op2_lval = _zval_get_long_func_noisy(op2); \ - if (UNEXPECTED(EG(exception))) { \ + ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(opcode); \ + op2_lval = zendi_try_get_long(op2, &failed); \ + if (UNEXPECTED(failed)) { \ + zend_binop_error(sigil, op1, op2); \ if (result != op1) { \ ZVAL_UNDEF(result); \ } \ @@ -838,12 +892,6 @@ ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op) /* {{{ */ } /* }}} */ -static zend_long ZEND_FASTCALL _zval_get_long_func_noisy(zval *op) /* {{{ */ -{ - return _zval_get_long_func_ex(op, 0); -} -/* }}} */ - ZEND_API double ZEND_FASTCALL zval_get_double_func(zval *op) /* {{{ */ { try_again: @@ -1331,7 +1379,7 @@ ZEND_API int ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2) /* { { zend_long op1_lval, op2_lval; - convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_MOD); + convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_MOD, "%"); if (op2_lval == 0) { /* modulus by zero */ @@ -1470,7 +1518,8 @@ ZEND_API int ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1) /* {{{ if (result != op1) { ZVAL_UNDEF(result); } - zend_throw_error(NULL, "Unsupported operand types"); + zend_type_error("Cannot perform bitwise not on %s", + zend_get_type_by_const(Z_TYPE_P(op1))); return FAILURE; } } @@ -1522,9 +1571,11 @@ ZEND_API int ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op } if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { + zend_bool failed; ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR); - op1_lval = _zval_get_long_func_noisy(op1); - if (UNEXPECTED(EG(exception))) { + op1_lval = zendi_try_get_long(op1, &failed); + if (UNEXPECTED(failed)) { + zend_binop_error("|", op1, op2); if (result != op1) { ZVAL_UNDEF(result); } @@ -1534,9 +1585,11 @@ ZEND_API int ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op op1_lval = Z_LVAL_P(op1); } if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { + zend_bool failed; ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR); - op2_lval = _zval_get_long_func_noisy(op2); - if (UNEXPECTED(EG(exception))) { + op2_lval = zendi_try_get_long(op2, &failed); + if (UNEXPECTED(failed)) { + zend_binop_error("|", op1, op2); if (result != op1) { ZVAL_UNDEF(result); } @@ -1600,9 +1653,11 @@ ZEND_API int ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *o } if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { + zend_bool failed; ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND); - op1_lval = _zval_get_long_func_noisy(op1); - if (UNEXPECTED(EG(exception))) { + op1_lval = zendi_try_get_long(op1, &failed); + if (UNEXPECTED(failed)) { + zend_binop_error("&", op1, op2); if (result != op1) { ZVAL_UNDEF(result); } @@ -1612,9 +1667,11 @@ ZEND_API int ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *o op1_lval = Z_LVAL_P(op1); } if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { + zend_bool failed; ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND); - op2_lval = _zval_get_long_func_noisy(op2); - if (UNEXPECTED(EG(exception))) { + op2_lval = zendi_try_get_long(op2, &failed); + if (UNEXPECTED(failed)) { + zend_binop_error("&", op1, op2); if (result != op1) { ZVAL_UNDEF(result); } @@ -1678,9 +1735,11 @@ ZEND_API int ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *o } if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { + zend_bool failed; ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR); - op1_lval = _zval_get_long_func_noisy(op1); - if (UNEXPECTED(EG(exception))) { + op1_lval = zendi_try_get_long(op1, &failed); + if (UNEXPECTED(failed)) { + zend_binop_error("^", op1, op2); if (result != op1) { ZVAL_UNDEF(result); } @@ -1690,9 +1749,11 @@ ZEND_API int ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *o op1_lval = Z_LVAL_P(op1); } if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { + zend_bool failed; ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR); - op2_lval = _zval_get_long_func_noisy(op2); - if (UNEXPECTED(EG(exception))) { + op2_lval = zendi_try_get_long(op2, &failed); + if (UNEXPECTED(failed)) { + zend_binop_error("^", op1, op2); if (result != op1) { ZVAL_UNDEF(result); } @@ -1714,7 +1775,7 @@ ZEND_API int ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op { zend_long op1_lval, op2_lval; - convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SL); + convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SL, "<<"); /* prevent wrapping quirkiness on some processors where << 64 + x == << x */ if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) { @@ -1751,7 +1812,7 @@ ZEND_API int ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *o { zend_long op1_lval, op2_lval; - convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SR); + convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SR, ">>"); /* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */ if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) { @@ -2347,22 +2408,27 @@ ZEND_API int ZEND_FASTCALL increment_function(zval *op1) /* {{{ */ } } break; + case IS_FALSE: + case IS_TRUE: + /* Do nothing. */ + break; + case IS_REFERENCE: + op1 = Z_REFVAL_P(op1); + goto try_again; case IS_OBJECT: if (Z_OBJ_HANDLER_P(op1, do_operation)) { zval op2; - int res; - ZVAL_LONG(&op2, 1); - res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, &op2); - - return res; + if (Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, &op2) == SUCCESS) { + return SUCCESS; + } } + /* break missing intentionally */ + case IS_RESOURCE: + case IS_ARRAY: + zend_type_error("Cannot increment %s", zend_get_type_by_const(Z_TYPE_P(op1))); return FAILURE; - case IS_REFERENCE: - op1 = Z_REFVAL_P(op1); - goto try_again; - default: - return FAILURE; + EMPTY_SWITCH_DEFAULT_CASE() } return SUCCESS; } @@ -2403,22 +2469,28 @@ ZEND_API int ZEND_FASTCALL decrement_function(zval *op1) /* {{{ */ break; } break; + case IS_NULL: + case IS_FALSE: + case IS_TRUE: + /* Do nothing. */ + break; + case IS_REFERENCE: + op1 = Z_REFVAL_P(op1); + goto try_again; case IS_OBJECT: if (Z_OBJ_HANDLER_P(op1, do_operation)) { zval op2; - int res; - ZVAL_LONG(&op2, 1); - res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, &op2); - - return res; + if (Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, &op2) == SUCCESS) { + return SUCCESS; + } } + /* break missing intentionally */ + case IS_RESOURCE: + case IS_ARRAY: + zend_type_error("Cannot decrement %s", zend_get_type_by_const(Z_TYPE_P(op1))); return FAILURE; - case IS_REFERENCE: - op1 = Z_REFVAL_P(op1); - goto try_again; - default: - return FAILURE; + EMPTY_SWITCH_DEFAULT_CASE() } return SUCCESS; diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 8144185d07166..fcc229b385df6 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -4357,8 +4357,8 @@ int zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ && (t2 & MAY_BE_ANY) == MAY_BE_ARRAY) { return 0; } - return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) || - (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)); + return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || + (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); case ZEND_DIV: case ZEND_MOD: if (!OP2_HAS_RANGE() || @@ -4370,12 +4370,12 @@ int zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ case ZEND_SUB: case ZEND_MUL: case ZEND_POW: - return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) || - (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)); + return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || + (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); case ZEND_SL: case ZEND_SR: - return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) || - (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) || + return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || + (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || !OP2_HAS_RANGE() || OP2_MIN_RANGE() < 0; case ZEND_CONCAT: @@ -4389,15 +4389,16 @@ int zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ && (t2 & MAY_BE_ANY) == MAY_BE_STRING) { return 0; } - return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) || - (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)); + return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || + (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); case ZEND_BW_NOT: return (t1 & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); - case ZEND_BOOL_NOT: case ZEND_PRE_INC: case ZEND_POST_INC: case ZEND_PRE_DEC: case ZEND_POST_DEC: + return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); + case ZEND_BOOL_NOT: case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZNZ: diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 4839e93e6f919..034a68c479dc7 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2189,7 +2189,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op op1_def_info, OP1_DEF_REG_ADDR(), res_use_info, res_info, res_addr, - (op1_def_info & MAY_BE_LONG) && (op1_def_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, op_array, ssa))) { + (op1_def_info & MAY_BE_LONG) && (op1_def_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, op_array, ssa), + zend_may_throw(opline, ssa_op, op_array, ssa))) { goto jit_failure; } goto done; diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index d2fe33b63fbf6..a26fc6b0bf917 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -1900,7 +1900,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par op1_def_info, OP1_DEF_REG_ADDR(), res_use_info, res_info, res_addr, - (op1_def_info & MAY_BE_LONG) && (op1_def_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow_ex(opline, ssa_op, op_array, ssa))) { + (op1_def_info & MAY_BE_LONG) && (op1_def_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow_ex(opline, ssa_op, op_array, ssa), + zend_may_throw(opline, ssa_op, op_array, ssa))) { goto jit_failure; } if ((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)) { diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 3029d911ba9f9..673e526846128 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -3348,7 +3348,7 @@ static int zend_jit_update_regs(dasm_State **Dst, zend_jit_addr src, zend_jit_ad return 1; } -static int zend_jit_inc_dec(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op1_def_info, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow) +static int zend_jit_inc_dec(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op1_def_info, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw) { if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) { | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >2 @@ -3484,6 +3484,9 @@ static int zend_jit_inc_dec(dasm_State **Dst, const zend_op *opline, const zend_ | EXT_CALL decrement_function, r0 } } + if (may_throw) { + zend_jit_check_exception(Dst); + } } else { zend_reg tmp_reg; diff --git a/ext/standard/tests/math/pow_variation1_64bit.phpt b/ext/standard/tests/math/pow_variation1_64bit.phpt index 75b9f576db652..05cb9151ae1f7 100644 --- a/ext/standard/tests/math/pow_variation1_64bit.phpt +++ b/ext/standard/tests/math/pow_variation1_64bit.phpt @@ -174,9 +174,7 @@ Warning: A non-numeric value encountered in %s on line %d int(0) -- Iteration 23 -- - -Notice: Object of class classA could not be converted to number in %s on line %d -int(1) +Unsupported operand types: object ** int -- Iteration 24 -- int(0) diff --git a/ext/standard/tests/math/pow_variation2.phpt b/ext/standard/tests/math/pow_variation2.phpt index 8af96ef8d6d09..5d106ed9d2e7b 100644 --- a/ext/standard/tests/math/pow_variation2.phpt +++ b/ext/standard/tests/math/pow_variation2.phpt @@ -170,9 +170,7 @@ Warning: A non-numeric value encountered in %s on line %d float(1) -- Iteration 23 -- - -Notice: Object of class classA could not be converted to number in %s on line %d -float(20.3) +Unsupported operand types: float ** object -- Iteration 24 -- float(1)