[gcc r17-2265] cobol: Do not crash on bad refmod literal. Fix PR 126104.

"James K. Lowden via Gcc-cvs" <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:b95305d39fcf230573a6cc3f56196b8002ef170c

commit r17-2265-gb95305d39fcf230573a6cc3f56196b8002ef170c
Author: James K. Lowden <[email protected]>
Date:   Mon Jul 6 12:09:24 2026 -0400

    cobol: Do not crash on bad refmod literal.  Fix PR 126104.
    
    gcc/cobol/ChangeLog:
    
            * parse.y (literal_refmod_valid): Do not deference NULL pointer.

Diff:
---
 gcc/cobol/parse.y | 67 ++++++++++++++++++++++++++++++-------------------------
 1 file changed, 37 insertions(+), 30 deletions(-)

diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y
index 38205262ad2c..7eed35c1a015 100644
--- a/gcc/cobol/parse.y
+++ b/gcc/cobol/parse.y
@@ -14761,66 +14761,73 @@ literal_refmod_valid( cbl_loc_t loc, const cbl_refer_t& r ) {
 
   unsigned int nchar = r.field->char_capacity();
   const cbl_span_t& refmod(r.refmod);
+  const char *len_name = refmod.len? nice_name_of(refmod.len->field) : "";
 
   // Check ANY LENGTH for initial refmod FROM literal 0. A bit specific....
   if( r.field->has_attr(any_length_e) ) {
     if( is_literal(refmod.from->field) ) {
-      auto edge = refmod.from->field->as_integer();
-      if( edge < 1 ) {
+      auto from = refmod.from->field->as_integer();
+      if( from < 1 ) {
         error_msg(loc,"%s(%zu:%s) out of bounds, must be within 1:%u",
                   r.field->name,
                   size_t(refmod.from->field->as_integer()),
-                  nice_name_of(refmod.len->field),
+                  len_name,
                   nchar );
         return false;
       }
     }
     return true;
   }
-  
+
+  // from is unknown
   if( ! is_literal(refmod.from->field) ) {
     if( ! refmod.len ) return true;
     if( ! is_literal(refmod.len->field) ) return true;
-    auto edge = refmod.len->field->as_integer();
-    if( 0 < edge ) {
-      if( edge-1 < nchar ) return true;
+    auto len = refmod.len->field->as_integer();
+    if( 0 < len ) {
+      if( len-1 < nchar ) return true; // len is less than the field's size
     }
-    // len < 0 or not: 0 < from + len <= capacity
+    // len too big: 0 < from + len <= capacity
     error_msg(loc, "%s(%s:%zu) out of bounds, "
 	           "size is %u",
 	      r.field->name,
 	      refmod.from->name(),
-	      size_t(edge),
+	      size_t(len),
 	      nchar );
     return false;
   }
 
-  auto edge = refmod.from->field->as_integer();
-  if( 0 < edge ) {
-    if( --edge < nchar ) {
-      if( ! refmod.len ) return true;
-      if( ! is_literal(refmod.len->field) ) return true;
-      auto len = refmod.len->field->as_integer();
-      if( len > 0 ) {
-	edge += len;
-	if( --edge < nchar ) return true;
-      }
-      // len < 0 or not: 0 < from + len <= capacity
-      loc = symbol_field_location(field_index(r.field));
-      error_msg(loc, "%s(%zu:%zu) out of bounds, "
-		"size is %u",
-		r.field->name,
-		size_t(refmod.from->field->as_integer()),
-		size_t(len),
-		nchar );
-      return false;
+  gcc_assert(is_literal(refmod.from->field));
+
+  // from is known
+  auto from = refmod.from->field->as_integer();
+  if( 0 < from && from <= nchar ) {
+    // from is in bounds
+    if( ! refmod.len ) return true;
+    if( ! is_literal(refmod.len->field) ) return true;
+    // len is known
+    auto len = refmod.len->field->as_integer();
+    if( 0 < len ) {
+      if( from + len - 2 < nchar ) return true;
     }
+    // from + len too big: 0 < from + len <= capacity
+    loc = symbol_field_location(field_index(r.field));
+    error_msg(loc, "%s(%zu:%zu) out of bounds, "
+      	"size is %u",
+      	r.field->name,
+      	size_t(from),
+      	size_t(len),
+      	nchar );
+    return false;
   }
 
+  // from is too big or 0
+  gcc_assert(from < 1 || nchar <= from);
+
   error_msg(loc,"%s(%zu:%s) out of bounds, must be within 1:%u",
 	    r.field->name,
-	    size_t(refmod.from->field->as_integer()),
-            nice_name_of(refmod.len->field),
+	    size_t(from),
+            len_name,
 	    nchar );
   return false;
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.