public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-2903] Warn for reads from write-only arguments [PR101734].
@ 2021-08-13 18:24 Martin Sebor
  0 siblings, 0 replies; only message in thread
From: Martin Sebor @ 2021-08-13 18:24 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:fb85d6eb6c392e829d1ee5b8a2e2b81c53c9840f

commit r12-2903-gfb85d6eb6c392e829d1ee5b8a2e2b81c53c9840f
Author: Martin Sebor <msebor@redhat.com>
Date:   Fri Aug 13 12:21:20 2021 -0600

    Warn for reads from write-only arguments [PR101734].
    
    Resolves:
    PR middle-end/101734 - missing warning reading from a write-only object
    
    gcc/ChangeLog:
    
            PR middle-end/101734
            * tree-ssa-uninit.c (maybe_warn_read_write_only): New function.
            (maybe_warn_operand): Call it.
    
    gcc/testsuite/ChangeLog:
    
            PR middle-end/101734
            * gcc.dg/uninit-42.c: New test.

Diff:
---
 gcc/testsuite/gcc.dg/uninit-42.c | 87 +++++++++++++++++++++++++++++++++++++++
 gcc/tree-ssa-uninit.c            | 89 ++++++++++++++++++++++++++++++++++++----
 2 files changed, 167 insertions(+), 9 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/uninit-42.c b/gcc/testsuite/gcc.dg/uninit-42.c
new file mode 100644
index 00000000000..efaaacdf9bc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-42.c
@@ -0,0 +1,87 @@
+/* PR middle-end/101734 - missing warning reading from a write-only object
+   Verify that reading objects pointed to by arguments
+   declared with attribute access none or write-only is diagnosed by
+   -Wmaybe-uninitialized.
+   { dg-do compile }
+   { dg-options "-Wall" } */
+
+#define A(mode, ...) __attribute__ ((access (mode, __VA_ARGS__)))
+
+void sink (void *, ...);
+
+
+A (write_only, 1, 2)
+int nowarn_wo_assign_r0 (int *p, int n)
+{
+  *p = n;
+  return *p;
+}
+
+A (write_only, 1, 2)
+int nowarn_wo_sink_r0 (int *p, int n)
+{
+  sink (p, p + 1, p + n);
+  return *p;
+}
+
+A (write_only, 1, 2)
+int warn_wo_r0 (int *p, int n)
+{
+  return *p;        // { dg-warning "'\\*p' may be used uninitialized \\\[-Wmaybe-uninitialized" }
+}
+
+
+A (write_only, 1, 2)
+int nowarn_wo_w1_r1 (int *p, int n)
+{
+  p[1] = n;
+  return p[1];
+}
+
+A (write_only, 1, 2)
+int warn_wo_r1 (int *p, int n)
+{
+  return p[1];      // { dg-warning "'p\\\[1]' may be used uninitialized" }
+}
+
+
+A (write_only, 1, 2)
+int nowarn_wo_rwi_rj (int *p, int n, int i, int j)
+{
+  p[i] = n;
+  return p[j];
+}
+
+A (write_only, 1, 2)
+  int warn_wo_ri (int *p, int n, int i)
+{
+  return p[i];      // { dg-warning " may be used uninitialized" }
+}
+
+
+
+A (none, 1, 2)
+int* nowarn_none_sink_return (int *p, int n)
+{
+  sink (p, p + 1, p + n);
+  return p;
+}
+
+A (none, 1, 2)
+int warn_none_r0 (int *p, int n)
+{
+  (void)&n;
+  return *p;        // { dg-warning "'\\*p' may be used uninitialized" }
+}
+
+A (none, 1, 2)
+int warn_none_r1 (int *p, int n)
+{
+  return p[1];      // { dg-warning "'p\\\[1]' may be used uninitialized" }
+}
+
+A (write_only, 1, 2)
+int warn_none_ri (int *p, int n, int i)
+{
+  return p[i];      // { dg-warning " may be used uninitialized" }
+}
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index 5d7bc800419..d5cdffbae8b 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -283,6 +283,64 @@ builtin_call_nomodifying_p (gimple *stmt)
   return true;
 }
 
