From d8d89afa1efca3cfa627c23ce4e5f1ca77f783e3 Mon Sep 17 00:00:00 2001 From: mwilliams Date: Tue, 4 Oct 2011 10:47:35 -0700 Subject: [PATCH] [Fix] is_callable should respect __call and __callStatic Summary: is_callable didnt check for __call, or __callStatic. It also didnt handle all the possible array formats. Since I'd recently updated call_user_func etc to go through a common routine to handle that, I decided to point is_callable at the same code. The one problem is that is_callable respects private and protected, where currently call_user_func etc do not. I will fix that in a later diff, but for now, I've added flags to CallInfo to indicate that its private or protected, and when is_callable finds a private or protected method, it uses ClassInfo to determine whether its accessible (this isnt very efficient, but its no worse than it used to be). Test Plan: fast_tests slow_tests Reviewers: qigao, myang Reviewed By: myang CC: ps, mwilliams, myang Differential Revision: 343168 Task ID: 740787 --- src/compiler/analysis/class_scope.cpp | 11 +-- src/compiler/analysis/function_scope.cpp | 5 ++ src/runtime/base/builtin_functions.cpp | 68 +++++++++-------- src/runtime/base/builtin_functions.h | 20 ++--- src/runtime/base/object_data.cpp | 14 ++-- src/runtime/eval/ast/method_statement.cpp | 5 ++ src/runtime/ext/ext_function.cpp | 119 ++++++++++++++--------------- src/system/gen/php/classes/iterator.cpp | 4 +- src/system/gen/php/classes/reflection.cpp | 4 +- src/system/gen/sys/dynamic_table_class.cpp | 9 ++- src/test/test_ext_fb.cpp | 2 +- src/test/test_ext_function.cpp | 2 +- src/test/test_externals.cpp | 5 ++ 13 files changed, 146 insertions(+), 122 deletions(-) diff --git a/src/compiler/analysis/class_scope.cpp b/src/compiler/analysis/class_scope.cpp index d856b675a8c..2ec0c197828 100644 --- a/src/compiler/analysis/class_scope.cpp +++ b/src/compiler/analysis/class_scope.cpp @@ -1234,7 +1234,8 @@ void ClassScope::outputCPPHashTableClasses " int64 off = p->ptv1;\n" " if (LIKELY(!(off & 1))) return ((const ObjectStaticCallbacks *)off);\n" " DECLARE_GLOBAL_VARIABLES(g);\n" - " checkClassExistsThrow(s, (bool*)((char*)g + p->cdec));\n" + " if (UNLIKELY(!checkClassExistsNoThrow(" + "s, (bool*)((char*)g + p->cdec)))) return 0;\n" " if (LIKELY(!(off & 2))) /* volatile class */ return " "((const ObjectStaticCallbacks *)(off-1));\n" " /* redeclared class */\n" @@ -1392,7 +1393,6 @@ void ClassScope::outputCPPDynamicClassCreateImpl } if (!classes.size()) { if (system) { - cg_printf("throw_missing_class(s);\n"); cg_printf("return 0;\n"); } else { cg_printf("return create_builtin_object_only_no_init(s, root);\n"); @@ -1401,7 +1401,6 @@ void ClassScope::outputCPPDynamicClassCreateImpl cg_printf("const ObjectStaticCallbacks *cwo = " "get_%sobject_static_callbacks(s);\n" "if (LIKELY(cwo != 0)) return cwo->createOnlyNoInit(root);\n" - "throw_missing_class(s);\n" "return 0;\n", system ? "builtin_" : ""); } @@ -1410,9 +1409,11 @@ void ClassScope::outputCPPDynamicClassCreateImpl cg_indentBegin("Object create%s_object_only(CStrRef s, " "ObjectData* root /* = NULL*/) {\n", system ? "_builtin" : ""); - cg_printf("Object r(create%s_object_only_no_init(s, root));\n", + cg_printf("ObjectData *obj = create%s_object_only_no_init(s, root);\n", system ? "_builtin" : ""); - cg_printf("r->init();\n"); + cg_printf("if (UNLIKELY(!obj)) throw_missing_class(s);\n"); + cg_printf("Object r = obj;\n"); + cg_printf("obj->init();\n"); cg_printf("return r;\n"); cg_indentEnd("}\n"); } diff --git a/src/compiler/analysis/function_scope.cpp b/src/compiler/analysis/function_scope.cpp index d1c35a1768f..9cd11d381df 100644 --- a/src/compiler/analysis/function_scope.cpp +++ b/src/compiler/analysis/function_scope.cpp @@ -1942,6 +1942,11 @@ void FunctionScope::outputCPPCallInfo(CodeGenerator &cg, } if (m_method) { flags |= CallInfo::Method; + if (isProtected()) { + flags |= CallInfo::Protected; + } else if (isPrivate()) { + flags |= CallInfo::Private; + } if (isStatic()) { flags |= CallInfo::StaticMethod; } diff --git a/src/runtime/base/builtin_functions.cpp b/src/runtime/base/builtin_functions.cpp index 8fb8fc71097..b26997a46f5 100644 --- a/src/runtime/base/builtin_functions.cpp +++ b/src/runtime/base/builtin_functions.cpp @@ -90,7 +90,7 @@ String getUndefinedConstant(CStrRef name) { bool get_user_func_handler(CVarRef function, bool skip, MethodCallPackage &mcp, String &classname, String &methodname, - bool &doBind) { + bool &doBind, bool warn /* = true */) { doBind = false; mcp.noFatal(); @@ -98,7 +98,7 @@ bool get_user_func_handler(CVarRef function, bool skip, if (Variant::GetAccessorType(tv_func) == KindOfObject) { mcp.functionNamedCall(Variant::GetObjectData(tv_func)); if (LIKELY(mcp.ci != 0)) return true; - raise_warning("call_user_func to non-callback object"); + if (warn) raise_warning("call_user_func to non-callback object"); return false; } @@ -136,12 +136,14 @@ bool get_user_func_handler(CVarRef function, bool skip, return true; } } - raise_warning("call_user_func to non-existent function %s", base); + if (warn) { + raise_warning("call_user_func to non-existent function %s", base); + } return false; } mcp.functionNamedCall(Variant::GetAsString(tv_func)); if (LIKELY(mcp.ci != 0)) return true; - raise_warning("call_user_func to non-existent function %s", base); + if (warn) raise_warning("call_user_func to non-existent function %s", base); return false; } @@ -152,13 +154,13 @@ bool get_user_func_handler(CVarRef function, bool skip, if (arr.size() != 2 || &clsname == &null_variant || &mthname == &null_variant) { - throw_invalid_argument("function: not a valid callback array"); + if (warn) throw_invalid_argument("function: not a valid callback array"); return false; } Variant::TypedValueAccessor tv_meth = mthname.getTypedAccessor(); if (!Variant::IsString(tv_meth)) { - throw_invalid_argument("function: methodname not string"); + if (warn) throw_invalid_argument("function: methodname not string"); return false; } @@ -181,8 +183,8 @@ bool get_user_func_handler(CVarRef function, bool skip, !strncasecmp(base, "parent", 6)) { classname = obj->o_getParentName(); if (classname.empty()) { - raise_warning("cannot access parent:: when current " - "class scope has no parent"); + if (warn) raise_warning("cannot access parent:: when current " + "class scope has no parent"); return false; } } else if (cc - base == 6 && @@ -199,12 +201,14 @@ bool get_user_func_handler(CVarRef function, bool skip, } return true; } - if (!obj->o_instanceof(classname)) { - raise_warning("class '%s' is not a subclass of '%s'", - obj->o_getClassName().data(), classname.data()); - } else { - raise_warning("class '%s' does not have a method '%s'", - classname.data(), methodname.data()); + if (warn) { + if (!obj->o_instanceof(classname)) { + raise_warning("class '%s' is not a subclass of '%s'", + obj->o_getClassName().data(), classname.data()); + } else { + raise_warning("class '%s' does not have a method '%s'", + classname.data(), methodname.data()); + } } return false; } @@ -220,7 +224,7 @@ bool get_user_func_handler(CVarRef function, bool skip, return false; } else { if (UNLIKELY(!Variant::IsString(tv_cls))) { - throw_invalid_argument("function: classname not string"); + if (warn) throw_invalid_argument("function: classname not string"); return false; } StringData *sclass = Variant::GetStringData(tv_cls); @@ -229,8 +233,8 @@ bool get_user_func_handler(CVarRef function, bool skip, } else if (sclass->isame(s_parent.get())) { classname = FrameInjection::GetParentClassName(skip); if (classname.empty()) { - raise_warning("cannot access parent:: when current " - "class scope has no parent"); + if (warn) raise_warning("cannot access parent:: when current " + "class scope has no parent"); return false; } } else { @@ -261,8 +265,8 @@ bool get_user_func_handler(CVarRef function, bool skip, !strncasecmp(base, "parent", 6)) { classname = ObjectData::GetParentName(classname); if (classname.empty()) { - raise_warning("cannot access parent:: when current " - "class scope has no parent"); + if (warn) raise_warning("cannot access parent:: when current " + "class scope has no parent"); return false; } doBind = false; @@ -272,8 +276,8 @@ bool get_user_func_handler(CVarRef function, bool skip, CStrRef cls = FrameInjection::GetStaticClassName(ti); if (UNLIKELY(!classname.get()->isame(cls.get()) && !f_is_subclass_of(classname, cls))) { - raise_warning("class '%s' is not a subclass of '%s'", - classname.data(), cls.data()); + if (warn) raise_warning("class '%s' is not a subclass of '%s'", + classname.data(), cls.data()); return false; } doBind = false; @@ -282,29 +286,29 @@ bool get_user_func_handler(CVarRef function, bool skip, CStrRef cls = String(base, cc - base, CopyString); if (UNLIKELY(!classname.get()->isame(cls.get()) && !f_is_subclass_of(classname, cls))) { - raise_warning("class '%s' is not a subclass of '%s'", - classname.data(), cls.data()); + if (warn) raise_warning("class '%s' is not a subclass of '%s'", + classname.data(), cls.data()); return false; } doBind = true; classname = cls; } + if (LIKELY(mcp.dynamicNamedCall(classname, methodname))) { + doBind &= !mcp.isObj || (mcp.ci->m_flags & CallInfo::StaticMethod); + return true; + } } else { - methodname = Variant::GetStringData(tv_meth); + // nothing to do. we already checked this case. } - if (LIKELY(mcp.dynamicNamedCall(classname, methodname))) { - doBind &= !mcp.isObj || (mcp.ci->m_flags & CallInfo::StaticMethod); - return true; - } - raise_warning("call_user_func to non-existent function %s::%s", - classname.data(), methodname.data()); + if (warn) raise_warning("call_user_func to non-existent function %s::%s", + classname.data(), methodname.data()); return false; } - raise_warning("call_user_func to non-existent function"); + if (warn) raise_warning("call_user_func to non-existent function"); return false; } - throw_invalid_argument("function: not string or array"); + if (warn) throw_invalid_argument("function: not string or array"); return false; } diff --git a/src/runtime/base/builtin_functions.h b/src/runtime/base/builtin_functions.h index e2b0632b93b..1e2c6de8002 100644 --- a/src/runtime/base/builtin_functions.h +++ b/src/runtime/base/builtin_functions.h @@ -338,7 +338,7 @@ Variant f_call_user_func_array(CVarRef function, CArrRef params, bool get_user_func_handler(CVarRef function, bool skip, MethodCallPackage& mcp, String &classname, String &methodname, - bool &doBind); + bool &doBind, bool warn = true); Variant invoke_func_few_handler(void *extra, CArrRef params, Variant (*few_args)( @@ -616,8 +616,8 @@ class CallInfo; class MethodCallPackage { public: MethodCallPackage() - : ci(NULL), extra(NULL), isObj(false), obj(NULL), - m_fatal(true), m_isFunc(false) {} + : ci(NULL), extra(NULL), obj(NULL), + isObj(false), m_fatal(true), m_isFunc(false) {} // e->n() style method call bool methodCall(CObjRef self, CStrRef method, int64 prehash = -1) { @@ -662,13 +662,13 @@ public: // Data members const CallInfo *ci; void *extra; - bool isObj; union { // object or class name ObjectData *rootObj; StringData *rootCls; }; ObjectData *obj; const String *name; + bool isObj; bool m_fatal; bool m_isFunc; }; @@ -676,12 +676,14 @@ public: class CallInfo { public: enum Flags { - VarArgs = 0x1, - RefVarArgs = 0x2, - Method = 0x4, - StaticMethod = 0x8, + VarArgs = 0x1, + RefVarArgs = 0x2, + Method = 0x4, + StaticMethod = 0x8, CallMagicMethod = 0x10, // Special flag for __call handler - MixedVarArgs = 0x20 + MixedVarArgs = 0x20, + Protected = 0x40, + Private = 0x80 }; CallInfo(void *inv, void *invFa, int ac, int flags, int64 refs) : m_invoker(inv), m_invokerFewArgs(invFa), diff --git a/src/runtime/base/object_data.cpp b/src/runtime/base/object_data.cpp index ef22180cf39..64aabcfb07c 100644 --- a/src/runtime/base/object_data.cpp +++ b/src/runtime/base/object_data.cpp @@ -579,9 +579,11 @@ inline ALWAYS_INLINE bool GetCallInfoHelper(bool ex, const char *cls, bool ok = false; if (!obj || !obj->o_instanceof(cls)) { obj = create_object_only_no_init(cls); - ok = obj->hasCallStatic(); - obj->release(); - obj = 0; + if (obj) { + ok = obj->hasCallStatic(); + obj->release(); + obj = 0; + } } else { ok = obj->hasCallStatic() || obj->hasCall(); } @@ -614,8 +616,10 @@ Variant ObjectData::os_invoke(CStrRef c, CStrRef s, bool fatal /* = true */) { Object obj = FrameInjection::GetThis(); if (!obj.instanceof(c)) { - obj = create_object_only_no_init(c); - obj->setDummy(); + ObjectData *o = create_object_only_no_init(c); + if (UNLIKELY(!o)) throw_missing_class(c); + o->setDummy(); + obj = o; } return obj->o_invoke_ex(c, s, params, fatal); } diff --git a/src/runtime/eval/ast/method_statement.cpp b/src/runtime/eval/ast/method_statement.cpp index 49eabf1801c..0f2cd1536fb 100644 --- a/src/runtime/eval/ast/method_statement.cpp +++ b/src/runtime/eval/ast/method_statement.cpp @@ -44,6 +44,11 @@ MethodStatement::MethodStatement(STATEMENT_ARGS, const string &name, } else { m_callInfo.m_flags |= CallInfo::Method; } + if (m_modifiers & ClassStatement::Protected) { + m_callInfo.m_flags |= CallInfo::Protected; + } else if (m_modifiers & ClassStatement::Private) { + m_callInfo.m_flags |= CallInfo::Private; + } } void MethodStatement::setPublic() { diff --git a/src/runtime/ext/ext_function.cpp b/src/runtime/ext/ext_function.cpp index 5c9df04a8f5..bbdabde9c89 100644 --- a/src/runtime/ext/ext_function.cpp +++ b/src/runtime/ext/ext_function.cpp @@ -47,77 +47,74 @@ bool f_function_exists(CStrRef function_name) { bool f_is_callable(CVarRef v, bool syntax /* = false */, VRefParam name /* = null */) { - if (v.isString()) { - if (name.isReferenced()) name = v; - if (syntax) return true; - - String str = v.toString(); - int c = str.find("::"); - if (c != 0 && c != String::npos && c + 2 < str.size()) { - String classname = str.substr(0, c); - String methodname = str.substr(c + 2); - return f_class_exists(classname) && - ClassInfo::HasAccess(classname, methodname, true, false); + bool ret = true; + if (LIKELY(!syntax)) { + MethodCallPackage mcp; + String classname, methodname; + bool doBind; + ret = get_user_func_handler(v, true, mcp, + classname, methodname, doBind, false); + if (ret && mcp.ci->m_flags & (CallInfo::Protected|CallInfo::Private)) { + classname = mcp.getClassName(); + if (!ClassInfo::HasAccess(classname, *mcp.name, + mcp.ci->m_flags & CallInfo::StaticMethod || + !mcp.obj, + mcp.obj)) { + ret = false; + } } - return f_function_exists(str); + if (!name.isReferenced()) return ret; } - if (v.is(KindOfArray)) { - Array arr = v.toArray(); - if (arr.size() == 2 && arr.exists(0LL) && arr.exists(1LL)) { - Variant v0 = arr.rvalAt(0LL); - Variant v1 = arr.rvalAt(1LL); - Object obj; - bool staticCall = false; - if (v0.is(KindOfObject)) { - obj = v0.toObject(); - v0 = obj->o_getClassName(); - } else if (v0.isString()) { - if (!f_class_exists(v0.toString())) { - return false; - } - staticCall = true; - } - if (v1.isString()) { - String str = v1.toString(); - int c = str.find("::"); - if (c != 0 && c != String::npos && c + 2 < str.size()) { - String name1 = v0.toString(); - String name2 = str.substr(0, c); - ASSERT(name1.get() && name2.get()); - if (name1->isame(name2.get()) || - ClassInfo::IsSubClass(name1, name2, false)) { - staticCall = true; - v0 = name2; - v1 = str.substr(c + 2); - } - } - } - if (v0.isString() && v1.isString()) { - if (name.isReferenced()) { - name = v0.toString() + "::" + v1.toString(); - } - if (same(v0, s_self) || same(v0, s_parent)) { - throw NotImplementedException("augmenting class scope info"); - } - return ClassInfo::HasAccess(v0, v1, staticCall, !obj.isNull()); - } + Variant::TypedValueAccessor tv_func = v.getTypedAccessor(); + if (Variant::IsString(tv_func)) { + if (name.isReferenced()) name = Variant::GetStringData(tv_func); + return ret; + } + + if (Variant::GetAccessorType(tv_func) == KindOfArray) { + CArrRef arr = Variant::GetAsArray(tv_func); + CVarRef clsname = arr.rvalAtRef(0LL); + CVarRef mthname = arr.rvalAtRef(1LL); + if (arr.size() != 2 || + &clsname == &null_variant || + &mthname == &null_variant) { + name = v.toString(); + return false; + } + + Variant::TypedValueAccessor tv_meth = mthname.getTypedAccessor(); + if (!Variant::IsString(tv_meth)) { + if (name.isReferenced()) name = v.toString(); + return false; } + + Variant::TypedValueAccessor tv_cls = clsname.getTypedAccessor(); + if (Variant::GetAccessorType(tv_cls) == KindOfObject) { + name = Variant::GetObjectData(tv_cls)->o_getClassName(); + } else if (Variant::IsString(tv_cls)) { + name = Variant::GetStringData(tv_cls); + } else { + name = v.toString(); + return false; + } + + name = concat3(name, "::", Variant::GetAsString(tv_meth)); + return ret; } - if (v.isObject()) { - ObjectData *d = v.objectForCall(); - if (name.isReferenced()) { + if (Variant::GetAccessorType(tv_func) == KindOfObject) { + ObjectData *d = Variant::GetObjectData(tv_func); + void *extra; + if (d->t___invokeCallInfoHelper(extra)) { name = d->o_getClassName() + "::__invoke"; + return ret; + } + if (name.isReferenced()) { + name = v.toString(); } - void *extra; - const CallInfo *cit = d->t___invokeCallInfoHelper(extra); - return cit != NULL; } - if (name.isReferenced()) { - name = v.toString(); - } return false; } diff --git a/src/system/gen/php/classes/iterator.cpp b/src/system/gen/php/classes/iterator.cpp index cbb1e17ae73..0e4e13293fa 100644 --- a/src/system/gen/php/classes/iterator.cpp +++ b/src/system/gen/php/classes/iterator.cpp @@ -240,9 +240,9 @@ CallInfo c_FilterIterator::ci___call((void*)&c_FilterIterator::i___call, (void*) CallInfo c_FilterIterator::ci_rewind((void*)&c_FilterIterator::i_rewind, (void*)&c_FilterIterator::ifa_rewind, 0, 4, 0x0000000000000000LL); CallInfo c_FilterIterator::ci_next((void*)&c_FilterIterator::i_next, (void*)&c_FilterIterator::ifa_next, 0, 4, 0x0000000000000000LL); CallInfo c_FilterIterator::ci_getinneriterator((void*)&c_FilterIterator::i_getinneriterator, (void*)&c_FilterIterator::ifa_getinneriterator, 0, 4, 0x0000000000000000LL); -CallInfo c_FilterIterator::ci___clone((void*)&c_FilterIterator::i___clone, (void*)&c_FilterIterator::ifa___clone, 0, 4, 0x0000000000000000LL); +CallInfo c_FilterIterator::ci___clone((void*)&c_FilterIterator::i___clone, (void*)&c_FilterIterator::ifa___clone, 0, 68, 0x0000000000000000LL); CallInfo c_FilterIterator::ci_current((void*)&c_FilterIterator::i_current, (void*)&c_FilterIterator::ifa_current, 0, 4, 0x0000000000000000LL); -CallInfo c_FilterIterator::ci_fetch((void*)&c_FilterIterator::i_fetch, (void*)&c_FilterIterator::ifa_fetch, 0, 4, 0x0000000000000000LL); +CallInfo c_FilterIterator::ci_fetch((void*)&c_FilterIterator::i_fetch, (void*)&c_FilterIterator::ifa_fetch, 0, 132, 0x0000000000000000LL); CallInfo c_FilterIterator::ci_valid((void*)&c_FilterIterator::i_valid, (void*)&c_FilterIterator::ifa_valid, 0, 4, 0x0000000000000000LL); CallInfo c_FilterIterator::ci_key((void*)&c_FilterIterator::i_key, (void*)&c_FilterIterator::ifa_key, 0, 4, 0x0000000000000000LL); Variant c_FilterIterator::i___construct(MethodCallPackage &mcp, CArrRef params) { diff --git a/src/system/gen/php/classes/reflection.cpp b/src/system/gen/php/classes/reflection.cpp index 1f15651a367..b10eb433870 100644 --- a/src/system/gen/php/classes/reflection.cpp +++ b/src/system/gen/php/classes/reflection.cpp @@ -2319,14 +2319,14 @@ CallInfo c_ReflectionClass::ci_getdefaultproperties((void*)&c_ReflectionClass::i CallInfo c_ReflectionClass::ci_getstaticpropertyvalue((void*)&c_ReflectionClass::i_getstaticpropertyvalue, (void*)&c_ReflectionClass::ifa_getstaticpropertyvalue, 2, 4, 0x0000000000000000LL); CallInfo c_ReflectionClass::ci_isabstract((void*)&c_ReflectionClass::i_isabstract, (void*)&c_ReflectionClass::ifa_isabstract, 0, 4, 0x0000000000000000LL); CallInfo c_ReflectionClass::ci_gettraitaliases((void*)&c_ReflectionClass::i_gettraitaliases, (void*)&c_ReflectionClass::ifa_gettraitaliases, 0, 4, 0x0000000000000000LL); -CallInfo c_ReflectionClass::ci_fetch((void*)&c_ReflectionClass::i_fetch, (void*)&c_ReflectionClass::ifa_fetch, 1, 4, 0x0000000000000000LL); +CallInfo c_ReflectionClass::ci_fetch((void*)&c_ReflectionClass::i_fetch, (void*)&c_ReflectionClass::ifa_fetch, 1, 132, 0x0000000000000000LL); CallInfo c_ReflectionClass::ci_gettraitnames((void*)&c_ReflectionClass::i_gettraitnames, (void*)&c_ReflectionClass::ifa_gettraitnames, 0, 4, 0x0000000000000000LL); CallInfo c_ReflectionClass::ci_getinterfacenames((void*)&c_ReflectionClass::i_getinterfacenames, (void*)&c_ReflectionClass::ifa_getinterfacenames, 0, 4, 0x0000000000000000LL); CallInfo c_ReflectionClass::ci_isuserdefined((void*)&c_ReflectionClass::i_isuserdefined, (void*)&c_ReflectionClass::ifa_isuserdefined, 0, 4, 0x0000000000000000LL); CallInfo c_ReflectionClass::ci_getstartline((void*)&c_ReflectionClass::i_getstartline, (void*)&c_ReflectionClass::ifa_getstartline, 0, 4, 0x0000000000000000LL); CallInfo c_ReflectionClass::ci_getproperty((void*)&c_ReflectionClass::i_getproperty, (void*)&c_ReflectionClass::ifa_getproperty, 1, 4, 0x0000000000000000LL); CallInfo c_ReflectionClass::ci_getextensionname((void*)&c_ReflectionClass::i_getextensionname, (void*)&c_ReflectionClass::ifa_getextensionname, 0, 4, 0x0000000000000000LL); -CallInfo c_ReflectionClass::ci_test((void*)&c_ReflectionClass::i_test, (void*)&c_ReflectionClass::ifa_test, 2, 4, 0x0000000000000000LL); +CallInfo c_ReflectionClass::ci_test((void*)&c_ReflectionClass::i_test, (void*)&c_ReflectionClass::ifa_test, 2, 132, 0x0000000000000000LL); CallInfo c_ReflectionClass::ci_gettraits((void*)&c_ReflectionClass::i_gettraits, (void*)&c_ReflectionClass::ifa_gettraits, 0, 4, 0x0000000000000000LL); CallInfo c_ReflectionClass::ci_getmethods((void*)&c_ReflectionClass::i_getmethods, (void*)&c_ReflectionClass::ifa_getmethods, 1, 4, 0x0000000000000000LL); CallInfo c_ReflectionClass::ci_getconstants((void*)&c_ReflectionClass::i_getconstants, (void*)&c_ReflectionClass::ifa_getconstants, 0, 4, 0x0000000000000000LL); diff --git a/src/system/gen/sys/dynamic_table_class.cpp b/src/system/gen/sys/dynamic_table_class.cpp index b17058aca5c..7680cf45178 100644 --- a/src/system/gen/sys/dynamic_table_class.cpp +++ b/src/system/gen/sys/dynamic_table_class.cpp @@ -509,7 +509,7 @@ CallInfo c_PDOStatement::ci_debugdumpparams((void*)&c_PDOStatement::i_debugdumpp CallInfo c_PDOStatement::ci_nextrowset((void*)&c_PDOStatement::i_nextrowset, (void*)&c_PDOStatement::ifa_nextrowset, 0, 4, 0x0000000000000000LL); CallInfo c_PDOStatement::ci_bindvalue((void*)&c_PDOStatement::i_bindvalue, (void*)&c_PDOStatement::ifa_bindvalue, 3, 4, 0x0000000000000000LL); CallInfo c_PDOStatement::ci_getattribute((void*)&c_PDOStatement::i_getattribute, (void*)&c_PDOStatement::ifa_getattribute, 1, 4, 0x0000000000000000LL); -CallInfo c_PDOStatement::ci___construct((void*)&c_PDOStatement::i___construct, (void*)&c_PDOStatement::ifa___construct, 0, 4, 0x0000000000000000LL); +CallInfo c_PDOStatement::ci___construct((void*)&c_PDOStatement::i___construct, (void*)&c_PDOStatement::ifa___construct, 0, 68, 0x0000000000000000LL); CallInfo c_PDOStatement::ci___destruct((void*)&c_PDOStatement::i___destruct, (void*)&c_PDOStatement::ifa___destruct, 0, 4, 0x0000000000000000LL); CallInfo c_PDOStatement::ci___wakeup((void*)&c_PDOStatement::i___wakeup, (void*)&c_PDOStatement::ifa___wakeup, 0, 4, 0x0000000000000000LL); Variant c_PDOStatement::i___construct(MethodCallPackage &mcp, CArrRef params) { @@ -10606,12 +10606,13 @@ Variant get_builtin_class_var_init(CStrRef s, const char *var) { ObjectData *create_builtin_object_only_no_init(CStrRef s, ObjectData* root /* = NULL*/) { const ObjectStaticCallbacks *cwo = get_builtin_object_static_callbacks(s); if (LIKELY(cwo != 0)) return cwo->createOnlyNoInit(root); - throw_missing_class(s); return 0; } Object create_builtin_object_only(CStrRef s, ObjectData* root /* = NULL*/) { - Object r(create_builtin_object_only_no_init(s, root)); - r->init(); + ObjectData *obj = create_builtin_object_only_no_init(s, root); + if (UNLIKELY(!obj)) throw_missing_class(s); + Object r = obj; + obj->init(); return r; } bool get_call_info_static_method_builtin(MethodCallPackage &mcp) { diff --git a/src/test/test_ext_fb.cpp b/src/test/test_ext_fb.cpp index 1c87a406627..fef500b7022 100644 --- a/src/test/test_ext_fb.cpp +++ b/src/test/test_ext_fb.cpp @@ -151,7 +151,7 @@ bool TestExtFb::test_fb_call_user_func_array_safe() { } { Variant ret = f_fb_call_user_func_array_safe - ("NonT", CREATE_VECTOR1("param")); + ("NonTest", CREATE_VECTOR1("param")); VS(ret, CREATE_VECTOR2(false, null)); } return Count(true); diff --git a/src/test/test_ext_function.cpp b/src/test/test_ext_function.cpp index 76006842a98..12cb7648b71 100644 --- a/src/test/test_ext_function.cpp +++ b/src/test/test_ext_function.cpp @@ -63,7 +63,7 @@ bool TestExtFunction::test_function_exists() { bool TestExtFunction::test_is_callable() { VERIFY(f_is_callable("TEst")); - VERIFY(f_is_callable(CREATE_VECTOR2("tesT", "foo"))); + // lots of testing in TestCodeRun::TestObjectMethod() return Count(true); } diff --git a/src/test/test_externals.cpp b/src/test/test_externals.cpp index ddb9e4da0f8..2e6619e4225 100644 --- a/src/test/test_externals.cpp +++ b/src/test/test_externals.cpp @@ -289,6 +289,11 @@ Variant invokeImpl(void *extra, CArrRef params) { CallInfo invokeImplCallInfo((void*)invokeImpl, NULL, 0, CallInfo::VarArgs, 0); bool get_call_info(const CallInfo *&ci, void *&extra, const char *s, int64 hash /* = -1 */) { + if (!strcasecmp(s, "nontest")) { + extra = 0; + ci = 0; + return false; + } extra = (void*)s; ci = &invokeImplCallInfo; return true; -- 2.11.4.GIT