https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81776
Bug ID: 81776 Summary: missing sprintf optimization due to pointer escape analysis Product: gcc Version: 8.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: msebor at gcc dot gnu.org Target Milestone: --- When a built-in function like memcpy or strcpy is called with a local buffer GCC knows that the call doesn't clobber other local buffers. But the analysis seems to be missing a case to make the same determination for calls to sprintf or snprintf. As a result, as the following case shows, when sprintf if transformed to strcpy, GCC successfully optimizes away the test and subsequent call to abort in g1(). But when the same sprintf to strcpy transformation is defeated by using the '-' flag in the "%-s" directive, GCC fails to make the same optimization in g2(). $ cat a.c && gcc -O2 -S -Wall -fdump-tree-optimized=/dev/stdout b.c void f (void*); struct S { char *a, *b; }; void g1 (struct S *p, const char *s, unsigned n) { p->a = __builtin_malloc (n + 1); p->a[0] = 123; p->b = __builtin_malloc (n + 1); __builtin_sprintf (p->b, "%s", s); if (p->a[0] != 123) // can never be true __builtin_abort (); // eliminated __builtin_sprintf (p->b, "%s", s); f (p); } void g2 (struct S *p, const char *s, unsigned n) { p->a = __builtin_malloc (n + 1); p->a[0] = 123; p->b = __builtin_malloc (n + 1); __builtin_sprintf (p->b, "%-s", s); if (p->a[0] != 123) // can never be true __builtin_abort (); // not eliminated __builtin_sprintf (p->a, "%-s", s); f (p); } ;; Function g1 (g1, funcdef_no=0, decl_uid=1822, cgraph_uid=0, symbol_order=0) g1 (struct S * p, const char * s, unsigned int n) { unsigned int _1; long unsigned int _2; void * _3; void * _4; <bb 2> [100.00%] [count: INV]: _1 = n_8(D) + 1; _2 = (long unsigned int) _1; _3 = __builtin_malloc (_2); p_11(D)->a = _3; MEM[(char *)_3] = 123; _4 = __builtin_malloc (_2); p_11(D)->b = _4; __builtin_strcpy (_4, s_16(D)); __builtin_strcpy (_4, s_16(D)); f (p_11(D)); [tail call] return; } ;; Function g2 (g2, funcdef_no=1, decl_uid=1827, cgraph_uid=1, symbol_order=1) g2 (struct S * p, const char * s, unsigned int n) { unsigned int _1; long unsigned int _2; void * _3; void * _4; char * _5; char _6; <bb 2> [100.00%] [count: INV]: _1 = n_7(D) + 1; _2 = (long unsigned int) _1; _3 = __builtin_malloc (_2); p_10(D)->a = _3; MEM[(char *)_3] = 123; _4 = __builtin_malloc (_2); p_10(D)->b = _4; __builtin_sprintf (_4, "%-s", s_15(D)); _5 = p_10(D)->a; _6 = *_5; if (_6 != 123) goto <bb 3>; [0.04%] [count: 0] else goto <bb 4>; [99.96%] [count: INV] <bb 3> [0.04%] [count: 0]: __builtin_abort (); <bb 4> [99.96%] [count: INV]: __builtin_sprintf (_5, "%-s", s_15(D)); f (p_10(D)); [tail call] return; }