+/* If ARG is a FNDECL parameter declared with attribute access none or
+   write_only issue a warning for its read access via PTR.  */
+
+static void
+maybe_warn_read_write_only (tree fndecl, gimple *stmt, tree arg, tree ptr)
+{
+  if (!fndecl)
+    return;
+
+  if (get_no_uninit_warning (arg))
+    return;
+
+  tree fntype = TREE_TYPE (fndecl);
+  if (!fntype)
+    return;
+
+  /* Initialize a map of attribute access specifications for arguments
+     to the function function call.  */
+  rdwr_map rdwr_idx;
+  init_attr_rdwr_indices (&rdwr_idx, TYPE_ATTRIBUTES (fntype));
+
+  unsigned argno = 0;
+  tree parms = DECL_ARGUMENTS (fndecl);
+  for (tree parm = parms; parm; parm = TREE_CHAIN (parm), ++argno)
+    {
+      if (parm != arg)
+	continue;
+
+      const attr_access* access = rdwr_idx.get (argno);
+      if (!access)
+	break;
+
+      if (access->mode != access_none
+	  && access->mode != access_write_only)
+	continue;
+
+      location_t stmtloc
+	= linemap_resolve_location (line_table, gimple_location (stmt),
+				    LRK_SPELLING_LOCATION, NULL);
+
+      if (!warning_at (stmtloc, OPT_Wmaybe_uninitialized,
+		       "%qE may be used uninitialized", ptr))
+	break;
+
+      suppress_warning (arg, OPT_Wmaybe_uninitialized);
+
+      const char* const access_str =
+	TREE_STRING_POINTER (access->to_external_string ());
+
+      location_t parmloc = DECL_SOURCE_LOCATION (parm);
+      inform (parmloc, "accessing argument %u of a function declared with "
+	      "attribute %<%s%>",
+	      argno + 1, access_str);
+
+      break;
+    }
+}
+
 /* Callback for walk_aliased_vdefs.  */
 
 static bool
@@ -350,7 +408,9 @@ struct wlimits
 };
 
 /* Determine if REF references an uninitialized operand and diagnose
-   it if so.  */
+   it if so.  STMS is the referencing statement.  LHS is the result
+   of the access and may be null.  RHS is the variable referenced by
+   the access; it may not be null.  */
 
 static tree
 maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs,
@@ -497,14 +557,25 @@ maybe_warn_operand (ao_ref &ref, gimple *stmt, tree lhs, tree rhs,
   /* Do not warn if it can be initialized outside this function.
      If we did not reach function entry then we found killing
      clobbers on all paths to entry.  */
-  if (!found_alloc
-      && fentry_reached
-      /* ???  We'd like to use ref_may_alias_global_p but that
-	 excludes global readonly memory and thus we get bogus
-	 warnings from p = cond ? "a" : "b" for example.  */
-      && (!VAR_P (base)
-	  || is_global_var (base)))
-    return NULL_TREE;
+  if (!found_alloc && fentry_reached)
+    {
+      if (TREE_CODE (base) == SSA_NAME)
+	{
+	  tree var = SSA_NAME_VAR (base);
+	  if (var && TREE_CODE (var) == PARM_DECL)
+	    {
+	      maybe_warn_read_write_only (cfun->decl, stmt, var, rhs);
+	      return NULL_TREE;
+	    }
+	}
+
+      if (!VAR_P (base)
+	  || is_global_var (base))
+	/* ???  We'd like to use ref_may_alias_global_p but that
+	   excludes global readonly memory and thus we get bogus
+	   warnings from p = cond ? "a" : "b" for example.  */
+	return NULL_TREE;
+    }
 
   /* Strip the address-of expression from arrays passed to functions. */
   if (TREE_CODE (rhs) == ADDR_EXPR)


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-08-13 18:24 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-13 18:24 [gcc r12-2903] Warn for reads from write-only arguments [PR101734] Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).