[PATCH] a68: Fix moids diagnostics buffer overflow [PR122330]

Pietro Monteiro pietro@sociotechnical.xyz
Sat Oct 25 03:33:45 GMT 2025


Even though there's enough room in the buffer the fortified string
functions will abort because the capacity left in the buffer is less
than SNPRINTF_SIZE.

Fix by passing SNPRINTF_SIZE - len (buffer) to snprintf.

Signed-off-by: Pietro Monteiro <pietro@sociotechnical.xyz>
---
 gcc/algol68/a68-moids-diagnostics.cc | 74 ++++++++++++++++------------
 1 file changed, 43 insertions(+), 31 deletions(-)

diff --git a/gcc/algol68/a68-moids-diagnostics.cc b/gcc/algol68/a68-moids-diagnostics.cc
index bd9638cb36c..375bd3dfa83 100644
--- a/gcc/algol68/a68-moids-diagnostics.cc
+++ b/gcc/algol68/a68-moids-diagnostics.cc
@@ -32,17 +32,20 @@ const char *
 a68_mode_error_text (NODE_T *n, MOID_T *p, MOID_T *q, int context, int deflex, int depth)
 {
 #define TAIL(z) (&(z)[strlen (z)])
+#define ACTUAL_SNPRINTF_SIZE ((SNPRINTF_SIZE - len))
   static BUFFER txt;
+  size_t len;
   if (depth == 1)
     txt[0] = '\0';
   if (IS (p, SERIES_MODE))
     {
+      len = strlen (txt);
       PACK_T *u = PACK (p);
 
       int N = 0;
       if (u == NO_PACK)
 	{
-	  if (snprintf (txt, SNPRINTF_SIZE, "empty mode-list") < 0)
+	  if (snprintf (txt, ACTUAL_SNPRINTF_SIZE, "empty mode-list") < 0)
 	    gcc_unreachable ();
 	  N++;
 	}
@@ -56,22 +59,23 @@ a68_mode_error_text (NODE_T *n, MOID_T *p, MOID_T *q, int context, int deflex, i
 		    (void) a68_mode_error_text (n, MOID (u), q, context, deflex, depth + 1);
 		  else if (!a68_is_coercible (MOID (u), q, context, deflex))
 		    {
-		      size_t len = strlen (txt);
+		      len = strlen (txt);
 		      if (len > BUFFER_SIZE / 2)
 			{
-			  if (snprintf (TAIL (txt), SNPRINTF_SIZE, " etcetera") < 0)
+			  if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, " etcetera") < 0)
 			    gcc_unreachable ();
 			  N++;
 			}
 		      else
 			{
-			  if (strlen (txt) > 0)
+			  if (len > 0)
 			    {
-			      if (snprintf (TAIL (txt), SNPRINTF_SIZE, " and ") < 0)
+			      if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, " and ") < 0)
 				gcc_unreachable ();
 			      N++;
+			      len = strlen (txt);
 			    }
-			  if (snprintf (TAIL (txt), SNPRINTF_SIZE, "%s",
+			  if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, "%s",
 					a68_moid_to_string (MOID (u), MOID_ERROR_WIDTH, n)) < 0)
 			    gcc_unreachable ();
 			  N++;
@@ -82,12 +86,14 @@ a68_mode_error_text (NODE_T *n, MOID_T *p, MOID_T *q, int context, int deflex, i
 	}
       if (depth == 1)
 	{
+	  len = strlen (txt);
 	  if (N == 0)
 	    {
-	      if (snprintf (TAIL (txt), SNPRINTF_SIZE, "mode") < 0)
+	      if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, "mode") < 0)
 		gcc_unreachable ();
+	      len = strlen (txt);
 	    }
-	  if (snprintf (TAIL (txt), SNPRINTF_SIZE, " cannot be coerced to %s",
+	  if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, " cannot be coerced to %s",
 			a68_moid_to_string (q, MOID_ERROR_WIDTH, n)) < 0)
 	    gcc_unreachable ();
 	}
@@ -95,10 +101,10 @@ a68_mode_error_text (NODE_T *n, MOID_T *p, MOID_T *q, int context, int deflex, i
   else if (IS (p, STOWED_MODE) && IS_FLEX (q))
     {
       PACK_T *u = PACK (p);
-
+      len = strlen (txt);
       if (u == NO_PACK)
 	{
-	  if (snprintf (txt, SNPRINTF_SIZE, "empty mode-list") < 0)
+	  if (snprintf (txt, ACTUAL_SNPRINTF_SIZE, "empty mode-list") < 0)
 	    gcc_unreachable ();
 	}
       else
@@ -107,26 +113,28 @@ a68_mode_error_text (NODE_T *n, MOID_T *p, MOID_T *q, int context, int deflex, i
 	    {
 	      if (!a68_is_coercible (MOID (u), SLICE (SUB (q)), context, deflex))
 		{
-		  size_t len = strlen (txt);
+		  len = strlen (txt);
 		  if (len > BUFFER_SIZE / 2)
 		    {
-		      if (snprintf (TAIL (txt), SNPRINTF_SIZE, " etcetera") < 0)
+		      if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, " etcetera") < 0)
 			gcc_unreachable ();
 		    }
 		  else
 		    {
-		      if (strlen (txt) > 0)
+		      if (len > 0)
 			{
-			  if (snprintf (TAIL (txt), SNPRINTF_SIZE, " and ") < 0)
+			  if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, " and ") < 0)
 			    gcc_unreachable ();
+			  len = strlen (txt);
 			}
-		      if (snprintf (TAIL (txt), SNPRINTF_SIZE, "%s",
+		      if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, "%s",
 				    a68_moid_to_string (MOID (u), MOID_ERROR_WIDTH, n)) < 0)
 			gcc_unreachable ();
 		    }
 		}
 	    }
