[gcc r17-2902] cobol: Avoid internal compiler error in generated lexer.
"James K. Lowden via Gcc-cvs" <[email protected]> Mon, 3 Aug 2026 18:29:49 +0000 (GMT)
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:a5407eb736feab6e8778c0899fbf4626ee506a60 commit r17-2902-ga5407eb736feab6e8778c0899fbf4626ee506a60 Author: James K. Lowden <[email protected]> Date: Mon Aug 3 14:06:08 2026 -0400 cobol: Avoid internal compiler error in generated lexer. For some inputs the lexer returned: input buffer overflow, can't enlarge buffer because scanner uses REJECT. In fact REJECT is not used, but the message can be engendered by variable-length patterns if they match very long input. Use the flex input() and unput() to read the stream in advance of pattern-matching, and restore it before the lexer continues. gcc/cobol/ChangeLog: * scan.l: Remove pattern that potentially matches until EOF. * scan_ante.h (skip_string): Recast in terms of input/unput. (yyinput): Declare function. (yyunput): Declare function. (is_refmod): Recast in terms of input/unput. Diff: --- gcc/cobol/scan.l | 12 ++++---- gcc/cobol/scan_ante.h | 76 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 64 insertions(+), 24 deletions(-) diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l index b2843b9c7adf..1de688ee74fe 100644 --- a/gcc/cobol/scan.l +++ b/gcc/cobol/scan.l @@ -168,6 +168,10 @@ NAMEQUALS {NAMEQUAL}({SPC}{NAMEQUAL})* STRING [^\r\n""]+ STRING1 [^\r\n'']+ + +QSTRING1 ['']{STRING1}(['']{2}{STRING1})*[''] +QSTRING2 [""]{STRING}([""]{2}{STRING})*[""] + /* comma & semicolon must be followed by a space */ COMMA [,;][[:blank:]]* @@ -1915,12 +1919,10 @@ USE({SPC}FOR)? { return USE; } {ISNT}{SPC}/OMITTED { return NOT; } - [(:)] { return *yytext; } + [:)] { return *yytext; } [(]/[^(:)""'']*[:][^)]*[)] { return LPAREN; /* parentheses around a colon */ } - [(][^:""'']*[:][^)]*[)] { // does not match foo(bar)\n: :-( - int tok = is_refmod(yytext, yytext + yyleng)? - int(LPAREN) : '('; - myless(1); + [(] { + int tok = is_refmod()? int(LPAREN) : '('; return tok; } diff --git a/gcc/cobol/scan_ante.h b/gcc/cobol/scan_ante.h index 402600edabc7..4c147cb994ee 100644 --- a/gcc/cobol/scan_ante.h +++ b/gcc/cobol/scan_ante.h @@ -1321,21 +1321,31 @@ static inline bool is_quote( const char ch ) { return ch == '\'' || ch == '"'; } -static const char* -skip_string(const char* p, const char* pend, char delimiter) { - p++; // Skip opening delimiter - while (p < pend) { - if (p[0] == delimiter) { - if (p[1] == delimiter) { - p += 2; // doubled delimiter is escaped +static int yyinput(); +static void yyunput(int ch, char yytext_ptr[]); + +static std::string +skip_string(char delimiter) { + int ch; + std::string found; + + while ((ch = yyinput()) != EOF ) { + dbgmsg("%s:%d: input '%c'", __func__, __LINE__, ch); + found += ch; + if (ch == delimiter) { + if( (ch = yyinput()) == EOF ) break; + dbgmsg("%s:%d: input '%c'", __func__, __LINE__, ch); + if (ch == delimiter) { + found += ch; + continue; } else { - return ++p; // Found valid closing delimiter + unput(ch); + dbgmsg("%s:%d: unput '%c'", __func__, __LINE__, ch); + return found; // Found valid closing delimiter } - } else { - p++; } } - return pend; + return found; } /* @@ -1349,16 +1359,44 @@ skip_string(const char* p, const char* pend, char delimiter) { * parentheses in the left part, e.g. ((LENGTH OF x/2) - (y/2)) : 1. */ static bool -is_refmod( const char input[], const char enput[] ) { - if( input == enput ) return false; - gcc_assert( *input == '(' ); - int depth = 1; +is_refmod() { + class yystr_t { + std::string text; + public: + ~yystr_t() { + while( ! text.empty() ) { + char ch = text.back(); + text.pop_back(); + unput(ch); + dbgmsg("%s:%d: unput '%c'", __func__, __LINE__, ch); + } + } + int input() { + int ch = yyinput(); + dbgmsg("%s:%d: input '%c'", __func__, __LINE__, ch); + if( ch != EOF) text += ch; + return ch; + } + yystr_t& operator+=( const std::string& that ) { + text += that; + return *this; + } + const char * c_str() const { return text.c_str(); } + size_t size() const { return text.size(); } + } yystr; + + gcc_assert( *yytext == '(' ); + + int ch, depth = 1; bool colon_at_depth1 = false; - for( const char *p = input + 1; p < enput; p++ ) { - char ch = *p; + while( (ch = yystr.input()) != EOF ) { if( is_quote(ch) ) { - p = skip_string(p, enput, ch) - 1; + std::string s = skip_string(ch); + if( s.empty() ) { + break; + } + yystr += s; continue; } if( ch == '(' ) { @@ -1378,6 +1416,6 @@ is_refmod( const char input[], const char enput[] ) { } } dbgmsg("%s:%d: '%.*s' is %sa refmod", __func__, __LINE__, - int(enput - input), input, colon_at_depth1? "" : "not "); + int(yystr.size()), yystr.c_str(), colon_at_depth1? "" : "not "); return colon_at_depth1; }