/* +----------------------------------------------------------------------+ | HipHop for PHP | +----------------------------------------------------------------------+ | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) | | Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) | +----------------------------------------------------------------------+ | This source file is subject to version 2.00 of the Zend license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.zend.com/license/2_00.txt. | | If you did not receive a copy of the Zend license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@zend.com so we can mail you a copy immediately. | +----------------------------------------------------------------------+ */ #include "hphp/runtime/base/intercept.h" #include "hphp/runtime/base/request_local.h" #include "hphp/runtime/base/array_init.h" #include "hphp/runtime/base/array_iterator.h" #include "hphp/runtime/base/type_conversions.h" #include "hphp/runtime/base/builtin_functions.h" #include "hphp/runtime/vm/jit/target-cache.h" #include "hphp/runtime/vm/unit.h" #include "hphp/runtime/vm/event_hook.h" #include "hphp/util/parser/parser.h" #include "hphp/util/lock.h" #include "hphp/runtime/base/file_repository.h" #include "hphp/util/trace.h" using namespace HPHP::Trace; /////////////////////////////////////////////////////////////////////////////// namespace HPHP { TRACE_SET_MOD(intercept); class InterceptRequestData : public RequestEventHandler { public: InterceptRequestData() : m_use_allowed_functions(false) { } void clear() { *s_hasRenamedFunction = false; m_use_allowed_functions = false; m_allowed_functions.clear(); m_renamed_functions.clear(); m_global_handler.reset(); m_intercept_handlers.clear(); } virtual void requestInit() { clear(); } virtual void requestShutdown() { clear(); } public: bool m_use_allowed_functions; StringISet m_allowed_functions; StringIMap m_renamed_functions; Variant m_global_handler; StringIMap m_intercept_handlers; }; IMPLEMENT_STATIC_REQUEST_LOCAL(InterceptRequestData, s_intercept_data); IMPLEMENT_THREAD_LOCAL_NO_CHECK(bool, s_hasRenamedFunction); static Mutex s_mutex; typedef StringIMap > RegisteredFlagsMap; static RegisteredFlagsMap s_registered_flags; /////////////////////////////////////////////////////////////////////////////// static void flag_maybe_interrupted(vector &flags) { for (int i = flags.size() - 1; i >= 0; i--) { *flags[i] = 1; } } bool register_intercept(CStrRef name, CVarRef callback, CVarRef data) { StringIMap &handlers = s_intercept_data->m_intercept_handlers; if (!callback.toBoolean()) { if (name.empty()) { s_intercept_data->m_global_handler.reset(); handlers.clear(); } else { handlers.erase(name); } return true; } EventHook::EnableIntercept(); Array handler = CREATE_VECTOR2(callback, data); if (name.empty()) { s_intercept_data->m_global_handler = handler; handlers.clear(); } else { handlers[name] = handler; } Lock lock(s_mutex); if (name.empty()) { for (RegisteredFlagsMap::iterator iter = s_registered_flags.begin(); iter != s_registered_flags.end(); ++iter) { flag_maybe_interrupted(iter->second); } } else { RegisteredFlagsMap::iterator iter = s_registered_flags.find(name); if (iter != s_registered_flags.end()) { flag_maybe_interrupted(iter->second); } } return true; } Variant *get_enabled_intercept_handler(CStrRef name) { Variant *handler = nullptr; StringIMap &handlers = s_intercept_data->m_intercept_handlers; StringIMap::iterator iter = handlers.find(name); if (iter != handlers.end()) { handler = &iter->second; } else { handler = &s_intercept_data->m_global_handler; if (handler->isNull()) { return nullptr; } } return handler; } Variant *get_intercept_handler(CStrRef name, char* flag) { TRACE(1, "get_intercept_handler %s flag is %d\n", name.get()->data(), (int)*flag); if (*flag == -1) { Lock lock(s_mutex); if (*flag == -1) { StringData *sd = name.get(); if (!sd->isStatic()) { sd = StringData::GetStaticString(sd); } s_registered_flags[StrNR(sd)].push_back(flag); *flag = 0; } } Variant *handler = get_enabled_intercept_handler(name); if (handler == nullptr) { return nullptr; } *flag = 1; return handler; } void unregister_intercept_flag(CStrRef name, char *flag) { Lock lock(s_mutex); RegisteredFlagsMap::iterator iter = s_registered_flags.find(name); if (iter != s_registered_flags.end()) { vector &flags = iter->second; for (int i = flags.size(); i--; ) { if (flag == flags[i]) { flags.erase(flags.begin() + i); break; } } } } /////////////////////////////////////////////////////////////////////////////// // fb_rename_function() void check_renamed_functions(CArrRef names) { g_vmContext->addRenameableFunctions(names.get()); } bool check_renamed_function(CStrRef name) { return g_vmContext->isFunctionRenameable(name.get()); } void rename_function(CStrRef old_name, CStrRef new_name) { g_vmContext->renameFunction(old_name.get(), new_name.get()); } String get_renamed_function(CStrRef name) { HPHP::Func* f = HPHP::Unit::lookupFunc(name.get()); if (f) { return f->nameRef(); } return name; } /////////////////////////////////////////////////////////////////////////////// }