-	  if (snprintf (TAIL (txt), SNPRINTF_SIZE, " cannot be coerced to %s",
+	  len = strlen (txt);
+	  if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, " cannot be coerced to %s",
 			a68_moid_to_string (SLICE (SUB (q)), MOID_ERROR_WIDTH, n)) < 0)
 	    gcc_unreachable ();
 	}
@@ -134,10 +142,10 @@ a68_mode_error_text (NODE_T *n, MOID_T *p, MOID_T *q, int context, int deflex, i
   else if (IS (p, STOWED_MODE) && IS (q, ROW_SYMBOL))
     {
       PACK_T *u = PACK (p);
-
+      len = strlen (txt);
       if (u == NO_PACK)
 	{
-	  if (snprintf (txt, SNPRINTF_SIZE, "empty mode-list") < 0)
+	  if (snprintf (txt, ACTUAL_SNPRINTF_SIZE, "empty mode-list") < 0)
 	    gcc_unreachable ();
 	}
       else
@@ -146,26 +154,28 @@ a68_mode_error_text (NODE_T *n, MOID_T *p, MOID_T *q, int context, int deflex, i
 	    {
 	      if (!a68_is_coercible (MOID (u), SLICE (q), context, deflex))
 		{
-		  size_t len = strlen (txt);
+		  len = strlen (txt);
 		  if (len > BUFFER_SIZE / 2)
 		    {
-		      if (snprintf (TAIL (txt), SNPRINTF_SIZE, " etcetera") < 0)
+		      if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, " etcetera") < 0)
 			gcc_unreachable ();
 		    }
 		  else
 		    {
-		      if (strlen (txt) > 0)
+		      if (len > 0)
 			{
-			  if (snprintf (TAIL (txt), SNPRINTF_SIZE, " and ") < 0)
+			  if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, " and ") < 0)
 			    gcc_unreachable ();
+			  len = strlen (txt);
 			}
-		      if (snprintf (TAIL (txt), SNPRINTF_SIZE, "%s",
+		      if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, "%s",
 				    a68_moid_to_string (MOID (u), MOID_ERROR_WIDTH, n)) < 0)
 			gcc_unreachable ();
 		    }
 		}
 	    }
-	  if (snprintf (TAIL (txt), SNPRINTF_SIZE, " cannot be coerced to %s",
+	  len = strlen (txt);
+	  if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, " cannot be coerced to %s",
 			a68_moid_to_string (SLICE (q), MOID_ERROR_WIDTH, n)) < 0)
 	    gcc_unreachable ();
 	}
@@ -173,10 +183,10 @@ a68_mode_error_text (NODE_T *n, MOID_T *p, MOID_T *q, int context, int deflex, i
   else if (IS (p, STOWED_MODE) && (IS (q, PROC_SYMBOL) || IS (q, STRUCT_SYMBOL)))
     {
       PACK_T *u = PACK (p), *v = PACK (q);
-
+      len = strlen (txt);
       if (u == NO_PACK)
 	{
-	  if (snprintf (txt, SNPRINTF_SIZE, "empty mode-list") < 0)
+	  if (snprintf (txt, ACTUAL_SNPRINTF_SIZE, "empty mode-list") < 0)
 	    gcc_unreachable ();
 	}
       else
@@ -185,20 +195,21 @@ a68_mode_error_text (NODE_T *n, MOID_T *p, MOID_T *q, int context, int deflex, i
 	    {
 	      if (!a68_is_coercible (MOID (u), MOID (v), context, deflex))
 		{
-		  size_t len = strlen (txt);
+		  len = strlen (txt);
 		  if (len > BUFFER_SIZE / 2)
 		    {
-		      if (snprintf (TAIL (txt), SNPRINTF_SIZE, " etcetera") < 0)
+		      if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, " etcetera") < 0)
 			gcc_unreachable ();
 		    }
 		  else
 		    {
-		      if (strlen (txt) > 0)
+		      if (len > 0)
 			{
-			  if (snprintf (TAIL (txt), SNPRINTF_SIZE, " and ") < 0)
+			  if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, " and ") < 0)
 			    gcc_unreachable ();
+			  len = strlen (txt);
 			}
-		      if (snprintf (TAIL (txt), SNPRINTF_SIZE, "%s cannot be coerced to %s",
+		      if (snprintf (TAIL (txt), ACTUAL_SNPRINTF_SIZE, "%s cannot be coerced to %s",
 				    a68_moid_to_string (MOID (u), MOID_ERROR_WIDTH, n),
 				    a68_moid_to_string (MOID (v), MOID_ERROR_WIDTH, n)) < 0)
 			gcc_unreachable ();
@@ -209,6 +220,7 @@ a68_mode_error_text (NODE_T *n, MOID_T *p, MOID_T *q, int context, int deflex, i
     }
   return txt;
 #undef TAIL
+#undef ACTUAL_SNPRINTF_SIZE
 }
 
 /* Cannot coerce error.  */
-- 
2.43.0



More information about the Algol68 mailing list