]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Enable -Walloc-size and -Wcalloc-transposed-args warnings for C++
authorJakub Jelinek <jakub@redhat.com>
Thu, 21 Dec 2023 10:17:08 +0000 (11:17 +0100)
committerJakub Jelinek <jakub@redhat.com>
Thu, 21 Dec 2023 10:17:08 +0000 (11:17 +0100)
The following patch enables the -Walloc-size and -Wcalloc-transposed-args
warnings for C++ as well.

Tracking just 6 arguments for SIZEOF_EXPR for the calloc purposes
is because I see alloc_size 1,2, 2,3 and 3,4 pairs used in the wild,
so we need at least 5 to cover that rather than 3, and don't want to waste
too much compile time/memory for that.

2023-12-21  Jakub Jelinek  <jakub@redhat.com>

gcc/c-family/
* c.opt (Walloc-size): Enable also for C++ and ObjC++.
gcc/cp/
* cp-gimplify.cc (cp_genericize_r): If warn_alloc_size, call
warn_for_alloc_size for -Walloc-size diagnostics.
* semantics.cc (finish_call_expr): If warn_calloc_transposed_args,
call warn_for_calloc for -Wcalloc-transposed-args diagnostics.
gcc/testsuite/
* g++.dg/warn/Walloc-size-1.C: New test.
* g++.dg/warn/Wcalloc-transposed-args-1.C: New test.

gcc/c-family/c.opt
gcc/cp/cp-gimplify.cc
gcc/cp/semantics.cc
gcc/testsuite/g++.dg/warn/Walloc-size-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wcalloc-transposed-args-1.C [new file with mode: 0644]

index 3faab7a891861d564480327f221228cf45842f9f..dbda15486a00b4ad6aec1551e5013d3105036f20 100644 (file)
@@ -332,7 +332,7 @@ C ObjC C++ ObjC++ Var(warn_alloca) Warning
 Warn on any use of alloca.
 
 Walloc-size
-C ObjC Var(warn_alloc_size) Warning LangEnabledBy(C ObjC, Wextra)
+C ObjC C++ ObjC++ Var(warn_alloc_size) Warning LangEnabledBy(C ObjC C++ ObjC++, Wextra)
 Warn when allocating insufficient storage for the target type of the assigned pointer.
 
 Walloc-size-larger-than=
index 64049f4154e2240a913c0b71193c2fd8dbb8bf82..0ece9b00b8ccbf9f89d20d88f05fefcfa11fec25 100644 (file)
@@ -2048,6 +2048,25 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
 
     case NOP_EXPR:
       *stmt_p = predeclare_vla (*stmt_p);
+
+      /* Warn of new allocations that are not big enough for the target
+        type.  */
+      if (warn_alloc_size
+         && TREE_CODE (TREE_OPERAND (stmt, 0)) == CALL_EXPR
+         && POINTER_TYPE_P (TREE_TYPE (stmt)))
+       {
+         if (tree fndecl = get_callee_fndecl (TREE_OPERAND (stmt, 0)))
+           if (DECL_IS_MALLOC (fndecl))
+             {
+               tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (fndecl));
+               tree alloc_size = lookup_attribute ("alloc_size", attrs);
+               if (alloc_size)
+                 warn_for_alloc_size (EXPR_LOCATION (stmt),
+                                      TREE_TYPE (TREE_TYPE (stmt)),
+                                      TREE_OPERAND (stmt, 0), alloc_size);
+             }
+       }
+
       if (!wtd->no_sanitize_p
          && sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT)
          && TYPE_REF_P (TREE_TYPE (stmt)))
