Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Cleanup a few dynamically callable issues
Summary: - In/out wrappers should automatically inherit their dynamic callability from the function they are wrapping. - HackC should make all functions in systemlib be implicitly dynamically callable, not just native functions. - The HHAS assembler should not implicity mark things parsed during systemlib parsing as dynamically callable. Instead require the HHAS to explicitly indicate this (this prevents things like 86sinit from being marked dynamically callable). - Add a few more test cases Reviewed By: paulbiss Differential Revision: D7088310 fbshipit-source-id: 47700ca16d07093914863c059e3caa3a7f135542
- Loading branch information
Showing
with
329 additions
and 12 deletions.
- +9 −1 hphp/compiler/analysis/emitter.cpp
- +1 −1 hphp/hack/src/hhbc/emit_body.ml
- +4 −2 hphp/hack/src/hhbc/emit_function.ml
- +14 −4 hphp/hack/src/hhbc/emit_inout_function.ml
- +4 −2 hphp/hack/src/hhbc/emit_method.ml
- +0 −2 hphp/runtime/vm/as.cpp
- +1 −0 hphp/system/php/array_filter.hhas
- +1 −0 hphp/system/php/array_map.hhas
- +1 −0 hphp/system/php/array_reduce.hhas
- +86 −0 hphp/test/slow/dynamic-calls/inout.php
- +28 −0 hphp/test/slow/dynamic-calls/inout.php.expect
- +1 −0 hphp/test/slow/dynamic-calls/inout.php.hphp_opts
- +1 −0 hphp/test/slow/dynamic-calls/inout.php.opts
- +97 −0 hphp/test/slow/dynamic-calls/memoize.php
- +38 −0 hphp/test/slow/dynamic-calls/memoize.php.expect
- +1 −0 hphp/test/slow/dynamic-calls/memoize.php.hphp_opts
- +1 −0 hphp/test/slow/dynamic-calls/memoize.php.opts
- +34 −0 hphp/test/slow/dynamic-calls/reflection.php
- +5 −0 hphp/test/slow/dynamic-calls/reflection.php.expect
- +1 −0 hphp/test/slow/dynamic-calls/reflection.php.hphp_opts
- +1 −0 hphp/test/slow/dynamic-calls/reflection.php.opts
@@ -0,0 +1,86 @@ | ||
<?hh | ||
// Copyright 2004-present Facebook. All Rights Reserved. | ||
|
||
function wrap($e) { echo "Exception: {$e->getMessage()}\n"; } | ||
|
||
function func1(inout $x) {} | ||
<<__DynamicallyCallable>> function func4(inout $x) {} | ||
|
||
class A { | ||
public function func2(inout $x) {} | ||
public static function func3(inout $x) {} | ||
} | ||
|
||
class B { | ||
<<__DynamicallyCallable>> public function func5(inout $x) {} | ||
<<__DynamicallyCallable>> public static function func6(inout $x) {} | ||
} | ||
|
||
function positive_tests() { | ||
echo "====================== positive tests ========================\n"; | ||
$v = 123; | ||
|
||
try { $x = 'func1'; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'func1'; $x(inout $v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A::func2'; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A::func2'; $x(inout $v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A::func3'; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A::func3'; $x(inout $v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $x = ['A', 'func2']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = ['A', 'func2']; $x(inout $v); } catch (Exception $e) { wrap($e); } | ||
try { $x = ['A', 'func3']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = ['A', 'func3']; $x(inout $v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $x = [new A, 'func2']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = [new A, 'func2']; $x(inout $v); } catch (Exception $e) { wrap($e); } | ||
try { $x = [new A, 'func3']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = [new A, 'func3']; $x(inout $v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $x = 'A'; $x::func2($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A'; $x::func2(inout $v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A'; $x::func3($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A'; $x::func3(inout $v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $x = 'func2'; A::$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'func2'; A::$x(inout $v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'func3'; A::$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'func3'; A::$x(inout $v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $obj = new A; $x = 'func2'; $obj->$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $obj = new A; $x = 'func2'; $obj->$x(inout $v); } catch (Exception $e) { wrap($e); } | ||
try { $obj = new A; $x = 'func3'; $obj->$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $obj = new A; $x = 'func3'; $obj->$x(inout $v); } catch (Exception $e) { wrap($e); } | ||
} | ||
|
||
function negative_tests() { | ||
echo "====================== negative tests ========================\n"; | ||
$v = 123; | ||
|
||
$x = 'func4'; $x($v); | ||
$x = 'func4'; $x(inout $v); | ||
$x = 'B::func6'; $x($v); | ||
$x = 'B::func6'; $x(inout $v); | ||
|
||
$x = ['B', 'func6']; $x($v); | ||
$x = ['B', 'func6']; $x(inout $v); | ||
|
||
$x = [new B, 'func5']; $x($v); | ||
$x = [new B, 'func5']; $x(inout $v); | ||
$x = [new B, 'func6']; $x($v); | ||
$x = [new B, 'func6']; $x(inout $v); | ||
|
||
$x = 'B'; $x::func6($v); | ||
$x = 'B'; $x::func6(inout $v); | ||
|
||
$x = 'func6'; B::$x($v); | ||
$x = 'func6'; B::$x(inout $v); | ||
|
||
$obj = new B; $x = 'func5'; $obj->$x($v); | ||
$obj = new B; $x = 'func5'; $obj->$x(inout $v); | ||
$obj = new B; $x = 'func6'; $obj->$x($v); | ||
$obj = new B; $x = 'func6'; $obj->$x(inout $v); | ||
} | ||
|
||
positive_tests(); | ||
negative_tests(); |
@@ -0,0 +1,28 @@ | ||
====================== positive tests ======================== | ||
Exception: 'func1' called dynamically | ||
Exception: 'func1' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func2' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
Exception: 'A::func3' called dynamically | ||
====================== negative tests ======================== |
@@ -0,0 +1 @@ | ||
-vRuntime.Eval.ForbidDynamicCalls=2 -d hhvm.php7.all=0 |
@@ -0,0 +1 @@ | ||
-vEval.ForbidDynamicCalls=2 |
@@ -0,0 +1,97 @@ | ||
<?hh | ||
// Copyright 2004-present Facebook. All Rights Reserved. | ||
|
||
function wrap($e) { echo "Exception: {$e->getMessage()}\n"; } | ||
|
||
<<__Memoize>> function func1($x) {} | ||
<<__Memoize, __DynamicallyCallable>> function func4($x) {} | ||
|
||
class A { | ||
<<__Memoize>> public function func2($x) {} | ||
<<__Memoize>> public static function func3($x) {} | ||
|
||
public static function positive_tests() { | ||
echo "====================== positive tests (A) ==================\n"; | ||
$v = 123; | ||
|
||
try { $x = 'func1'; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'func1$memoize_impl'; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'func4$memoize_impl'; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A::func2'; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A::func2$memoize_impl'; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A::func3'; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A::func3$memoize_impl'; $x($v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $x = ['A', 'func2']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = ['A', 'func2$memoize_impl']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = ['A', 'func3']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = ['A', 'func3$memoize_impl']; $x($v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $x = [new A, 'func2']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = [new A, 'func2$memoize_impl']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = [new A, 'func3']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = [new A, 'func3$memoize_impl']; $x($v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $x = 'A'; $x::func2($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'A'; $x::func3($v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $x = 'func2'; A::$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'func2$memoize_impl'; A::$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'func3'; A::$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'func3$memoize_impl'; A::$x($v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $obj = new A; $x = 'func2'; $obj->$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $obj = new A; $x = 'func2$memoize_impl'; $obj->$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $obj = new A; $x = 'func3'; $obj->$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $obj = new A; $x = 'func3$memoize_impl'; $obj->$x($v); } catch (Exception $e) { wrap($e); } | ||
} | ||
} | ||
|
||
class B { | ||
<<__Memoize, __DynamicallyCallable>> public function func5($x) {} | ||
<<__Memoize, __DynamicallyCallable>> public static function func6($x) {} | ||
|
||
public static function positive_tests() { | ||
echo "====================== positive tests (B) ==================\n"; | ||
$v = 123; | ||
|
||
try { $x = 'func4$memoize_impl'; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'B::func6$memoize_impl'; $x($v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $x = ['B', 'func5$memoize_impl']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = ['B', 'func6$memoize_impl']; $x($v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $x = [new B, 'func5$memoize_impl']; $x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = [new B, 'func6$memoize_impl']; $x($v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $x = 'func5$memoize_impl'; B::$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $x = 'func6$memoize_impl'; B::$x($v); } catch (Exception $e) { wrap($e); } | ||
|
||
try { $obj = new B; $x = 'func5$memoize_impl'; $obj->$x($v); } catch (Exception $e) { wrap($e); } | ||
try { $obj = new B; $x = 'func6$memoize_impl'; $obj->$x($v); } catch (Exception $e) { wrap($e); } | ||
} | ||
|
||
public static function negative_tests() { | ||
echo "====================== negative tests ======================\n"; | ||
$v = 123; | ||
|
||
$x = 'func4'; $x($v); | ||
$x = 'B::func6'; $x($v); | ||
|
||
$x = ['B', 'func6']; $x($v); | ||
|
||
$x = [new B, 'func5']; $x($v); | ||
$x = [new B, 'func6']; $x($v); | ||
|
||
$x = 'B'; $x::func6($v); | ||
|
||
$x = 'func6'; B::$x($v); | ||
|
||
$obj = new B; $x = 'func5'; $obj->$x($v); | ||
$obj = new B; $x = 'func6'; $obj->$x($v); | ||
} | ||
} | ||
|
||
A::positive_tests(); | ||
B::positive_tests(); | ||
B::negative_tests(); |
Oops, something went wrong.