From a2ff672b349800c18eb7540c88ce851e44bdf27f Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Wed, 22 Jul 2015 11:13:10 -0600 Subject: [PATCH] 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 --- .../chaiscript/language/chaiscript_eval.hpp | 3 +- .../chaiscript/language/chaiscript_parser.hpp | 106 ++++++++++-------- 2 files changed, 61 insertions(+), 48 deletions(-) diff --git a/include/chaiscript/language/chaiscript_eval.hpp b/include/chaiscript/language/chaiscript_eval.hpp index c14a156..0478452 100644 --- a/include/chaiscript/language/chaiscript_eval.hpp +++ b/include/chaiscript/language/chaiscript_eval.hpp @@ -118,7 +118,7 @@ namespace chaiscript public: 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)), - m_value(std::move(t_bv)) { } + m_value(std::move(t_bv)) { assert(text != ""); } virtual ~Int_AST_Node() {} virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &) const CHAISCRIPT_OVERRIDE{ return m_value; @@ -629,6 +629,7 @@ namespace chaiscript virtual Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const CHAISCRIPT_OVERRIDE{ chaiscript::eval::detail::Function_Push_Pop fpp(t_ss); + Boxed_Value retval = children[0]->eval(t_ss); std::vector params{retval}; diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index ddc484f..4ba2f54 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -60,6 +60,8 @@ namespace chaiscript std::vector> m_operator_matches; std::vector m_operators; + void increment_pos(std::string::const_iterator &itr) { if (itr != m_input_end) ++itr; } + public: ChaiScript_Parser() : m_line(-1), m_col(-1), @@ -167,17 +169,16 @@ namespace chaiscript } /// test a char in an m_alphabet - bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast(c)]; } + bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast(c)]; } /// Prints the parsed ast_nodes as a tree - /* - 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'; - for (unsigned int j = 0; j < t->children.size(); ++j) { - debug_print(t->children[j], 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'; + for (unsigned int j = 0; j < t->children.size(); ++j) { + debug_print(t->children[j], prepend + " "); + } + } + /// Shows the current stack of matched ast_nodes void show_match_stack() const { @@ -326,7 +327,7 @@ namespace chaiscript break; } else if (!Eol_()) { ++m_col; - ++m_input_pos; + increment_pos(m_input_pos); } } return true; @@ -340,7 +341,7 @@ namespace chaiscript break; } else { ++m_col; - ++m_input_pos; + increment_pos(m_input_pos); } } return true; @@ -365,13 +366,14 @@ namespace chaiscript if(*(m_input_pos) == '\r') { // discards lf - ++m_input_pos; + increment_pos(m_input_pos); } } else { ++m_col; } - ++m_input_pos; + + increment_pos(m_input_pos); retval = true; } @@ -388,15 +390,15 @@ namespace chaiscript bool read_exponent_and_suffix() { // Support a form of scientific notation: 1e-5, 35.5E+8, 0.01e19 if (has_more_input() && (std::tolower(*m_input_pos) == 'e')) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; if (has_more_input() && ((*m_input_pos == '-') || (*m_input_pos == '+'))) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } auto exponent_pos = m_input_pos; while (has_more_input() && char_in_alphabet(*m_input_pos,detail::int_alphabet) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } if (m_input_pos == exponent_pos) { @@ -408,7 +410,7 @@ namespace chaiscript // Parse optional float suffix while (has_more_input() && char_in_alphabet(*m_input_pos, detail::float_suffix_alphabet)) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } @@ -420,7 +422,7 @@ namespace chaiscript bool Float_() { 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) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } @@ -429,11 +431,11 @@ namespace chaiscript return read_exponent_and_suffix(); } else if (has_more_input() && (*m_input_pos == '.')) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; 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) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } @@ -451,20 +453,20 @@ namespace chaiscript /// Reads a hex value from input, without skipping initial whitespace bool Hex_() { if (has_more_input() && (*m_input_pos == '0')) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::x_alphabet) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; 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) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet)) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } @@ -488,7 +490,7 @@ namespace chaiscript void IntSuffix_() { while (has_more_input() && char_in_alphabet(*m_input_pos, detail::int_suffix_alphabet)) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } } @@ -496,15 +498,15 @@ namespace chaiscript /// Reads a binary value from input, without skipping initial whitespace bool Binary_() { if (has_more_input() && (*m_input_pos == '0')) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; if (has_more_input() && char_in_alphabet(*m_input_pos, detail::b_alphabet) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; 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) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } return true; @@ -738,9 +740,11 @@ namespace chaiscript auto bv = buildInt(std::oct, match); m_match_stack.push_back(make_node(std::move(match), prev_line, prev_col, std::move(bv))); } - else { + else if (!match.empty()) { auto bv = buildInt(std::dec, match); m_match_stack.push_back(make_node(std::move(match), prev_line, prev_col, std::move(bv))); + } else { + return false; } return true; } @@ -755,14 +759,14 @@ namespace chaiscript bool Id_() { 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) ) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } return true; } else if (has_more_input() && (*m_input_pos == '`')) { ++m_col; - ++m_input_pos; + increment_pos(m_input_pos); const auto start = 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); } else { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } } @@ -783,7 +787,7 @@ namespace chaiscript } ++m_col; - ++m_input_pos; + increment_pos(m_input_pos); return true; } @@ -850,7 +854,7 @@ namespace chaiscript } else { ++m_col; - ++m_input_pos; + increment_pos(m_input_pos); } } } while (Symbol("#")); @@ -868,7 +872,7 @@ namespace chaiscript bool Quoted_String_() { if (has_more_input() && (*m_input_pos == '\"')) { char prev_char = *m_input_pos; - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; while (has_more_input() && ((*m_input_pos != '\"') || ((*m_input_pos == '\"') && (prev_char == '\\')))) { @@ -878,13 +882,13 @@ namespace chaiscript } else { prev_char = *m_input_pos; } - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } } if (has_more_input()) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } else { 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 == '\'')) { retval = true; char prev_char = *m_input_pos; - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; while (has_more_input() && ((*m_input_pos != '\'') || ((*m_input_pos == '\'') && (prev_char == '\\')))) { @@ -1031,13 +1035,13 @@ namespace chaiscript } else { prev_char = *m_input_pos; } - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } } if (m_input_pos != m_input_end) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; } else { 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 bool Char_(const char c) { if (has_more_input() && (*m_input_pos == c)) { - ++m_input_pos; + increment_pos(m_input_pos); ++m_col; return true; } else { @@ -1130,11 +1134,11 @@ namespace chaiscript if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { 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]) { return false; } - ++tmp; + increment_pos(tmp); } m_input_pos = tmp; m_col += static_cast(len); @@ -1171,11 +1175,11 @@ namespace chaiscript if ((m_input_end - m_input_pos) >= static_cast::type>(len)) { 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]) { return false; } - ++tmp; + increment_pos(tmp); } m_input_pos = tmp; m_col += static_cast(len); @@ -1895,13 +1899,17 @@ namespace chaiscript /// \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[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 func_call = m_match_stack.back(); m_match_stack.pop_back(); 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()); dot_access->children.pop_back(); 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)); } } @@ -1917,9 +1925,12 @@ namespace chaiscript else if (Symbol(".", true)) { has_more = true; 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(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(prev_stack_top); } } @@ -2307,7 +2318,7 @@ namespace chaiscript if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) { 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) } @@ -2317,6 +2328,7 @@ namespace chaiscript throw exception::eval_error("Unparsed input", File_Position(m_line, m_col), t_fname); } else { build_match(0); + //debug_print(ast()); return true; } } else {