From: Josh Stone Date: Tue Jan 19 15:36:35 2010 -0800 Git-Repo: git://sources.redhat.com/git/systemtap.git Git-Commit: 9300f661214a4f4dfac75878485867b30c7db389 Signed-Off-By: Tony Jones tonyj: this fixes parse errors such as: parse error: expected 'probe', 'global', 'function', or '%{' saw: identifier '?robe' at ------------------------------------------------- PR11195: Prevent all nested argument substitution Our existing protection only made sure that the first token in a substitution wasn't a nested substitution. That's not sufficient when there could be multiple tokens involved. This patch makes sure that no nested tokens are ever allowed to be argument substitutions. This also adds a cursor_suspended_line/column and resets the main cursor_line/column to the beginning of the substitution, so errors will point a little closer to the right place. diff --git a/parse.cxx b/parse.cxx index edb1927..2688d6d 100644 --- a/parse.cxx +++ b/parse.cxx @@ -632,7 +632,8 @@ parser::peek_kw (std::string const & kw) lexer::lexer (istream& input, const string& in, systemtap_session& s): input_name (in), input_pointer (0), input_end (0), - cursor_suspend_count(0), cursor_line (1), cursor_column (1), + cursor_suspend_count(0), cursor_suspend_line (1), cursor_suspend_column (1), + cursor_line (1), cursor_column (1), session(s), current_file (0) { getline(input, input_contents, '\0'); @@ -693,9 +694,15 @@ lexer::input_get () ++input_pointer; if (cursor_suspend_count) - // Track effect of input_put: preserve previous cursor/line_column - // until all of its characters are consumed. - cursor_suspend_count --; + { + // Track effect of input_put: preserve previous cursor/line_column + // until all of its characters are consumed. + if (--cursor_suspend_count == 0) + { + cursor_line = cursor_suspend_line; + cursor_column = cursor_suspend_column; + } + } else { // update source cursor @@ -714,12 +721,16 @@ lexer::input_get () void -lexer::input_put (const string& chars) +lexer::input_put (const string& chars, const token* t) { size_t pos = input_pointer - input_contents.data(); // clog << "[put:" << chars << " @" << pos << "]"; input_contents.insert (pos, chars); cursor_suspend_count += chars.size(); + cursor_suspend_line = cursor_line; + cursor_suspend_column = cursor_column; + cursor_line = t->location.line; + cursor_column = t->location.column; input_pointer = input_contents.data() + pos; input_end = input_contents.data() + input_contents.size(); } @@ -731,19 +742,11 @@ lexer::scan (bool wildcard) token* n = new token; n->location.file = current_file; - unsigned semiskipped_p = 0; - - skip: +skip: + bool suspended = (cursor_suspend_count > 0); n->location.line = cursor_line; n->location.column = cursor_column; - semiskip: - if (semiskipped_p > 1) - { - input_get (); - throw parse_error ("invalid nested substitution of command line arguments"); - } - int c = input_get(); // clog << "{" << (char)c << (char)c2 << "}"; if (c < 0) @@ -762,38 +765,41 @@ lexer::scan (bool wildcard) // characters; @1..@999 are quoted/escaped as strings. // $# and @# expand to the number of arguments, similarly // raw or quoted. - if ((c == '$' || c == '@') && - (c2 == '#')) + if ((c == '$' || c == '@') && (c2 == '#')) { + n->content.push_back (c); + n->content.push_back (c2); input_get(); // swallow '#' - stringstream converter; - converter << session.args.size (); - if (c == '$') input_put (converter.str()); - else input_put (lex_cast_qstring (converter.str())); - semiskipped_p ++; - goto semiskip; + if (suspended) + throw parse_error ("invalid nested substitution of command line arguments", n); + size_t num_args = session.args.size (); + input_put ((c == '$') ? lex_cast (num_args) : lex_cast_qstring (num_args), n); + n->content.clear(); + goto skip; } - else if ((c == '$' || c == '@') && - (isdigit (c2))) + else if ((c == '$' || c == '@') && (isdigit (c2))) { + n->content.push_back (c); unsigned idx = 0; do { input_get (); idx = (idx * 10) + (c2 - '0'); + n->content.push_back (c2); c2 = input_peek (); } while (c2 > 0 && isdigit (c2) && idx <= session.args.size()); // prevent overflow + if (suspended) + throw parse_error ("invalid nested substitution of command line arguments", n); if (idx == 0 || idx-1 >= session.args.size()) throw parse_error ("command line argument index " + lex_cast(idx) + " out of range [1-" + lex_cast(session.args.size()) + "]", n); - string arg = session.args[idx-1]; - if (c == '$') input_put (arg); - else input_put (lex_cast_qstring (arg)); - semiskipped_p ++; - goto semiskip; + const string& arg = session.args[idx-1]; + input_put ((c == '$') ? arg : lex_cast_qstring (arg), n); + n->content.clear(); + goto skip; } else if (isalpha (c) || c == '$' || c == '@' || c == '_' || diff --git a/parse.h b/parse.h index 5587586..0ff8664 100644 --- a/parse.h +++ b/parse.h @@ -79,12 +79,14 @@ public: private: inline int input_get (); inline int input_peek (unsigned n=0); - void input_put (const std::string&); + void input_put (const std::string&, const token*); std::string input_name; std::string input_contents; const char *input_pointer; // index into input_contents const char *input_end; unsigned cursor_suspend_count; + unsigned cursor_suspend_line; + unsigned cursor_suspend_column; unsigned cursor_line; unsigned cursor_column; systemtap_session& session; diff --git a/testsuite/parseko/preprocess16.stp b/testsuite/parseko/preprocess16.stp new file mode 100755 index 0000000..364bad6 --- /dev/null +++ b/testsuite/parseko/preprocess16.stp @@ -0,0 +1,4 @@ +#! /bin/sh + +# recursive after the first token (PR11195) +stap -p1 -e 'probe begin {$1}' 'x $1'