This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] errno can't alias locals (PR 92412)
- From: Martin Sebor <msebor at gmail dot com>
- To: gcc-patches <gcc-patches at gcc dot gnu dot org>, Richard Biener <richard dot guenther at gmail dot com>
- Date: Mon, 11 Nov 2019 15:38:44 -0700
- Subject: [PATCH] errno can't alias locals (PR 92412)
The conditional in default_ref_may_alias_errno has the function
return true even for local variables, implying that locals must
be assumed not to have been changed across calls to errno-setting
functions like malloc. This leads to both worse code and also
false negatives in the strlen pass' detection of buffer overflow
across such calls.
The attached patch constrains the conditional to only consider
external declarations.
Tested on x86_64-linux.
Martin
PR tree-optimization/92412 - excessive errno aliasing assumption defeats optimization
gcc/ChangeLog:
PR tree-optimization/92412
* targhooks.c (default_ref_may_alias_errno): Errono can only alias
extern variables.
gcc/testsuite/ChangeLog:
PR tree-optimization/92412
* gcc.dg/strlenopt-91.c: New test.
Index: gcc/targhooks.c
===================================================================
--- gcc/targhooks.c (revision 278066)
+++ gcc/targhooks.c (working copy)
@@ -1415,9 +1415,11 @@ default_ref_may_alias_errno (ao_ref *ref)
if (TYPE_UNSIGNED (TREE_TYPE (base))
|| TYPE_MODE (TREE_TYPE (base)) != TYPE_MODE (integer_type_node))
return false;
- /* The default implementation assumes an errno location
- declaration is never defined in the current compilation unit. */
+ /* The default implementation assumes an errno location declaration
+ is never defined in the current compilation unit and may not be
+ aliased by a local variable. */
if (DECL_P (base)
+ && DECL_EXTERNAL (base)
&& !TREE_STATIC (base))
return true;
else if (TREE_CODE (base) == MEM_REF
Index: gcc/testsuite/gcc.dg/strlenopt-91.c
===================================================================
--- gcc/testsuite/gcc.dg/strlenopt-91.c (nonexistent)
+++ gcc/testsuite/gcc.dg/strlenopt-91.c (working copy)
@@ -0,0 +1,124 @@
+/* PR tree-optimization/92412 - excessive errno aliasing assumption defeats
+ optimization
+ { dg-do compile }
+ { dg-options "-O1 -Wall -fdump-tree-optimized" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void* alloca (size_t);
+extern void* calloc (size_t, size_t);
+extern void* malloc (size_t);
+
+extern const char exta[4];
+static char stata[] = "123";
+
+void sink (const void*, ...);
+
+#define T(ptr, alloc) do { \
+ const char *p = ptr; \
+ if (p[0] != '1' || p[1] != '2' || p[2] != '3' || p[3] != '\0' \
+ || __builtin_strlen (p) != 3) \
+ return; \
+ \
+ void *q = alloc; \
+ __builtin_strcpy (q, p); \
+ \
+ if (p[0] != '1' || p[1] != '2' || p[2] != '3' || p[3] != '\0' \
+ || __builtin_strlen (p) != 3 \
+ || __builtin_strlen (q) != 3) \
+ __builtin_abort (); \
+ \
+ sink (p, q); \
+ } while (0)
+
+
+void alloca_test_local (unsigned n)
+{
+ char loca[] = "123";
+ T (loca, alloca (n));
+}
+
+void alloca_test_extern_const (unsigned n)
+{
+ T (exta, alloca (n));
+}
+
+void alloca_test_static (unsigned n)
+{
+ T (stata, alloca (n));
+}
+
+
+// Verify fix for PR tree-optimization/92412.
+void calloc_test_local (unsigned m, unsigned n)
+{
+ char loca[] = "123";
+ T (loca, calloc (m, n));
+}
+
+void calloc_test_extern_const (unsigned m, unsigned n)
+{
+ T (exta, calloc (m, n));
+}
+
+void calloc_test_static (unsigned m, unsigned n)
+{
+ T (stata, calloc (m, n));
+}
+
+
+// Verify fix for PR tree-optimization/92412.
+void malloc_test_local (unsigned n)
+{
+ char loca[] = "123";
+ T (loca, malloc (n));
+}
+
+void malloc_test_extern_const (unsigned n)
+{
+ T (exta, malloc (n));
+}
+
+void malloc_test_static (unsigned n)
+{
+ T (stata, malloc (n));
+}
+
+
+#undef T
+#define T(ptr, n) do { \
+ const char *p = ptr; \
+ if (p[0] != '1' || p[1] != '2' || p[2] != '3' || p[3] != '\0' \
+ || __builtin_strlen (p) != 3) \
+ return; \
+ \
+ char vla[n]; \
+ char *q = vla; \
+ __builtin_strcpy (q, p); \
+ \
+ if (p[0] != '1' || p[1] != '2' || p[2] != '3' || p[3] != '\0' \
+ || __builtin_strlen (p) != 3 \
+ || __builtin_strlen (q) != 3) \
+ __builtin_abort (); \
+ \
+ sink (p, vla); \
+ } while (0)
+
+
+void vla_test_local (unsigned n)
+{
+ char loca[] = "123";
+ T (loca, n);
+}
+
+void vla_test_extern_const (unsigned n)
+{
+ T (exta, n);
+}
+
+void vla_test_static (unsigned n)
+{
+ T (stata, n);
+}
+
+/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */