public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c/94815] New: Abusive -Wrestrict warning with sprintf
@ 2020-04-28 11:56 vincent.riviere at freesbee dot fr
  2020-04-28 13:33 ` [Bug c/94815] " rguenth at gcc dot gnu.org
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: vincent.riviere at freesbee dot fr @ 2020-04-28 11:56 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94815

            Bug ID: 94815
           Summary: Abusive -Wrestrict warning with sprintf
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: vincent.riviere at freesbee dot fr
  Target Milestone: ---
            Target: m68k-elf

Testcase:

$ cat foo.c && m68k-elf-gcc -c foo.c -Wall -O
char *strcpy(char *, const char *);
int sprintf(char *, const char *, ...);

char* myalloc(int n);

void f(void)
{
    char* buf = myalloc(20);
    char* str1 = buf;
    char* str2 = buf + 10;

    strcpy(str2, "123");
    sprintf(str1, "ABC%s", str2);
}
foo.c: In function 'f':
foo.c:13:5: warning: 'sprintf' argument 3 may overlap destination object 'buf'
[-Wrestrict]
   13 |     sprintf(str1, "ABC%s", str2);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

This warning is a unexpected because:

1) strcpy() and sprintf() are declared without __restrict, but __restrict rules
are still actually used.

2) In this simple example, it is obvious that the buffer will not overflow.

This is annoying, because it prevents creating several logical buffers from a
single allocation.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug c/94815] Abusive -Wrestrict warning with sprintf
  2020-04-28 11:56 [Bug c/94815] New: Abusive -Wrestrict warning with sprintf vincent.riviere at freesbee dot fr
@ 2020-04-28 13:33 ` rguenth at gcc dot gnu.org
  2020-04-28 14:18 ` msebor at gcc dot gnu.org
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: rguenth at gcc dot gnu.org @ 2020-04-28 13:33 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94815

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |NEW
     Ever confirmed|0                           |1
                 CC|                            |msebor at gcc dot gnu.org
   Last reconfirmed|                            |2020-04-28

--- Comment #1 from Richard Biener <rguenth at gcc dot gnu.org> ---
Confirmed.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug c/94815] Abusive -Wrestrict warning with sprintf
  2020-04-28 11:56 [Bug c/94815] New: Abusive -Wrestrict warning with sprintf vincent.riviere at freesbee dot fr
  2020-04-28 13:33 ` [Bug c/94815] " rguenth at gcc dot gnu.org
@ 2020-04-28 14:18 ` msebor at gcc dot gnu.org
  2020-04-28 14:33 ` msebor at gcc dot gnu.org
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: msebor at gcc dot gnu.org @ 2020-04-28 14:18 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94815

Martin Sebor <msebor at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |WONTFIX
             Status|NEW                         |RESOLVED

--- Comment #2 from Martin Sebor <msebor at gcc dot gnu.org> ---
The warning is only issued with optimization enabled the strlen pass disabled,
such as at -O1, but not at -O2.  The strlen dump below helps explain why: when
the strlen pass doesn't run the warning doesn't compute the length of str2 (as
reflected by the very large value in the Result of the %s directive) and so it
makes a decision solely on the basis that the %s argument points to the same
array as the destination of the sprintf call.  This is by design.   To avoid
the warning under these conditions use a precision in the directive: %.3s.

;; Function f (f, funcdef_no=0, decl_uid=1938, cgraph_uid=1, symbol_order=0)

;; 1 loops found
;;
;; Loop 0
;;  header 0, latch 1
;;  depth 0, outer -1
;;  nodes: 0 1 2
;; 2 succs { 1 }
Computing maximum subobject size for buf_3:
pr94815.c:13: sprintf: objsize = 9223372036854775807, fmtstr = "ABC%s"
  Directive 1 at offset 0: "ABC", length = 3
    Result: 3, 3, 3, 3 (3, 3, 3, 3)
  Directive 2 at offset 3: "%s"
    Result: 0, 0, -1, 9223372036854775807 (3, 3, -1, -1)
  Directive 3 at offset 5: "", length = 1
pr94815.c: In function ‘f’:
pr94815.c:13:5: warning: ‘sprintf’ argument 3 may overlap destination object
‘buf’ [-Wrestrict]
   13 |     sprintf(str1, "ABC%s", str2);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug c/94815] Abusive -Wrestrict warning with sprintf
  2020-04-28 11:56 [Bug c/94815] New: Abusive -Wrestrict warning with sprintf vincent.riviere at freesbee dot fr
  2020-04-28 13:33 ` [Bug c/94815] " rguenth at gcc dot gnu.org
  2020-04-28 14:18 ` msebor at gcc dot gnu.org
