]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
final: Fix out of bounds access for invalid asm operands [PR123709]
authorAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Sun, 25 Jan 2026 23:08:31 +0000 (15:08 -0800)
committerAndrew Pinski <andrew.pinski@oss.qualcomm.com>
Mon, 26 Jan 2026 19:10:57 +0000 (11:10 -0800)
output_asm_insn has an out of bounds array access if the supplied
operand number in the inline-asm is "big" (>=MAX_RECOG_OPERANDS).
This makes it so that there is no longer an out of bounds access
by increasing the two arrays by one and using the last element as
the fake location for all out of range operands.

This could be a regression because r0-38026-g4f9b4029463bc0 seems like
introduce the out of bounds access but

Bootstrapped and tested on x86_64-linux-gnu.

PR middle-end/123709

gcc/ChangeLog:

* final.cc (output_asm_operand_names): Skip over
opnum which is MAX_RECOG_OPERANDS (invalid).
(output_asm_insn): Increase opoutput and oporder size
by 1. For out of range operands, set the opnum to
MAX_RECOG_OPERANDS.

gcc/testsuite/ChangeLog:

* c-c++-common/asm-invalid-operand-1.c: New test.

Signed-off-by: Andrew Pinski <andrew.pinski@oss.qualcomm.com>
gcc/final.cc
gcc/testsuite/c-c++-common/asm-invalid-operand-1.c [new file with mode: 0644]

index f376f12e5a8a9b272f96a05afb00e863a0f8c052..b5e8c6e2efde01417370e7dea5456ba108b866ed 100644 (file)
@@ -3295,7 +3295,11 @@ output_asm_operand_names (rtx *operands, int *oporder, int nops)
   for (i = 0; i < nops; i++)
     {
       int addressp;
-      rtx op = operands[oporder[i]];
+      int opnum = oporder[i];
+      /* Skip invalid ops. */
+      if (opnum == MAX_RECOG_OPERANDS)
+       continue;
+      rtx op = operands[opnum];
       tree expr = get_mem_expr_from_op (op, &addressp);
 
       fprintf (asm_out_file, "%c%s",
@@ -3428,8 +3432,8 @@ output_asm_insn (const char *templ, rtx *operands)
 #ifdef ASSEMBLER_DIALECT
   int dialect = 0;
 #endif
-  int oporder[MAX_RECOG_OPERANDS];
-  char opoutput[MAX_RECOG_OPERANDS];
+  int oporder[MAX_RECOG_OPERANDS+1];
+  char opoutput[MAX_RECOG_OPERANDS+1];
   int ops = 0;
 
   /* An insn may return a null string template
@@ -3517,7 +3521,11 @@ output_asm_insn (const char *templ, rtx *operands)
              output_operand_lossage ("operand number missing "
                                      "after %%-letter");
            else if (this_is_asm_operands && opnum >= insn_noperands)
-             output_operand_lossage ("operand number out of range");
+             {
+               /* Force the opnum in bounds to a bogus location. */
+               opnum = MAX_RECOG_OPERANDS;
+               output_operand_lossage ("operand number out of range");
+             }
            else if (letter == 'l')
              output_asm_label (operands[opnum]);
            else if (letter == 'a')
@@ -3558,7 +3566,11 @@ output_asm_insn (const char *templ, rtx *operands)
 
            opnum = strtoul (p, &endptr, 10);
            if (this_is_asm_operands && opnum >= insn_noperands)
-             output_operand_lossage ("operand number out of range");
+             {
+               /* Force the opnum in bounds to a bogus location. */
+               opnum = MAX_RECOG_OPERANDS;
+               output_operand_lossage ("operand number out of range");
+             }
            else
              output_operand (operands[opnum], 0);
 
diff --git a/gcc/testsuite/c-c++-common/asm-invalid-operand-1.c b/gcc/testsuite/c-c++-common/asm-invalid-operand-1.c
new file mode 100644 (file)
index 0000000..d8dc79f
--- /dev/null
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* PR middle-end/123709 */
+
+int test1(int a) {
+    asm volatile("%i\n" /* { dg-error "operand number out of range" } */
+                 "505x"
+                 :
+                 : "r"(a));
+    return a;
+}