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" } } */