]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cobol: Avoid internal compiler error in generated lexer.
authorJames K. Lowden <jklowden@cobolworx.com>
Mon, 3 Aug 2026 18:06:08 +0000 (14:06 -0400)
committerJames K. Lowden <jklowden@cobolworx.com>
Mon, 3 Aug 2026 18:06:40 +0000 (14:06 -0400)
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.

gcc/cobol/scan.l
gcc/cobol/scan_ante.h

index b2843b9c7adf9a4a05a167d93394cc26acf2878f..1de688ee74fed156d3c86a699a04eb4068729845 100644 (file)
@@ -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; 
                                 }
 
index 402600edabc733b953389c6d13cb14ed6763ea9c..4c147cb994ee59d414406c068ed7363ebb88c7c0 100644 (file)
@@ -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;
 }