index 64839b1ac871fcba95f2304621662963298344b8..33708365ad50c840ff19aa9c71ae5669e3474c10 100644 (file)
@@ -2939,15 +2939,24 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
 
       if (!result)
        {
-         if (warn_sizeof_pointer_memaccess
+         tree alloc_size_attr = NULL_TREE;
+         if (warn_calloc_transposed_args
+             && TREE_CODE (fn) == FUNCTION_DECL
+             && (alloc_size_attr
+                 = lookup_attribute ("alloc_size",
+                                     TYPE_ATTRIBUTES (TREE_TYPE (fn)))))
+           if (TREE_VALUE (alloc_size_attr) == NULL_TREE
+               || TREE_CHAIN (TREE_VALUE (alloc_size_attr)) == NULL_TREE)
+             alloc_size_attr = NULL_TREE;
+         if ((warn_sizeof_pointer_memaccess || alloc_size_attr)
              && (complain & tf_warning)
              && !vec_safe_is_empty (*args)
              && !processing_template_decl)
            {
-             location_t sizeof_arg_loc[3];
-             tree sizeof_arg[3];
+             location_t sizeof_arg_loc[6];
+             tree sizeof_arg[6];
              unsigned int i;
-             for (i = 0; i < 3; i++)
+             for (i = 0; i < (alloc_size_attr ? 6 : 3); i++)
                {
                  tree t;
 
@@ -2964,9 +2973,15 @@ finish_call_expr (tree fn, vec<tree, va_gc> **args, bool disallow_virtual,
                    sizeof_arg[i] = TREE_OPERAND (t, 0);
                  sizeof_arg_loc[i] = EXPR_LOCATION (t);
                }
-             sizeof_pointer_memaccess_warning
-               (sizeof_arg_loc, fn, *args,
-                sizeof_arg, same_type_ignoring_top_level_qualifiers_p);
+             if (warn_sizeof_pointer_memaccess)
+               {
+                 auto same_p = same_type_ignoring_top_level_qualifiers_p;
+                 sizeof_pointer_memaccess_warning (sizeof_arg_loc, fn, *args,
+                                                   sizeof_arg, same_p);
+               }
+             if (alloc_size_attr)
+               warn_for_calloc (sizeof_arg_loc, fn, *args, sizeof_arg,
+                                alloc_size_attr);
            }
 
          if ((complain & tf_warning)
diff --git a/gcc/testsuite/g++.dg/warn/Walloc-size-1.C b/gcc/testsuite/g++.dg/warn/Walloc-size-1.C
new file mode 100644 (file)
index 0000000..3a3f3b0
--- /dev/null
@@ -0,0 +1,52 @@
+// Tests the warnings for insufficient allocation size.
+// { dg-do compile }
+// { dg-options "-Walloc-size -Wno-calloc-transposed-args" }
+
+struct S { int x[10]; };
+void bar (S *);
+typedef __SIZE_TYPE__ size_t;
+void *myfree (void *, int, int);
+void *mymalloc (int, int, size_t) __attribute__((malloc, malloc (myfree), alloc_size (3)));
+void *mycalloc (int, int, size_t, size_t) __attribute__((malloc, malloc (myfree), alloc_size (3, 4)));
+
+void
+foo (void)
+{
+  S *p = (S *) __builtin_malloc (sizeof *p);
+  __builtin_free (p);
+  p = (S *) __builtin_malloc (sizeof p);       // { dg-warning "allocation of insufficient size" }
+  __builtin_free (p);
+  p = (S *) __builtin_alloca (sizeof p);       // { dg-warning "allocation of insufficient size" }
+  bar (p);
+  p = (S *) __builtin_calloc (1, sizeof p);    // { dg-warning "allocation of insufficient size" }
+  __builtin_free (p);
+  bar ((S *) __builtin_malloc (4));            // { dg-warning "allocation of insufficient size" }
+  __builtin_free (p);
+  p = (S *) __builtin_calloc (sizeof *p, 1);
+  __builtin_free (p);
+}
+
+void
+baz (void)
+{
+  S *p = (S *) mymalloc (42, 42, sizeof *p);
+  myfree (p, 42, 42);
+  p = (S *) mymalloc (42, 42, sizeof p);       // { dg-warning "allocation of insufficient size" }
+  myfree (p, 42, 42);
+  p = (S *) mycalloc (42, 42, 1, sizeof p);    // { dg-warning "allocation of insufficient size" }
+  myfree (p, 42, 42);
+  bar ((S *) mymalloc (42, 42, 4));            // { dg-warning "allocation of insufficient size" }
+  myfree (p, 42, 42);
+  p = (S *) mycalloc (42, 42, sizeof *p, 1);
+  myfree (p, 42, 42);
+  p = static_cast <S *> (mycalloc (42, 42, sizeof *p, 1));
+  myfree (p, 42, 42);
+  p = static_cast <S *> (mymalloc (42, 42, sizeof *p));
+  myfree (p, 42, 42);
+  p = static_cast <S *> (mymalloc (42, 42, sizeof p));         // { dg-warning "allocation of insufficient size" }
+  myfree (p, 42, 42);
+  p = static_cast <S *> (mycalloc (42, 42, 1, sizeof p));      // { dg-warning "allocation of insufficient size" }
+  myfree (p, 42, 42);
+  bar (static_cast <S *> (mymalloc (42, 42, 4)));              // { dg-warning "allocation of insufficient size" }
+  myfree (p, 42, 42);
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wcalloc-transposed-args-1.C b/gcc/testsuite/g++.dg/warn/Wcalloc-transposed-args-1.C
new file mode 100644 (file)
index 0000000..fa60583
--- /dev/null
@@ -0,0 +1,54 @@
+// { dg-do compile }
+// { dg-options "-Wcalloc-transposed-args" }
+
+typedef __SIZE_TYPE__ size_t;
+extern "C" void free (void *);
+extern "C" void *calloc (size_t, size_t);
+void *myfree (void *, int, int);
+void *mycalloc (int, int, size_t, size_t) __attribute__((malloc, malloc (myfree), alloc_size (3, 4)));
+
+void
+foo (int n)
+{
+  void *p;
+  p = __builtin_calloc (1, sizeof (int));
+  __builtin_free (p);
+  p = __builtin_calloc (n, sizeof (int));
+  __builtin_free (p);
+  p = __builtin_calloc (sizeof (int), 1);              // { dg-warning "'\[^']*__builtin_calloc\[^']*' sizes specified with 'sizeof' in the earlier argument and not in the later argument" }
+  __builtin_free (p);                                  // { dg-message "earlier argument should specify number of elements, later size of each element" "" { target *-*-* } .-1 }
+  p = __builtin_calloc (sizeof (int), n);              // { dg-warning "'\[^']*__builtin_calloc\[^']*' sizes specified with 'sizeof' in the earlier argument and not in the later argument" }
+  __builtin_free (p);                                  // { dg-message "earlier argument should specify number of elements, later size of each element" "" { target *-*-* } .-1 }
+  p = __builtin_calloc ((sizeof (int)), 1);            // { dg-warning "'\[^']*__builtin_calloc\[^']*' sizes specified with 'sizeof' in the earlier argument and not in the later argument" }
+  __builtin_free (p);                                  // { dg-message "earlier argument should specify number of elements, later size of each element" "" { target *-*-* } .-1 }
+  p = __builtin_calloc (sizeof (int) + 0, 1);
+  __builtin_free (p);
+  p = __builtin_calloc (sizeof (int), sizeof (char));
+  __builtin_free (p);
+  p = __builtin_calloc (1 * sizeof (int), 1);
+  __builtin_free (p);
+  p = calloc (1, sizeof (int));
+  free (p);
+  p = calloc (n, sizeof (int));
+  free (p);
+  p = calloc (sizeof (int), 1);                                // { dg-warning "'\[^']*calloc\[^']*' sizes specified with 'sizeof' in the earlier argument and not in the later argument" }
+  free (p);                                            // { dg-message "earlier argument should specify number of elements, later size of each element" "" { target *-*-* } .-1 }
+  p = calloc (sizeof (int), n);                                // { dg-warning "'\[^']*calloc\[^']*' sizes specified with 'sizeof' in the earlier argument and not in the later argument" }
+  free (p);                                            // { dg-message "earlier argument should specify number of elements, later size of each element" "" { target *-*-* } .-1 }
+  p = calloc (sizeof (int), sizeof (char));
+  free (p);
+  p = calloc (1 * sizeof (int), 1);
+  free (p);
+  p = mycalloc (42, 42, 1, sizeof (int));
+  myfree (p, 42, 42);
+  p = mycalloc (42, 42, n, sizeof (int));
+  myfree (p, 42, 42);
+  p = mycalloc (42, 42, sizeof (int), 1);              // { dg-warning "'\[^']*mycalloc\[^']*' sizes specified with 'sizeof' in the earlier argument and not in the later argument" }
+  myfree (p, 42, 42);                                  // { dg-message "earlier argument should specify number of elements, later size of each element" "" { target *-*-* } .-1 }
+  p = mycalloc (42, 42, sizeof (int), n);              // { dg-warning "'\[^']*mycalloc\[^']*' sizes specified with 'sizeof' in the earlier argument and not in the later argument" }
+  myfree (p, 42, 42);                                  // { dg-message "earlier argument should specify number of elements, later size of each element" "" { target *-*-* } .-1 }
+  p = mycalloc (42, 42, sizeof (int), sizeof (char));
+  myfree (p, 42, 42);
+  p = mycalloc (42, 42, 1 * sizeof (int), 1);
+  myfree (p, 42, 42);
+}