@ 2020-04-28 14:33 ` msebor at gcc dot gnu.org
  2020-04-28 15:02 ` vincent.riviere at freesbee dot fr
  2020-04-28 16:58 ` [Bug middle-end/94815] " msebor at gcc dot gnu.org
  4 siblings, 0 replies; 6+ messages in thread
From: msebor at gcc dot gnu.org @ 2020-04-28 14:33 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94815

--- Comment #3 from Martin Sebor <msebor at gcc dot gnu.org> ---
I should add: it's helpful to make use of attribute alloc_size on allocation
functions like myalloc to let GCC determine the size of the allocated objects.
The size can then be used as an upper bound on the lengths of strings stored
there.

The -Wrestrict warning for sprintf doesn't yet make use of it but other
warnings already do and I expect to extend it to sprintf as well.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug c/94815] Abusive -Wrestrict warning with sprintf
  2020-04-28 11:56 [Bug c/94815] New: Abusive -Wrestrict warning with sprintf vincent.riviere at freesbee dot fr
                   ` (2 preceding siblings ...)
  2020-04-28 14:33 ` msebor at gcc dot gnu.org
@ 2020-04-28 15:02 ` vincent.riviere at freesbee dot fr
  2020-04-28 16:58 ` [Bug middle-end/94815] " msebor at gcc dot gnu.org
  4 siblings, 0 replies; 6+ messages in thread
From: vincent.riviere at freesbee dot fr @ 2020-04-28 15:02 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94815

Vincent Riviere <vincent.riviere at freesbee dot fr> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|WONTFIX                     |---
             Status|RESOLVED                    |REOPENED

--- Comment #4 from Vincent Riviere <vincent.riviere at freesbee dot fr> ---
Thanks for your explanations.
But apologies, I oversimplified my real-world testcase. The one below is more
realistic, and still triggers the warning with -O2

$ cat foo.c && m68k-elf-gcc -c foo.c -Wall -O2
char *strcpy(char *, const char *);
int sprintf(char *, const char *, ...);

char* myalloc(int n) __attribute__((alloc_size(1)));

void f(void)
{
    char* buf = myalloc(30);
    char* str1 = buf;
    char* str2 = buf + 10;
    char* str3 = buf + 20;

    strcpy(str3, "123");
    sprintf(str2, "ABC%s", str3);
    sprintf(str1, "DEF%s", str2);
}
foo.c: In function 'f':
foo.c:15:5: warning: 'sprintf' argument 3 may overlap destination object 'buf'
[-Wrestrict]
   15 |     sprintf(str1, "DEF%s", str2);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug middle-end/94815] Abusive -Wrestrict warning with sprintf
  2020-04-28 11:56 [Bug c/94815] New: Abusive -Wrestrict warning with sprintf vincent.riviere at freesbee dot fr
                   ` (3 preceding siblings ...)
  2020-04-28 15:02 ` vincent.riviere at freesbee dot fr
@ 2020-04-28 16:58 ` msebor at gcc dot gnu.org
  4 siblings, 0 replies; 6+ messages in thread
From: msebor at gcc dot gnu.org @ 2020-04-28 16:58 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94815

Martin Sebor <msebor at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
         Resolution|---                         |DUPLICATE
           Keywords|                            |missed-optimization
             Blocks|                            |83819
             Status|REOPENED                    |RESOLVED
          Component|c                           |middle-end

--- Comment #5 from Martin Sebor <msebor at gcc dot gnu.org> ---
The test case in comment #4 isn't handled yet.  Even though the sprintf code
has access to the results of the strlen pass computed for prior string built-in
function calls and so knows the length of str3, it doesn't expose the lengths
of the strings it itself computes to the strlen pass (or track them across
statements) yet so it doesn't "know" the length of str2 computed at the prior
sprintf statement.

When the sprintf pass makes use of attribute alloc_size it will be able to use
the array sizes to improve its analysis but as I mentioned in comment #2 this
isn't implemented yet either.  The effect that we will get once it is can be
emulated by replacing buf with a fixed size array (char buf[30]).  It doesn't
eliminate the warning due to the missing bits above but the output of the
-fdump-tree-strlen option confirms that the warning is due to the strlen
limitation:

pr94815.c:15: sprintf: objsize = 20, fmtstr = "ABC%s"
  Directive 1 at offset 0: "ABC", length = 3
    Result: 3, 3, 3, 3 (3, 3, 3, 3)
  Directive 2 at offset 3: "%s"
    Result: 3, 3, 3, 3 (6, 6, 6, 6)
  Directive 3 at offset 5: "", length = 1
  Substituting 6 for return value.

pr94815.c:18: sprintf: objsize = 30, fmtstr = "DEF%s"
  Directive 1 at offset 0: "DEF", length = 3
    Result: 3, 3, 3, 3 (3, 3, 3, 3)
  Directive 2 at offset 3: "%s"
    Result: 0, 19, 19, 19 (3, 22, 22, 22)   <<< str2 length assumed to be up to
19
  Directive 3 at offset 5: "", length = 1

PR 92813 tracks the enhancement to make the string length information computed
by sprintf across statements (via the strlen pass).

*** This bug has been marked as a duplicate of bug 92813 ***


Referenced Bugs:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83819
[Bug 83819] [meta-bug] missing strlen optimizations

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-04-28 16:58 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-28 11:56 [Bug c/94815] New: Abusive -Wrestrict warning with sprintf vincent.riviere at freesbee dot fr
2020-04-28 13:33 ` [Bug c/94815] " rguenth at gcc dot gnu.org
2020-04-28 14:18 ` msebor at gcc dot gnu.org
2020-04-28 14:33 ` msebor at gcc dot gnu.org
2020-04-28 15:02 ` vincent.riviere at freesbee dot fr
2020-04-28 16:58 ` [Bug middle-end/94815] " msebor at gcc dot gnu.org

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).