Arquivos
hhvm/hphp/util/parser/parser.cpp
T
mwilliams 23919b915f Fix crash/hang in Parser::newClosureName
The parser was updating a static std::map without a lock.
It looks like this is supposed to be local to a file anyway,
so add the map as a member of ParserBase.
2013-05-28 10:30:27 -07:00

263 linhas
7.5 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 "parser.h"
#include "hphp/util/hash.h"
#include <boost/algorithm/string/predicate.hpp>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
bool ParserBase::IsClosureName(const std::string &name) {
return boost::istarts_with(name, "closure$");
}
bool ParserBase::IsContinuationName(const std::string &name) {
return boost::iends_with(name, "$continuation");
}
bool ParserBase::IsClosureOrContinuationName(const std::string &name) {
return IsClosureName(name) || IsContinuationName(name);
}
std::string ParserBase::newContinuationName(const std::string &name) {
assert(!name.empty());
size_t pos = 0;
std::string shorterName = name;
std::string suffix("$continuation");
while((pos = shorterName.find(suffix, pos)) != std::string::npos) {
shorterName.replace(pos, suffix.length(), "");
}
return shorterName + suffix;
}
std::string ParserBase::newClosureName(
const std::string &className,
const std::string &funcName) {
std::string name = "Closure$";
if (!className.empty()) {
name += className + "::";
}
name += funcName;
int id = ++m_seenClosures[name];
if (id > 1) {
// we've seen the same name before, uniquify
name = name + '#' + std::to_string(id);
}
return name;
}
///////////////////////////////////////////////////////////////////////////////
ParserBase::ParserBase(Scanner &scanner, const char *fileName)
: m_scanner(scanner), m_fileName(fileName) {
if (m_fileName == nullptr) m_fileName = "";
// global scope
m_labelInfos.reserve(3);
m_labelInfos.resize(1);
pushLabelScope();
}
ParserBase::~ParserBase() {
}
std::string ParserBase::getMessage(bool filename /* = false */) const {
string ret = m_scanner.getError();
if (!ret.empty()) {
ret += " ";
}
ret += getMessage(m_scanner.getLocation(), filename);
return ret;
}
std::string ParserBase::getMessage(Location *loc,
bool filename /* = false */) const {
int line = loc->line1;
int column = loc->char1;
string ret = "(";
if (filename) {
ret += string("File: ") + file() + ", ";
}
ret += string("Line: ") + boost::lexical_cast<string>(line);
ret += ", Char: " + boost::lexical_cast<string>(column) + ")";
return ret;
}
LocationPtr ParserBase::getLocation() const {
LocationPtr location(new Location());
location->file = file();
location->line0 = line0();
location->char0 = char0();
location->line1 = line1();
location->char1 = char1();
location->cursor = cursor();
return location;
}
///////////////////////////////////////////////////////////////////////////////
// T_FUNCTION related functions
void ParserBase::pushFuncLocation() {
m_funcLocs.push_back(getLocation());
}
LocationPtr ParserBase::popFuncLocation() {
assert(!m_funcLocs.empty());
LocationPtr loc = m_funcLocs.back();
m_funcLocs.pop_back();
return loc;
}
void ParserBase::pushClass(bool isXhpClass) {
m_classes.push_back(isXhpClass);
}
bool ParserBase::peekClass() {
assert(!m_classes.empty());
return m_classes.back();
}
void ParserBase::popClass() {
m_classes.pop_back();
}
///////////////////////////////////////////////////////////////////////////////
// typevar scopes
void ParserBase::pushTypeScope() {
m_typeScopes.push_back(m_typeVars);
m_typeVars.clear();
}
void ParserBase::popTypeScope() {
m_typeScopes.pop_back();
}
void ParserBase::addTypeVar(const std::string &name) {
m_typeVars.insert(name);
}
bool ParserBase::isTypeVar(const std::string &name) {
for (TypevarScopeStack::iterator iter = m_typeScopes.begin();
iter != m_typeScopes.end();
iter++) {
if (iter->find(name) != iter->end()) {
return true;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
// checks GOTO label syntax
void ParserBase::pushLabelInfo() {
m_labelInfos.resize(m_labelInfos.size() + 1);
pushLabelScope();
}
void ParserBase::pushLabelScope() {
assert(!m_labelInfos.empty());
LabelInfo &info = m_labelInfos.back();
info.scopes.push_back(++info.scopeId);
}
void ParserBase::popLabelScope() {
assert(!m_labelInfos.empty());
LabelInfo &info = m_labelInfos.back();
info.scopes.pop_back();
}
void ParserBase::addLabel(const std::string &label,
LocationPtr loc,
ScannerToken *stmt) {
assert(!m_labelInfos.empty());
LabelInfo &info = m_labelInfos.back();
if (info.labels.find(label) != info.labels.end()) {
error("Label '%s' already defined: %s", label.c_str(),
getMessage().c_str());
invalidateLabel(extractStatement(stmt));
return;
}
assert(!info.scopes.empty());
LabelStmtInfo labelInfo;
labelInfo.scopeId = info.scopes.back();
labelInfo.stmt = extractStatement(stmt);
labelInfo.loc = loc;
info.labels[label] = labelInfo;
}
void ParserBase::addGoto(const std::string &label,
LocationPtr loc,
ScannerToken *stmt) {
assert(!m_labelInfos.empty());
LabelInfo &info = m_labelInfos.back();
GotoInfo gotoInfo;
gotoInfo.label = label;
gotoInfo.scopes = info.scopes;
gotoInfo.loc = loc;
gotoInfo.stmt = extractStatement(stmt);
info.gotos.push_back(gotoInfo);
}
void ParserBase::popLabelInfo() {
assert(!m_labelInfos.empty());
LabelInfo &info = m_labelInfos.back();
LabelMap labels = info.labels; // shallow copy
for (unsigned int i = 0; i < info.gotos.size(); i++) {
const GotoInfo &gotoInfo = info.gotos[i];
LabelMap::const_iterator iter = info.labels.find(gotoInfo.label);
if (iter == info.labels.end()) {
invalidateGoto(gotoInfo.stmt, UndefLabel);
error("'goto' to undefined label '%s': %s",
gotoInfo.label.c_str(), getMessage(gotoInfo.loc.get()).c_str());
continue;
}
const LabelStmtInfo &labelInfo = iter->second;
int labelScopeId = labelInfo.scopeId;
bool found = false;
for (int j = gotoInfo.scopes.size() - 1; j >= 0; j--) {
if (labelScopeId == gotoInfo.scopes[j]) {
found = true;
break;
}
}
if (!found) {
invalidateGoto(gotoInfo.stmt, InvalidBlock);
error("'goto' into loop or switch statement "
"is disallowed: %s", getMessage(gotoInfo.loc.get()).c_str());
continue;
} else {
labels.erase(gotoInfo.label);
}
}
// now invalidate all un-used labels
for (LabelMap::const_iterator it(labels.begin());
it != labels.end();
++it) {
invalidateLabel(it->second.stmt);
}
m_labelInfos.pop_back();
}
///////////////////////////////////////////////////////////////////////////////
}