From 78df5374d503852402dbfc5b4d7fb6a892765ca5 Mon Sep 17 00:00:00 2001 From: ptarjan Date: Tue, 2 Apr 2013 20:40:05 -0700 Subject: [PATCH] change func_num_args() from parser error to warning I also introduced some code that I'll use to map their error messages to ours. --- hphp/compiler/parser/parser.cpp | 4 --- hphp/idl/function.idl.php | 3 +- hphp/runtime/ext/ext_function.cpp | 37 +++++++++++++++++++-- hphp/runtime/ext/ext_function.ext_hhvm.cpp | 9 +++-- hphp/runtime/ext/ext_function.ext_hhvm.h | 4 +-- hphp/runtime/ext/ext_function.h | 2 +- hphp/system/class_map.cpp | 4 +-- hphp/system/function.inc | 2 +- hphp/test/zend/bad/001.php.exp | 13 -------- hphp/test/zend/{bad => good}/001.php | 0 hphp/test/zend/good/001.php.exp | 13 ++++++++ hphp/test/zend/{bad => good}/002.php | 0 hphp/test/zend/{bad => good}/002.php.exp | 38 +++++++++++----------- hphp/test/zend/{bad => good}/003.php | 0 hphp/test/zend/{bad => good}/003.php.exp | 6 ++-- hphp/test/zend/good/011.php.exp | 4 +-- hphp/tools/import_zend_test.py | 13 ++++++-- 17 files changed, 94 insertions(+), 58 deletions(-) delete mode 100644 hphp/test/zend/bad/001.php.exp rename hphp/test/zend/{bad => good}/001.php (100%) create mode 100644 hphp/test/zend/good/001.php.exp rename hphp/test/zend/{bad => good}/002.php (100%) rename hphp/test/zend/{bad => good}/002.php.exp (57%) rename hphp/test/zend/{bad => good}/003.php (100%) rename hphp/test/zend/{bad => good}/003.php.exp (52%) diff --git a/hphp/compiler/parser/parser.cpp b/hphp/compiler/parser/parser.cpp index 735d7b508..53c6f1dcc 100644 --- a/hphp/compiler/parser/parser.cpp +++ b/hphp/compiler/parser/parser.cpp @@ -398,10 +398,6 @@ void Parser::onCall(Token &out, bool dynamic, Token &name, Token ¶ms, } else { const string &s = name.text(); if (s == "func_num_args" || s == "func_get_args" || s == "func_get_arg") { - if (m_hasCallToGetArgs.empty()) { - PARSE_ERROR("%s() Called from the global scope - no function context", - s.c_str()); - } m_hasCallToGetArgs.back() = true; } diff --git a/hphp/idl/function.idl.php b/hphp/idl/function.idl.php index cbe996f35..27b5083ac 100644 --- a/hphp/idl/function.idl.php +++ b/hphp/idl/function.idl.php @@ -470,8 +470,9 @@ DefineFunction( 'desc' => "Gets an array of the function's argument list.\n\nThis function may be used in conjunction with func_get_arg() and func_num_args() to allow user-defined functions to accept variable-length argument lists.", 'flags' => HasDocComment, 'return' => array( - 'type' => VariantVec, + 'type' => Variant, 'desc' => "Returns an array in which each element is a copy of the corresponding member of the current user-defined function's argument list.", + 'predicted_type' => VariantVec, ), 'taint_observer' => false, )); diff --git a/hphp/runtime/ext/ext_function.cpp b/hphp/runtime/ext/ext_function.cpp index e29f56f4c..f157da55b 100644 --- a/hphp/runtime/ext/ext_function.cpp +++ b/hphp/runtime/ext/ext_function.cpp @@ -263,7 +263,25 @@ Variant f_func_get_arg(int arg_num) { CallerFrame cf; ActRec* ar = cf(); - if (ar == NULL || arg_num < 0 || arg_num >= ar->numArgs()) { + if (ar == NULL) { + return false; + } + if (ar->hasVarEnv() && ar->getVarEnv()->isGlobalScope()) { + raise_warning( + "func_get_arg(): Called from the global scope - no function context" + ); + return false; + } + if (arg_num < 0) { + raise_warning( + "func_get_arg(): The argument number should be >= 0" + ); + return false; + } + if (arg_num >= ar->numArgs()) { + raise_warning( + "func_get_arg(): Argument %d not passed to function", arg_num + ); return false; } @@ -332,9 +350,16 @@ Array hhvm_get_frame_args(const ActRec* ar) { return Array(retval); } -Array f_func_get_args() { +Variant f_func_get_args() { CallerFrame cf; - return hhvm_get_frame_args(cf()); + ActRec* ar = cf(); + if (ar && ar->hasVarEnv() && ar->getVarEnv()->isGlobalScope()) { + raise_warning( + "func_get_args(): Called from the global scope - no function context" + ); + return false; + } + return hhvm_get_frame_args(ar); } Array func_get_args(int num_args, CArrRef params, CArrRef args) { @@ -363,6 +388,12 @@ int64_t f_func_num_args() { if (ar == NULL) { return -1; } + if (ar->hasVarEnv() && ar->getVarEnv()->isGlobalScope()) { + raise_warning( + "func_num_args(): Called from the global scope - no function context" + ); + return -1; + } return ar->numArgs(); } diff --git a/hphp/runtime/ext/ext_function.ext_hhvm.cpp b/hphp/runtime/ext/ext_function.ext_hhvm.cpp index c388ebf0f..e525bae19 100644 --- a/hphp/runtime/ext/ext_function.ext_hhvm.cpp +++ b/hphp/runtime/ext/ext_function.ext_hhvm.cpp @@ -895,23 +895,22 @@ TypedValue* fg_func_get_arg(HPHP::VM::ActRec *ar) { /* -HPHP::Array HPHP::f_func_get_args() +HPHP::Variant HPHP::f_func_get_args() _ZN4HPHP15f_func_get_argsEv (return value) => rax _rv => rdi */ -Value* fh_func_get_args(Value* _rv) asm("_ZN4HPHP15f_func_get_argsEv"); +TypedValue* fh_func_get_args(TypedValue* _rv) asm("_ZN4HPHP15f_func_get_argsEv"); TypedValue* fg_func_get_args(HPHP::VM::ActRec *ar) { TypedValue rv; int64_t count = ar->numArgs(); TypedValue* args UNUSED = ((TypedValue*)ar) - 1; if (count == 0LL) { - rv.m_type = KindOfArray; - fh_func_get_args((&rv.m_data)); - if (rv.m_data.num == 0LL) rv.m_type = KindOfNull; + fh_func_get_args((&(rv))); + if (rv.m_type == KindOfUninit) rv.m_type = KindOfNull; frame_free_locals_no_this_inl(ar, 0); memcpy(&ar->m_r, &rv, sizeof(TypedValue)); return &ar->m_r; diff --git a/hphp/runtime/ext/ext_function.ext_hhvm.h b/hphp/runtime/ext/ext_function.ext_hhvm.h index 72547b36d..7bb6ee212 100644 --- a/hphp/runtime/ext/ext_function.ext_hhvm.h +++ b/hphp/runtime/ext/ext_function.ext_hhvm.h @@ -215,14 +215,14 @@ arg_num => rsi TypedValue* fh_func_get_arg(TypedValue* _rv, int arg_num) asm("_ZN4HPHP14f_func_get_argEi"); /* -HPHP::Array HPHP::f_func_get_args() +HPHP::Variant HPHP::f_func_get_args() _ZN4HPHP15f_func_get_argsEv (return value) => rax _rv => rdi */ -Value* fh_func_get_args(Value* _rv) asm("_ZN4HPHP15f_func_get_argsEv"); +TypedValue* fh_func_get_args(TypedValue* _rv) asm("_ZN4HPHP15f_func_get_argsEv"); /* long HPHP::f_func_num_args() diff --git a/hphp/runtime/ext/ext_function.h b/hphp/runtime/ext/ext_function.h index 61e3ada2c..3fe43006c 100644 --- a/hphp/runtime/ext/ext_function.h +++ b/hphp/runtime/ext/ext_function.h @@ -53,7 +53,7 @@ Variant func_get_arg(int num_args, CArrRef params, CArrRef args, int pos); * PHP's func_get_args() is transformed to this function with some extra * parameters to help the implementation. */ -Array f_func_get_args(); +Variant f_func_get_args(); Array hhvm_get_frame_args(const VM::ActRec* ar); Array func_get_args(int num_args, CArrRef params, CArrRef args); diff --git a/hphp/system/class_map.cpp b/hphp/system/class_map.cpp index 09c8f307b..7d8d19eb8 100644 --- a/hphp/system/class_map.cpp +++ b/hphp/system/class_map.cpp @@ -7053,8 +7053,8 @@ const char *g_class_map[] = { NULL, NULL, (const char *)0x10006040, "func_get_args", "", (const char*)0, (const char*)0, - "/**\n * ( excerpt from http://php.net/manual/en/function.func-get-args.php )\n *\n * Gets an array of the function's argument list.\n *\n * This function may be used in conjunction with func_get_arg() and\n * func_num_args() to allow user-defined functions to accept\n * variable-length argument lists.\n *\n * @return vector Returns an array in which each element is a copy of\n * the corresponding member of the current user-defined\n * function's argument list.\n */", - (const char *)0x20, NULL, + "/**\n * ( excerpt from http://php.net/manual/en/function.func-get-args.php )\n *\n * Gets an array of the function's argument list.\n *\n * This function may be used in conjunction with func_get_arg() and\n * func_num_args() to allow user-defined functions to accept\n * variable-length argument lists.\n *\n * @return mixed Returns an array in which each element is a copy of\n * the corresponding member of the current user-defined\n * function's argument list.\n */", + (const char *)0xffffffff, NULL, NULL, NULL, (const char *)0x10006040, "func_num_args", "", (const char*)0, (const char*)0, diff --git a/hphp/system/function.inc b/hphp/system/function.inc index 8d2677501..f5a9930cf 100644 --- a/hphp/system/function.inc +++ b/hphp/system/function.inc @@ -18,7 +18,7 @@ "get_called_class", T(Variant), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/function.get-called-class.php )\n *\n * Gets the name of the class the static method is called in.\n *\n * @return mixed Returns the class name. Returns FALSE if called from\n * outside a class.\n */", "create_function", T(String), S(0), "args", T(String), NULL, S(0), NULL, S(0), "code", T(String), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/function.create-function.php )\n *\n * Creates an anonymous function from the parameters passed, and returns a\n * unique name for it.\n * Usually these parameters will be passed as single quote delimited\n * strings. The reason for using single quoted strings, is to protect the\n * variable names from parsing, otherwise, if you use double quotes there\n * will be a need to escape the variable names, e.g. \\$avar.\n *\n * @args string The function arguments.\n * @code string The function code.\n *\n * @return string Returns a unique function name as a string, or FALSE\n * on error.\n */", "func_get_arg", T(Variant), S(0), "arg_num", T(Int32), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/function.func-get-arg.php )\n *\n * Gets the specified argument from a user-defined function's argument\n * list.\n *\n * This function may be used in conjunction with func_get_args() and\n * func_num_args() to allow user-defined functions to accept\n * variable-length argument lists.\n *\n * @arg_num int The argument offset. Function arguments are counted\n * starting from zero.\n *\n * @return mixed Returns the specified argument, or FALSE on error.\n */", -"func_get_args", T(Array), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/function.func-get-args.php )\n *\n * Gets an array of the function's argument list.\n *\n * This function may be used in conjunction with func_get_arg() and\n * func_num_args() to allow user-defined functions to accept\n * variable-length argument lists.\n *\n * @return vector Returns an array in which each element is a copy of\n * the corresponding member of the current user-defined\n * function's argument list.\n */", +"func_get_args", T(Variant), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/function.func-get-args.php )\n *\n * Gets an array of the function's argument list.\n *\n * This function may be used in conjunction with func_get_arg() and\n * func_num_args() to allow user-defined functions to accept\n * variable-length argument lists.\n *\n * @return mixed Returns an array in which each element is a copy of\n * the corresponding member of the current user-defined\n * function's argument list.\n */", "func_num_args", T(Int64), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/function.func-num-args.php )\n *\n * Gets the number of arguments passed to the function.\n *\n * This function may be used in conjunction with func_get_arg() and\n * func_get_args() to allow user-defined functions to accept\n * variable-length argument lists.\n *\n * @return int Returns the number of arguments passed into the\n * current user-defined function.\n */", "register_postsend_function", T(Void), S(0), "function", T(Variant), NULL, S(0), NULL, S(0), NULL, S(212992), "/**\n * ( HipHop specific )\n *\n * Registers functions to call after HTTP response is completely sent to\n * browser.\n *\n * @function mixed The callback to register.\n */", "register_shutdown_function", T(Void), S(0), "function", T(Variant), NULL, S(0), NULL, S(0), NULL, S(147456), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.register-shutdown-function.php )\n *\n * Registers the function named by function to be executed when script\n * processing is complete or when exit() is called.\n *\n * Multiple calls to register_shutdown_function() can be made, and each\n * will be called in the same order as they were registered. If you call\n * exit() within one registered shutdown function, processing will stop\n * completely and no other registered shutdown functions will be called.\n *\n * @function mixed The shutdown function to register.\n *\n * The shutdown functions are called as the part of\n * the request so that it's possible to send the output\n * from them. There is currently no way to process the\n * data with output buffering functions in the shutdown\n * function.\n *\n * Shutdown functions are called after closing all\n * opened output buffers thus, for example, its output\n * will not be compressed if zlib.output_compression is\n * enabled.\n *\n * @return mixed No value is returned.\n */", diff --git a/hphp/test/zend/bad/001.php.exp b/hphp/test/zend/bad/001.php.exp deleted file mode 100644 index de30f3991..000000000 --- a/hphp/test/zend/bad/001.php.exp +++ /dev/null @@ -1,13 +0,0 @@ -int(0) -int(1) -HipHop Warning: Missing argument 1 for test2(), called in hphp/test/zend/bad/001.php on line %d -int(0) -int(2) -int(0) -HipHop Warning: Missing argument 2 for test3() in hphp/test/zend/bad/001.php on line %d -int(1) -int(2) -int(1) -HipHop Warning: func_num_args(): Called from the global scope - no function context in hphp/test/zend/bad/001.php on line %d -int(-1) -Done diff --git a/hphp/test/zend/bad/001.php b/hphp/test/zend/good/001.php similarity index 100% rename from hphp/test/zend/bad/001.php rename to hphp/test/zend/good/001.php diff --git a/hphp/test/zend/good/001.php.exp b/hphp/test/zend/good/001.php.exp new file mode 100644 index 000000000..4b918dfbc --- /dev/null +++ b/hphp/test/zend/good/001.php.exp @@ -0,0 +1,13 @@ +int(0) +int(1) +HipHop Warning: test2() expects exactly 1 parameter, 0 given in hphp/test/zend/good/001.php on line 8 +int(0) +int(2) +int(0) +HipHop Warning: test3() expects exactly 2 parameters, 1 given in hphp/test/zend/good/001.php on line 12 +int(1) +int(2) +int(1) +HipHop Warning: func_num_args(): Called from the global scope - no function context in hphp/test/zend/good/001.php on line 31 +int(-1) +Done diff --git a/hphp/test/zend/bad/002.php b/hphp/test/zend/good/002.php similarity index 100% rename from hphp/test/zend/bad/002.php rename to hphp/test/zend/good/002.php diff --git a/hphp/test/zend/bad/002.php.exp b/hphp/test/zend/good/002.php.exp similarity index 57% rename from hphp/test/zend/bad/002.php.exp rename to hphp/test/zend/good/002.php.exp index 89c1c1f1c..fb9a310a8 100644 --- a/hphp/test/zend/bad/002.php.exp +++ b/hphp/test/zend/good/002.php.exp @@ -1,45 +1,45 @@ -HipHop Warning: func_get_arg(): The argument number should be >= 0 in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): The argument number should be >= 0 in hphp/test/zend/good/002.php on line 4 bool(false) -HipHop Warning: func_get_arg(): Argument 0 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 0 not passed to function in hphp/test/zend/good/002.php on line 5 bool(false) -HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/good/002.php on line 6 bool(false) -HipHop Warning: func_get_arg(): The argument number should be >= 0 in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): The argument number should be >= 0 in hphp/test/zend/good/002.php on line 4 bool(false) int(10) -HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/good/002.php on line 6 bool(false) int(1) -HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/good/002.php on line 11 bool(false) -HipHop Warning: Missing argument 1 for test2(), called in hphp/test/zend/bad/002.php on line %d and defined in hphp/test/zend/bad/002.php on line %d -HipHop Warning: func_get_arg(): Argument 0 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: test2() expects exactly 1 parameter, 0 given in hphp/test/zend/good/002.php on line 10 +HipHop Warning: func_get_arg(): Argument 0 not passed to function in hphp/test/zend/good/002.php on line 10 bool(false) -HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/good/002.php on line 11 bool(false) int(1) int(2) -HipHop Warning: func_get_arg(): Argument 2 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 2 not passed to function in hphp/test/zend/good/002.php on line 17 bool(false) -HipHop Warning: func_get_arg(): The argument number should be >= 0 in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): The argument number should be >= 0 in hphp/test/zend/good/002.php on line 4 bool(false) -HipHop Warning: func_get_arg(): Argument 0 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 0 not passed to function in hphp/test/zend/good/002.php on line 5 bool(false) -HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/good/002.php on line 6 bool(false) -HipHop Warning: Missing argument 2 for test3() in hphp/test/zend/bad/002.php on line %d +HipHop Warning: test3() expects exactly 2 parameters, 1 given in hphp/test/zend/good/002.php on line 15 int(1) -HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/good/002.php on line 16 bool(false) -HipHop Warning: func_get_arg(): Argument 2 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 2 not passed to function in hphp/test/zend/good/002.php on line 17 bool(false) int(1) int(2) -HipHop Warning: func_get_arg(): Argument 2 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 2 not passed to function in hphp/test/zend/good/002.php on line 17 bool(false) int(1) -HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Argument 1 not passed to function in hphp/test/zend/good/002.php on line 33 bool(false) -HipHop Warning: func_get_arg(): Called from the global scope - no function context in hphp/test/zend/bad/002.php on line %d +HipHop Warning: func_get_arg(): Called from the global scope - no function context in hphp/test/zend/good/002.php on line 38 bool(false) Done diff --git a/hphp/test/zend/bad/003.php b/hphp/test/zend/good/003.php similarity index 100% rename from hphp/test/zend/bad/003.php rename to hphp/test/zend/good/003.php diff --git a/hphp/test/zend/bad/003.php.exp b/hphp/test/zend/good/003.php.exp similarity index 52% rename from hphp/test/zend/bad/003.php.exp rename to hphp/test/zend/good/003.php.exp index e546da3d3..368bf9803 100644 --- a/hphp/test/zend/bad/003.php.exp +++ b/hphp/test/zend/good/003.php.exp @@ -8,7 +8,7 @@ array(1) { [0]=> int(1) } -HipHop Warning: Missing argument 1 for test2(), called in hphp/test/zend/bad/003.php on line %d and defined in hphp/test/zend/bad/003.php on line %d +HipHop Warning: test2() expects exactly 1 parameter, 0 given in hphp/test/zend/good/003.php on line 8 array(0) { } array(2) { @@ -19,7 +19,7 @@ array(2) { } array(0) { } -HipHop Warning: Missing argument 2 for test3() in hphp/test/zend/bad/003.php on line %d +HipHop Warning: test3() expects exactly 2 parameters, 1 given in hphp/test/zend/good/003.php on line 12 array(1) { [0]=> int(1) @@ -34,6 +34,6 @@ array(1) { [0]=> int(1) } -HipHop Warning: func_get_args(): Called from the global scope - no function context in hphp/test/zend/bad/003.php on line %d +HipHop Warning: func_get_args(): Called from the global scope - no function context in hphp/test/zend/good/003.php on line 32 bool(false) Done diff --git a/hphp/test/zend/good/011.php.exp b/hphp/test/zend/good/011.php.exp index 76e339959..ef6dc4827 100644 --- a/hphp/test/zend/good/011.php.exp +++ b/hphp/test/zend/good/011.php.exp @@ -1,6 +1,6 @@ -HipHop Warning: property_exists() expects exactly 2 parameters, 0 given in hphp/test/zend/bad/011.php on line %d +HipHop Warning: property_exists() expects exactly 2 parameters, 0 given in hphp/test/zend/good/011.php on line 23 NULL -HipHop Warning: property_exists() expects exactly 2 parameters, 1 given in hphp/test/zend/bad/011.php on line %d +HipHop Warning: property_exists() expects exactly 2 parameters, 1 given in hphp/test/zend/good/011.php on line 24 NULL bool(true) bool(true) diff --git a/hphp/tools/import_zend_test.py b/hphp/tools/import_zend_test.py index fb45848b1..f2a2ceacd 100755 --- a/hphp/tools/import_zend_test.py +++ b/hphp/tools/import_zend_test.py @@ -12,8 +12,14 @@ import subprocess import sys bad_tests = ( - 'unset_cv05.php', - 'unset_cv06.php', + '/unset_cv05.php', + '/unset_cv06.php', +) + +use_hhvm_output = ( + '/001.php', + '/002.php', + '/003.php', ) errors = ( @@ -104,6 +110,9 @@ def isOkDiff(original_name): for test in bad_tests: if test in original_name: return False + for test in use_hhvm_output: + if test in original_name: + return True filename = original_name + '.diff' # no diff file or is empty