]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c: Fix ICE when using va_arg with arrays [PR97986]
authorMartin Uecker <uecker@tugraz.at>
Fri, 31 Oct 2025 15:10:40 +0000 (16:10 +0100)
committerMartin Uecker <uecker@gcc.gnu.org>
Sat, 1 Nov 2025 06:59:27 +0000 (07:59 +0100)
When array type is passed to va_arg, this is undefined behavior.
Emit a warning, and insert a run-time trap after evaluating side effects,
but return the correct type for sizeof / typeof.  For C90 a VLA is an
error.

PR c/97986

gcc/c/ChangeLog:
* c-parser.cc (c_parser_postfix_expression): Adapt.
* c-tree.h (c_build_va_arg): Adapt prototype.
* c-typeck.cc (c_build_va_arg): Handle UB.

gcc/testsuite/ChangeLog:
* gcc.dg/pr97986-1.c: New test.
* gcc.dg/pr97986-2.c: New test.

gcc/c/c-parser.cc
gcc/c/c-tree.h
gcc/c/c-typeck.cc
gcc/testsuite/gcc.dg/pr97986-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/pr97986-2.c [new file with mode: 0644]

index 0cf3f92a72cbbf99bba849b3169240790c8e1e57..a559a4e6a060bdd0fd97789ed49599d061701a34 100644 (file)
@@ -11793,15 +11793,9 @@ c_parser_postfix_expression (c_parser *parser)
            else
              {
                tree type_expr = NULL_TREE;
+               tree type = groktypename (t1, &type_expr, NULL);
                expr.value = c_build_va_arg (start_loc, e1.value, loc,
-                                            groktypename (t1, &type_expr, NULL));
-               if (type_expr)
-                 {
-                   expr.value = build2 (C_MAYBE_CONST_EXPR,
-                                        TREE_TYPE (expr.value), type_expr,
-                                        expr.value);
-                   C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true;
-                 }
+                                            type, type_expr);
                set_c_expr_source_range (&expr, start_loc, end_loc);
              }
          }
index f367cda35d7c5db3529b67cb456d9c33b998e1d0..ff63d69e85d5e12d9c1c5200a14ae9ae45161a1f 100644 (file)
@@ -917,7 +917,7 @@ extern tree c_omp_finish_mapper_clauses (tree);
 extern tree c_omp_mapper_lookup (tree, tree);
 extern tree c_omp_extract_mapper_directive (tree);
 extern tree c_omp_map_array_section (location_t, tree);
-extern tree c_build_va_arg (location_t, tree, location_t, tree);
+extern tree c_build_va_arg (location_t, tree, location_t, tree, tree);
 extern tree c_finish_transaction (location_t, tree, int);
 extern bool c_tree_equal (tree, tree);
 extern tree c_build_function_call_vec (location_t, const vec<location_t>&,
index bc0fb6b59e556522289b2eed89a3479a64321df9..eba57afac095385d96000268da49c118614fde36 100644 (file)
@@ -18435,7 +18435,8 @@ c_build_qualified_type (tree type, int type_quals, tree orig_qual_type,
 /* Build a VA_ARG_EXPR for the C parser.  */
 
 tree
-c_build_va_arg (location_t loc1, tree expr, location_t loc2, tree type)
+c_build_va_arg (location_t loc1, tree expr, location_t loc2, tree type,
+               tree type_expr)
 {
   if (error_operand_p (type))
     return error_mark_node;
@@ -18459,10 +18460,36 @@ c_build_va_arg (location_t loc1, tree expr, location_t loc2, tree type)
                type);
       return error_mark_node;
     }
+  else if (TREE_CODE (type) == ARRAY_TYPE && C_TYPE_VARIABLE_SIZE (type)
+          && !flag_isoc99)
+    {
+      error_at (loc2, "second argument to %<va_arg%> is an array type %qT",
+               type);
+      return error_mark_node;
+    }
   else if (warn_cxx_compat && TREE_CODE (type) == ENUMERAL_TYPE)
     warning_at (loc2, OPT_Wc___compat,
                "C++ requires promoted type, not enum type, in %<va_arg%>");
-  return build_va_arg (loc2, expr, type);
+
+  if (flag_isoc99 && TREE_CODE (type) == ARRAY_TYPE)
+    {
+      warning_at (loc2, 0, "second argument to %<va_arg%> is an array type %qT",
+                 type);
+      /* We create a trap but evaluate side effects first.  */
+      tree trapfn = builtin_decl_explicit (BUILT_IN_TRAP);
+      trapfn = build_call_expr_loc (loc2, trapfn, 0);
+      tree e2 = build2 (COMPOUND_EXPR, void_type_node, expr, trapfn);
+      /* Return a compound literal of the right type.  */
+      tree e1 = build_compound_literal (loc2, type, NULL, true, 0, NULL);
+      expr = build2 (COMPOUND_EXPR, type, e2, e1);
+    }
+  else
+    expr = build_va_arg (loc2, expr, type);
+
+  if (type_expr)
+    expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), type_expr, expr);
+
+  return expr;
 }
 
 /* Return truthvalue of whether T1 is the same tree structure as T2.
diff --git a/gcc/testsuite/gcc.dg/pr97986-1.c b/gcc/testsuite/gcc.dg/pr97986-1.c
new file mode 100644 (file)
index 0000000..87ee3d8
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+/* { dg-options "-std=gnu23" } */
+
+#include <stdarg.h>
+
+int f(int n, ...)
+{
+       __label__ b, d;
+       va_list ap;
+       va_start(ap, n);
+       _Static_assert(5 == sizeof(va_arg(ap, char[5])));       /* { dg-warning "array type" } */
+       void g(void) { n++; goto b; }
+       int *a = va_arg((g(), ap), int[n]);     /* { dg-warning "array type" } */
+b:
+       void h(void) { n++; goto d; }
+       typeof(va_arg(ap, int[(h(), n)])) c;    /* { dg-warning "array type" } */
+d:
+       return n;
+}
+
+int main()
+{
+       if (9 != f(7))
+               __builtin_abort();
+       return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr97986-2.c b/gcc/testsuite/gcc.dg/pr97986-2.c
new file mode 100644 (file)
index 0000000..fc23a57
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c90" } */
+
+#include <stdarg.h>
+
+
+int f(int n, ...)
+{
+       va_list ap;
+       va_start(ap, n);
+       _Static_assert(5 == sizeof(va_arg(ap, char[5])));
+       va_arg(ap, int[n]);                     /* { dg-error "array type" } */
+       int * a = va_arg(ap, int[3]);           /* { dg-error "invalid use of non-lvalue array" } */
+}
+