6a93844442
The unserialization of random objects may be dangerous because the destructor of the object will be called when the unserialized objects are out of scope. However, the person who wrote the class may not be aware of the danger of unserialization. Therefore, we would like to require every users of the unserialize() to provide a whitelist of the class names that are authorized to be unserialized so that we can make sure the object is safe to be unserialized. Add a parameter 'class_whitelist' to unserialize() function to determine whether to raise warnings for unsafe unserialization. If the class to be unserialized is not an instance of Serilizable or not in the whitelist, warnings will be raised. For the detailed reason why we need this, please see http://fburl.com/SafeSerializable for more information. Add a parameter 'all_classes_enabled' to allow those hphp functions that need to unserialize any class. For example, fb_call_user_func_async() will need to serialize and nserialize the given parameters.
511 linhas
13 KiB
C++
511 linhas
13 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include <sstream>
|
|
#include <cmath>
|
|
#include <limits.h>
|
|
#include <compiler/expression/scalar_expression.h>
|
|
#include <util/parser/hphp.tab.hpp>
|
|
#include <util/util.h>
|
|
#include <compiler/analysis/code_error.h>
|
|
#include <compiler/analysis/block_scope.h>
|
|
#include <compiler/analysis/variable_table.h>
|
|
#include <compiler/analysis/constant_table.h>
|
|
#include <compiler/statement/statement_list.h>
|
|
#include <compiler/analysis/function_scope.h>
|
|
#include <compiler/analysis/class_scope.h>
|
|
#include <compiler/parser/parser.h>
|
|
#include <util/hash.h>
|
|
#include <runtime/base/string_data.h>
|
|
#include <runtime/base/type_conversions.h>
|
|
#include <runtime/base/builtin_functions.h>
|
|
#include <runtime/ext/ext_variable.h>
|
|
#include <compiler/analysis/file_scope.h>
|
|
|
|
using namespace HPHP;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// constructors/destructors
|
|
|
|
ScalarExpression::ScalarExpression
|
|
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
|
int type, const std::string &value, bool quoted /* = false */)
|
|
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ScalarExpression)),
|
|
m_type(type), m_value(value), m_originalValue(value), m_quoted(quoted) {
|
|
}
|
|
|
|
ScalarExpression::ScalarExpression
|
|
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
|
int type, const std::string &value, const std::string &translated,
|
|
bool quoted /* false */)
|
|
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ScalarExpression)),
|
|
m_type(type), m_value(value), m_originalValue(value),
|
|
m_translated(translated) {
|
|
}
|
|
|
|
ScalarExpression::ScalarExpression
|
|
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
|
CVarRef value, bool quoted /* = true */)
|
|
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ScalarExpression)),
|
|
m_quoted(quoted) {
|
|
if (!value.isNull()) {
|
|
String serialized = f_serialize(value);
|
|
m_serializedValue = string(serialized.data(), serialized.size());
|
|
if (value.isDouble()) {
|
|
m_dval = value.toDouble();
|
|
}
|
|
}
|
|
switch (value.getType()) {
|
|
case KindOfStaticString:
|
|
case KindOfString:
|
|
m_type = T_STRING;
|
|
break;
|
|
case KindOfInt64:
|
|
m_type = T_LNUMBER;
|
|
break;
|
|
case KindOfDouble:
|
|
m_type = T_DNUMBER;
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
CStrRef s = value.toString();
|
|
m_value = string(s->data(), s->size());
|
|
if (m_type == T_DNUMBER && m_value.find_first_of(".eE", 0) == string::npos) {
|
|
m_value += ".";
|
|
}
|
|
m_originalValue = m_value;
|
|
}
|
|
|
|
ExpressionPtr ScalarExpression::clone() {
|
|
ScalarExpressionPtr exp(new ScalarExpression(*this));
|
|
Expression::deepCopy(exp);
|
|
return exp;
|
|
}
|
|
|
|
void ScalarExpression::appendEncapString(const std::string &value) {
|
|
m_value += value;
|
|
}
|
|
|
|
void ScalarExpression::toLower(bool funcCall /* = false */) {
|
|
assert(funcCall || !m_quoted);
|
|
m_value = Util::toLower(m_value);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// static analysis functions
|
|
|
|
bool ScalarExpression::needsTranslation() const {
|
|
switch (m_type) {
|
|
case T_LINE:
|
|
case T_NS_C:
|
|
case T_CLASS_C:
|
|
case T_METHOD_C:
|
|
case T_FUNC_C:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void ScalarExpression::analyzeProgram(AnalysisResultPtr ar) {
|
|
if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
|
|
string id = Util::toLower(getIdentifier());
|
|
|
|
switch (m_type) {
|
|
case T_LINE:
|
|
if (getLocation()) {
|
|
m_translated = lexical_cast<string>(getLocation()->line1);
|
|
} else {
|
|
m_translated = "0";
|
|
}
|
|
break;
|
|
case T_NS_C:
|
|
m_translated = m_value;
|
|
break;
|
|
// case T_TRAIT_C: Note: T_TRAIT_C is translated at parse time
|
|
case T_CLASS_C:
|
|
case T_METHOD_C: {
|
|
if (!m_translated.empty()) break;
|
|
|
|
BlockScopeRawPtr b = getScope();
|
|
while (b && b->is(BlockScope::FunctionScope)) {
|
|
b = b->getOuterScope();
|
|
}
|
|
m_translated.clear();
|
|
if (b && b->is(BlockScope::ClassScope)) {
|
|
ClassScopePtr clsScope = dynamic_pointer_cast<ClassScope>(b);
|
|
if (!clsScope->isTrait()) {
|
|
m_translated = clsScope->getOriginalName();
|
|
}
|
|
}
|
|
if (m_type == T_METHOD_C) {
|
|
if (FunctionScopePtr func = getFunctionScope()) {
|
|
if (b && b->is(BlockScope::ClassScope)) {
|
|
m_translated += "::";
|
|
}
|
|
m_translated += func->getOriginalName();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case T_FUNC_C:
|
|
if (getFunctionScope()) {
|
|
m_translated = getFunctionScope()->getOriginalName();
|
|
if (m_translated[0] == '0') {
|
|
m_translated = "{closure}";
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
unsigned ScalarExpression::getCanonHash() const {
|
|
int64_t val = getHash();
|
|
if (val == -1) {
|
|
val = hash_string(m_value.c_str(), m_value.size());
|
|
}
|
|
return unsigned(val) ^ unsigned(val >> 32);
|
|
}
|
|
|
|
bool ScalarExpression::canonCompare(ExpressionPtr e) const {
|
|
if (!Expression::canonCompare(e)) return false;
|
|
ScalarExpressionPtr s =
|
|
static_pointer_cast<ScalarExpression>(e);
|
|
|
|
return
|
|
m_value == s->m_value &&
|
|
m_type == s->m_type &&
|
|
m_quoted == s->m_quoted;
|
|
}
|
|
|
|
ExpressionPtr ScalarExpression::postOptimize(AnalysisResultConstPtr ar) {
|
|
if (!m_expectedType || Type::SameType(m_actualType, m_expectedType)) {
|
|
return ExpressionPtr();
|
|
}
|
|
|
|
Variant orig = getVariant();
|
|
Variant cast;
|
|
bool match = false;
|
|
|
|
switch (m_expectedType->getKindOf()) {
|
|
case Type::KindOfBoolean: match = true; cast = orig.toBoolean(); break;
|
|
case Type::KindOfInt64: match = true; cast = orig.toInt64(); break;
|
|
case Type::KindOfDouble: match = true; cast = orig.toDouble(); break;
|
|
case Type::KindOfString: match = true; cast = orig.toString(); break;
|
|
}
|
|
|
|
if (!match || same(orig, cast)) {
|
|
// no changes need to be made
|
|
return ExpressionPtr();
|
|
}
|
|
|
|
ExpressionPtr p = makeScalarExpression(ar, cast);
|
|
p->setActualType(m_expectedType);
|
|
return p;
|
|
}
|
|
|
|
TypePtr ScalarExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
|
|
bool coerce) {
|
|
assert(false);
|
|
return TypePtr();
|
|
}
|
|
|
|
TypePtr ScalarExpression::inferenceImpl(AnalysisResultConstPtr ar,
|
|
TypePtr type, bool coerce) {
|
|
TypePtr actualType;
|
|
switch (m_type) {
|
|
case T_STRING:
|
|
actualType = Type::String;
|
|
break;
|
|
case T_NUM_STRING:
|
|
case T_LNUMBER:
|
|
actualType = Type::Int64;
|
|
break;
|
|
case T_DNUMBER:
|
|
actualType = Type::Double;
|
|
break;
|
|
|
|
case T_LINE:
|
|
actualType = Type::Int64;
|
|
break;
|
|
|
|
case T_CONSTANT_ENCAPSED_STRING:
|
|
case T_ENCAPSED_AND_WHITESPACE:
|
|
case T_TRAIT_C:
|
|
case T_CLASS_C:
|
|
case T_NS_C:
|
|
case T_METHOD_C:
|
|
case T_FUNC_C:
|
|
actualType = Type::String;
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
|
|
return checkTypesImpl(ar, type, actualType, coerce);
|
|
}
|
|
|
|
TypePtr ScalarExpression::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
|
|
bool coerce) {
|
|
IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());
|
|
resetTypes();
|
|
|
|
if (!Option::AllDynamic &&
|
|
ar->getPhase() == AnalysisResult::FirstInference &&
|
|
getScope()->isFirstPass() &&
|
|
isLiteralString() && m_value.find(' ') == string::npos) {
|
|
setDynamicByIdentifier(ar, m_value);
|
|
}
|
|
|
|
return inferenceImpl(ar, type, coerce);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// code generation functions
|
|
|
|
bool ScalarExpression::isLiteralInteger() const {
|
|
switch (m_type) {
|
|
case T_NUM_STRING:
|
|
{
|
|
char ch = m_value[0];
|
|
if ((ch == '0' && m_value.size() == 1) || ('1' <= ch && ch <= '9')) {
|
|
// Offset could be treated as a long
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
case T_LNUMBER:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int64_t ScalarExpression::getLiteralInteger() const {
|
|
assert(isLiteralInteger());
|
|
return strtoll(m_value.c_str(), nullptr, 0);
|
|
}
|
|
|
|
bool ScalarExpression::isLiteralString() const {
|
|
switch (m_type) {
|
|
case T_STRING:
|
|
return m_quoted;
|
|
case T_CONSTANT_ENCAPSED_STRING:
|
|
case T_ENCAPSED_AND_WHITESPACE:
|
|
assert(m_quoted); // fall through
|
|
case T_TRAIT_C:
|
|
case T_CLASS_C:
|
|
case T_NS_C:
|
|
case T_METHOD_C:
|
|
case T_FUNC_C:
|
|
return true;
|
|
case T_NUM_STRING:
|
|
{
|
|
char ch = m_value[0];
|
|
if (!((ch == '0' && m_value.size() == 1) || ('1' <= ch && ch <= '9'))) {
|
|
// Offset must be treated as a string
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::string ScalarExpression::getLiteralString() const {
|
|
return getLiteralStringImpl(false);
|
|
}
|
|
|
|
std::string ScalarExpression::getOriginalLiteralString() const {
|
|
return getLiteralStringImpl(true);
|
|
}
|
|
|
|
std::string ScalarExpression::getLiteralStringImpl(bool original) const {
|
|
string output;
|
|
if (!isLiteralString() && m_type != T_STRING) {
|
|
return output;
|
|
}
|
|
|
|
if (m_type == T_CLASS_C || m_type == T_NS_C || m_type == T_METHOD_C ||
|
|
m_type == T_FUNC_C || m_type == T_TRAIT_C) {
|
|
return m_translated;
|
|
}
|
|
|
|
switch (m_type) {
|
|
case T_NUM_STRING:
|
|
assert(isLiteralString());
|
|
case T_STRING:
|
|
case T_ENCAPSED_AND_WHITESPACE:
|
|
case T_CONSTANT_ENCAPSED_STRING:
|
|
return original ? m_originalValue : m_value;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
std::string ScalarExpression::getIdentifier() const {
|
|
if (isLiteralString()) {
|
|
std::string id = getLiteralString();
|
|
if (IsIdentifier(id)) {
|
|
return id;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
void ScalarExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
|
|
switch (m_type) {
|
|
case T_CONSTANT_ENCAPSED_STRING:
|
|
case T_ENCAPSED_AND_WHITESPACE:
|
|
assert(m_quoted); // fall through
|
|
case T_STRING:
|
|
if (m_quoted) {
|
|
string output = Util::escapeStringForPHP(m_originalValue);
|
|
cg_printf("%s", output.c_str());
|
|
} else {
|
|
cg_printf("%s", m_originalValue.c_str());
|
|
}
|
|
break;
|
|
case T_NUM_STRING:
|
|
case T_LNUMBER:
|
|
case T_DNUMBER:
|
|
cg_printf("%s", m_originalValue.c_str());
|
|
break;
|
|
case T_NS_C:
|
|
if (cg.translatePredefined()) {
|
|
cg_printf("%s", m_translated.c_str());
|
|
} else {
|
|
cg_printf("__NAMESPACE__");
|
|
}
|
|
break;
|
|
case T_LINE:
|
|
case T_TRAIT_C:
|
|
case T_CLASS_C:
|
|
case T_METHOD_C:
|
|
case T_FUNC_C:
|
|
if (cg.translatePredefined()) {
|
|
cg_printf("%s", m_translated.c_str());
|
|
} else {
|
|
cg_printf("%s", m_originalValue.c_str());
|
|
}
|
|
break;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
int64_t ScalarExpression::getHash() const {
|
|
int64_t hash = -1;
|
|
if (isLiteralInteger()) {
|
|
hash = hash_int64(getLiteralInteger());
|
|
} else if (isLiteralString()) {
|
|
string scs = getLiteralString();
|
|
int64_t res;
|
|
if (is_strictly_integer(scs.c_str(), scs.size(), res)) {
|
|
hash = hash_int64(res);
|
|
} else {
|
|
hash = hash_string(scs.c_str(), scs.size());
|
|
}
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
Variant ScalarExpression::getVariant() const {
|
|
if (!m_serializedValue.empty()) {
|
|
Variant ret = unserialize_from_buffer(
|
|
m_serializedValue.data(), m_serializedValue.size(), null_array);
|
|
if (ret.isDouble()) {
|
|
return m_dval;
|
|
}
|
|
return ret;
|
|
}
|
|
switch (m_type) {
|
|
case T_ENCAPSED_AND_WHITESPACE:
|
|
case T_CONSTANT_ENCAPSED_STRING:
|
|
case T_STRING:
|
|
case T_NUM_STRING:
|
|
return String(m_value);
|
|
case T_LNUMBER:
|
|
return strtoll(m_value.c_str(), nullptr, 0);
|
|
case T_LINE:
|
|
return String(m_translated).toInt64();
|
|
case T_TRAIT_C:
|
|
case T_CLASS_C:
|
|
case T_NS_C:
|
|
case T_METHOD_C:
|
|
case T_FUNC_C:
|
|
return String(m_translated);
|
|
case T_DNUMBER:
|
|
return String(m_value).toDouble();
|
|
default:
|
|
assert(false);
|
|
}
|
|
return uninit_null();
|
|
}
|
|
|
|
bool ScalarExpression::getString(const std::string *&s) const {
|
|
switch (m_type) {
|
|
case T_ENCAPSED_AND_WHITESPACE:
|
|
case T_CONSTANT_ENCAPSED_STRING:
|
|
case T_STRING:
|
|
case T_NUM_STRING:
|
|
s = &m_value;
|
|
return true;
|
|
case T_TRAIT_C:
|
|
case T_CLASS_C:
|
|
case T_NS_C:
|
|
case T_METHOD_C:
|
|
case T_FUNC_C:
|
|
s = &m_translated;
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ScalarExpression::getInt(int64_t &i) const {
|
|
if (m_type == T_LNUMBER) {
|
|
i = strtoll(m_value.c_str(), nullptr, 0);
|
|
return true;
|
|
} else if (m_type == T_LINE) {
|
|
i = getLocation() ? getLocation()->line1 : 0;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ScalarExpression::getDouble(double &d) const {
|
|
if (m_type == T_DNUMBER) {
|
|
Variant v = getVariant();
|
|
assert(v.isDouble());
|
|
d = v.toDouble();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|