Memory error fixes

* prevent recognizing . as a number
 * do all checked iterator operations for incrementing through input
   stream
 * Verify that all is as expected when building up a dot notation call
This commit is contained in:
Jason Turner 2015-07-22 11:13:10 -06:00
parent 9a0a12d230
commit a2ff672b34
2 changed files with 61 additions and 48 deletions

View File

@ -118,7 +118,7 @@ namespace chaiscript
public: public:
Int_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_bv) : Int_AST_Node(std::string t_ast_node_text, Parse_Location t_loc, Boxed_Value t_bv) :
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, std::move(t_loc)), AST_Node(std::move(t_ast_node_text), AST_Node_Type::Int, std::move(t_loc)),
m_value(std::move(t_bv)) { } m_value(std::move(t_bv)) { assert(text != ""); }
virtual ~Int_AST_Node() {} virtual ~Int_AST_Node() {}
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{ virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{
return m_value; return m_value;
@ -629,6 +629,7 @@ namespace chaiscript
virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
Boxed_Value retval = children[0]->eval(t_ss); Boxed_Value retval = children[0]->eval(t_ss);
std::vector<Boxed_Value> params{retval}; std::vector<Boxed_Value> params{retval};

View File

@ -60,6 +60,8 @@ namespace chaiscript
std::vector<std::vector<std::string>> m_operator_matches; std::vector<std::vector<std::string>> m_operator_matches;
std::vector<AST_Node_Type::Type> m_operators; std::vector<AST_Node_Type::Type> m_operators;
void increment_pos(std::string::const_iterator &itr) { if (itr != m_input_end) ++itr; }
public: public:
ChaiScript_Parser() ChaiScript_Parser()
: m_line(-1), m_col(-1), : m_line(-1), m_col(-1),
@ -167,17 +169,16 @@ namespace chaiscript
} }
/// test a char in an m_alphabet /// test a char in an m_alphabet
bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast<int>(c)]; } bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast<uint8_t>(c)]; }
/// Prints the parsed ast_nodes as a tree /// Prints the parsed ast_nodes as a tree
/* void debug_print(AST_NodePtr t, std::string prepend = "") {
void debug_print(AST_NodePtr t, std::string prepend = "") { std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start().line << ", " << t->start().column << '\n';
std::cout << prepend << "(" << ast_node_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << '\n'; for (unsigned int j = 0; j < t->children.size(); ++j) {
for (unsigned int j = 0; j < t->children.size(); ++j) { debug_print(t->children[j], prepend + " ");
debug_print(t->children[j], prepend + " "); }
} }
}
*/
/// Shows the current stack of matched ast_nodes /// Shows the current stack of matched ast_nodes
void show_match_stack() const { void show_match_stack() const {
@ -326,7 +327,7 @@ namespace chaiscript
break; break;
} else if (!Eol_()) { } else if (!Eol_()) {
++m_col; ++m_col;
++m_input_pos; increment_pos(m_input_pos);
} }
} }
return true; return true;
@ -340,7 +341,7 @@ namespace chaiscript
break; break;
} else { } else {
++m_col; ++m_col;
++m_input_pos; increment_pos(m_input_pos);
} }
} }
return true; return true;
@ -365,13 +366,14 @@ namespace chaiscript
if(*(m_input_pos) == '\r') { if(*(m_input_pos) == '\r') {
// discards lf // discards lf
++m_input_pos; increment_pos(m_input_pos);
} }
} }
else { else {
++m_col; ++m_col;
} }
++m_input_pos;
increment_pos(m_input_pos);
retval = true; retval = true;
} }
@ -388,15 +390,15 @@ namespace chaiscript
bool read_exponent_and_suffix() { bool read_exponent_and_suffix() {
// Support a form of scientific notation: 1e-5, 35.5E+8, 0.01e19 // Support a form of scientific notation: 1e-5, 35.5E+8, 0.01e19
if (has_more_input() && (std::tolower(*m_input_pos) == 'e')) { if (has_more_input() && (std::tolower(*m_input_pos) == 'e')) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
if (has_more_input() && ((*m_input_pos == '-') || (*m_input_pos == '+'))) { if (has_more_input() && ((*m_input_pos == '-') || (*m_input_pos == '+'))) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
auto exponent_pos = m_input_pos; auto exponent_pos = m_input_pos;
while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
if (m_input_pos == exponent_pos) { if (m_input_pos == exponent_pos) {
@ -408,7 +410,7 @@ namespace chaiscript
// Parse optional float suffix // Parse optional float suffix
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_suffix_alphabet)) while (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_suffix_alphabet))
{ {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
@ -420,7 +422,7 @@ namespace chaiscript
bool Float_() { bool Float_() {
if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) { if (has_more_input() && char_in_alphabet(*m_input_pos,detail::float_alphabet) ) {
while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
@ -429,11 +431,11 @@ namespace chaiscript
return read_exponent_and_suffix(); return read_exponent_and_suffix();
} }
else if (has_more_input() && (*m_input_pos == '.')) { else if (has_more_input() && (*m_input_pos == '.')) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
if (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet)) { if (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet)) {
while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
@ -451,20 +453,20 @@ namespace chaiscript
/// Reads a hex value from input, without skipping initial whitespace /// Reads a hex value from input, without skipping initial whitespace
bool Hex_() { bool Hex_() {
if (has_more_input() && (*m_input_pos == '0')) { if (has_more_input() && (*m_input_pos == '0')) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
if (has_more_input() && char_in_alphabet(*m_input_pos, detail::x_alphabet) ) { if (has_more_input() && char_in_alphabet(*m_input_pos, detail::x_alphabet) ) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
if (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet)) { if (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet)) {
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet) ) { while (has_more_input() && char_in_alphabet(*m_input_pos, detail::hex_alphabet) ) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet)) while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet))
{ {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
@ -488,7 +490,7 @@ namespace chaiscript
void IntSuffix_() { void IntSuffix_() {
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet)) while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet))
{ {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
} }
@ -496,15 +498,15 @@ namespace chaiscript
/// Reads a binary value from input, without skipping initial whitespace /// Reads a binary value from input, without skipping initial whitespace
bool Binary_() { bool Binary_() {
if (has_more_input() && (*m_input_pos == '0')) { if (has_more_input() && (*m_input_pos == '0')) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
if (has_more_input() && char_in_alphabet(*m_input_pos, detail::b_alphabet) ) { if (has_more_input() && char_in_alphabet(*m_input_pos, detail::b_alphabet) ) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
if (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { if (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) {
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) { while (has_more_input() && char_in_alphabet(*m_input_pos, detail::bin_alphabet) ) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
return true; return true;
@ -738,9 +740,11 @@ namespace chaiscript
auto bv = buildInt(std::oct, match); auto bv = buildInt(std::oct, match);
m_match_stack.push_back(make_node<eval::Int_AST_Node>(std::move(match), prev_line, prev_col, std::move(bv))); m_match_stack.push_back(make_node<eval::Int_AST_Node>(std::move(match), prev_line, prev_col, std::move(bv)));
} }
else { else if (!match.empty()) {
auto bv = buildInt(std::dec, match); auto bv = buildInt(std::dec, match);
m_match_stack.push_back(make_node<eval::Int_AST_Node>(std::move(match), prev_line, prev_col, std::move(bv))); m_match_stack.push_back(make_node<eval::Int_AST_Node>(std::move(match), prev_line, prev_col, std::move(bv)));
} else {
return false;
} }
return true; return true;
} }
@ -755,14 +759,14 @@ namespace chaiscript
bool Id_() { bool Id_() {
if (has_more_input() && char_in_alphabet(*m_input_pos, detail::id_alphabet)) { if (has_more_input() && char_in_alphabet(*m_input_pos, detail::id_alphabet)) {
while (has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) { while (has_more_input() && char_in_alphabet(*m_input_pos, detail::keyword_alphabet) ) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
return true; return true;
} else if (has_more_input() && (*m_input_pos == '`')) { } else if (has_more_input() && (*m_input_pos == '`')) {
++m_col; ++m_col;
++m_input_pos; increment_pos(m_input_pos);
const auto start = m_input_pos; const auto start = m_input_pos;
while (has_more_input() && (*m_input_pos != '`')) { while (has_more_input() && (*m_input_pos != '`')) {
@ -770,7 +774,7 @@ namespace chaiscript
throw exception::eval_error("Carriage return in identifier literal", File_Position(m_line, m_col), *m_filename); throw exception::eval_error("Carriage return in identifier literal", File_Position(m_line, m_col), *m_filename);
} }
else { else {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
} }
@ -783,7 +787,7 @@ namespace chaiscript
} }
++m_col; ++m_col;
++m_input_pos; increment_pos(m_input_pos);
return true; return true;
} }
@ -850,7 +854,7 @@ namespace chaiscript
} }
else { else {
++m_col; ++m_col;
++m_input_pos; increment_pos(m_input_pos);
} }
} }
} while (Symbol("#")); } while (Symbol("#"));
@ -868,7 +872,7 @@ namespace chaiscript
bool Quoted_String_() { bool Quoted_String_() {
if (has_more_input() && (*m_input_pos == '\"')) { if (has_more_input() && (*m_input_pos == '\"')) {
char prev_char = *m_input_pos; char prev_char = *m_input_pos;
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
while (has_more_input() && ((*m_input_pos != '\"') || ((*m_input_pos == '\"') && (prev_char == '\\')))) { while (has_more_input() && ((*m_input_pos != '\"') || ((*m_input_pos == '\"') && (prev_char == '\\')))) {
@ -878,13 +882,13 @@ namespace chaiscript
} else { } else {
prev_char = *m_input_pos; prev_char = *m_input_pos;
} }
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
} }
if (has_more_input()) { if (has_more_input()) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} else { } else {
throw exception::eval_error("Unclosed quoted string", File_Position(m_line, m_col), *m_filename); throw exception::eval_error("Unclosed quoted string", File_Position(m_line, m_col), *m_filename);
@ -1021,7 +1025,7 @@ namespace chaiscript
if (has_more_input() && (*m_input_pos == '\'')) { if (has_more_input() && (*m_input_pos == '\'')) {
retval = true; retval = true;
char prev_char = *m_input_pos; char prev_char = *m_input_pos;
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) {
@ -1031,13 +1035,13 @@ namespace chaiscript
} else { } else {
prev_char = *m_input_pos; prev_char = *m_input_pos;
} }
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} }
} }
if (m_input_pos != m_input_end) { if (m_input_pos != m_input_end) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
} else { } else {
throw exception::eval_error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename); throw exception::eval_error("Unclosed single-quoted string", File_Position(m_line, m_col), *m_filename);
@ -1097,7 +1101,7 @@ namespace chaiscript
/// Reads a char from input if it matches the parameter, without skipping initial whitespace /// Reads a char from input if it matches the parameter, without skipping initial whitespace
bool Char_(const char c) { bool Char_(const char c) {
if (has_more_input() && (*m_input_pos == c)) { if (has_more_input() && (*m_input_pos == c)) {
++m_input_pos; increment_pos(m_input_pos);
++m_col; ++m_col;
return true; return true;
} else { } else {
@ -1130,11 +1134,11 @@ namespace chaiscript
if ((m_input_end - m_input_pos) >= static_cast<std::make_signed<size_t>::type>(len)) { if ((m_input_end - m_input_pos) >= static_cast<std::make_signed<size_t>::type>(len)) {
auto tmp = m_input_pos; auto tmp = m_input_pos;
for (size_t i = 0; i < len; ++i) { for (size_t i = 0; tmp != m_input_end && i < len; ++i) {
if (*tmp != t_s[i]) { if (*tmp != t_s[i]) {
return false; return false;
} }
++tmp; increment_pos(tmp);
} }
m_input_pos = tmp; m_input_pos = tmp;
m_col += static_cast<int>(len); m_col += static_cast<int>(len);
@ -1171,11 +1175,11 @@ namespace chaiscript
if ((m_input_end - m_input_pos) >= static_cast<std::make_signed<decltype(len)>::type>(len)) { if ((m_input_end - m_input_pos) >= static_cast<std::make_signed<decltype(len)>::type>(len)) {
auto tmp = m_input_pos; auto tmp = m_input_pos;
for (size_t i = 0; i < len; ++i) { for (size_t i = 0; tmp != m_input_end && i < len; ++i) {
if (*tmp != t_s[i]) { if (*tmp != t_s[i]) {
return false; return false;
} }
++tmp; increment_pos(tmp);
} }
m_input_pos = tmp; m_input_pos = tmp;
m_col += static_cast<int>(len); m_col += static_cast<int>(len);
@ -1895,13 +1899,17 @@ namespace chaiscript
/// \todo Work around for method calls until we have a better solution /// \todo Work around for method calls until we have a better solution
if (!m_match_stack.back()->children.empty()) { if (!m_match_stack.back()->children.empty()) {
if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) { if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) {
if (m_match_stack.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename);
if (m_match_stack.back()->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename);
AST_NodePtr dot_access = m_match_stack.back()->children[0]; AST_NodePtr dot_access = m_match_stack.back()->children[0];
AST_NodePtr func_call = m_match_stack.back(); AST_NodePtr func_call = m_match_stack.back();
m_match_stack.pop_back(); m_match_stack.pop_back();
func_call->children.erase(func_call->children.begin()); func_call->children.erase(func_call->children.begin());
if (dot_access->children.empty()) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename);
func_call->children.insert(func_call->children.begin(), dot_access->children.back()); func_call->children.insert(func_call->children.begin(), dot_access->children.back());
dot_access->children.pop_back(); dot_access->children.pop_back();
dot_access->children.push_back(std::move(func_call)); dot_access->children.push_back(std::move(func_call));
if (dot_access->children.size() != 3) throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename);
m_match_stack.push_back(std::move(dot_access)); m_match_stack.push_back(std::move(dot_access));
} }
} }
@ -1917,9 +1925,12 @@ namespace chaiscript
else if (Symbol(".", true)) { else if (Symbol(".", true)) {
has_more = true; has_more = true;
if (!(Id())) { if (!(Id())) {
throw exception::eval_error("Incomplete array access", File_Position(m_line, m_col), *m_filename); throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename);
} }
if ( std::distance(m_match_stack.begin() + static_cast<int>(prev_stack_top), m_match_stack.end()) != 3) {
throw exception::eval_error("Incomplete dot access fun call", File_Position(m_line, m_col), *m_filename);
}
build_match<eval::Dot_Access_AST_Node>(prev_stack_top); build_match<eval::Dot_Access_AST_Node>(prev_stack_top);
} }
} }
@ -2307,7 +2318,7 @@ namespace chaiscript
if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) {
while ((m_input_pos != m_input_end) && (!Eol())) { while ((m_input_pos != m_input_end) && (!Eol())) {
++m_input_pos; increment_pos(m_input_pos);
} }
/// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html) /// \todo respect // -*- coding: utf-8 -*- on line 1 or 2 see: http://evanjones.ca/python-utf8.html)
} }
@ -2317,6 +2328,7 @@ namespace chaiscript
throw exception::eval_error("Unparsed input", File_Position(m_line, m_col), t_fname); throw exception::eval_error("Unparsed input", File_Position(m_line, m_col), t_fname);
} else { } else {
build_match<eval::File_AST_Node>(0); build_match<eval::File_AST_Node>(0);
//debug_print(ast());
return true; return true;
} }
} else { } else {