Bug 113922 - -Wstringop-overflow with FORTIFY_SOURCE=3 and O{1,2,3} generates a false positive for 0-sized structs
Summary: -Wstringop-overflow with FORTIFY_SOURCE=3 and O{1,2,3} generates a false posi...
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 13.2.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Keywords: diagnostic
Depends on:
Blocks: Wstringop-overflow
  Show dependency treegraph
Reported: 2024-02-14 20:25 UTC by Sergio Durigan Junior
Modified: 2024-02-14 21:20 UTC (History)
3 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed:

Preprocessed source (10.13 KB, text/plain)
2024-02-14 20:49 UTC, Sergio Durigan Junior

Note You need to log in before you can comment on or make changes to this bug.
Description Sergio Durigan Junior 2024-02-14 20:25:44 UTC

Consider the following example program:

#include <stdio.h>
#include <unistd.h>

int main(void) {
    struct test_st {};
    int fd = 0;
    int count = 0;

    struct test_st test_info[16];
    count = read(fd, test_info, sizeof(test_info));

When compiling it with GCC 13.2 using -D_FORTIFY_SOURCE=3 and -O1, I see:

a.c: In function ‘main’:
a.c:15:13: warning: ‘read’ writing 1 byte into a region of size 0 overflows the destination [-Wstringop-overflow=]
   15 |     count = read(fd, test_info, sizeof(test_info));
      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a.c:10:20: note: destination object ‘test_info’ of size 0
   10 |     struct test_st test_info[16];
      |                    ^~~~~~~~~
In file included from /usr/include/unistd.h:1214,
                 from a.c:3:
/usr/include/x86_64-linux-gnu/bits/unistd.h:26:1: note: in a call to function ‘read’ declared with attribute ‘access (write_only, 2)’
   26 | read (int __fd, void *__buf, size_t __nbytes)
      | ^~~~

GCC allows empty structs on C code and they are correctly sized 0, but -Wstringop-overflow still thinks the code is trying to read 1 byte into the array, which is not correct.

I know there are a lot of false positives reported against -Wstringop-overflow, but I couldn't find an exact duplicate of this one.
Comment 1 Andrew Pinski 2024-02-14 20:29:39 UTC
Can you attach the preprocessed source since this depends on glibc's FORTIFY_SOURCE for value of 3 which is only included in newer glibc's?
Comment 2 Sergio Durigan Junior 2024-02-14 20:49:46 UTC
Created attachment 57431 [details]
Preprocessed source

Sure thing.  Here it is.
Comment 3 Andrew Pinski 2024-02-14 20:52:01 UTC
From https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-access-function-attribute :

>When no size-index argument is specified, the pointer argument must be either null or point to a space that is suitably aligned and large for at least one object of the referenced type (this implies that a past-the-end pointer is not a valid argument).

I think this is a bug in glibc and its (mis)use of the access and write only attribute without a size. 

It has:
 __attribute__ ((__access__ (__write_only__, 2)))

but the documentation for this attribute does not correspond with the above.
Comment 4 Andrew Pinski 2024-02-14 20:56:13 UTC
POSIX definition of read:

>Before any action described below is taken, and if nbyte is zero, the read() function may detect and return errors as described below. In the absence of errors, or if error detection is not performed, the read() function shall return zero and have no other results.

So yes it does look like the use of write_only access is incorrect ...
Comment 5 Andrew Pinski 2024-02-14 21:04:34 UTC
extern ssize_t read (int __fd, void *__buf, size_t __nbytes) __wur
    __fortified_attr_access (__write_only__, 2, 3);

/* For _FORTIFY_SOURCE == 3 we use __builtin_dynamic_object_size, which may
   use the access attribute to get object sizes from function definition
   arguments, so we can't use them on functions we fortify.  Drop the object
   size hints for such functions.  */
#  if __USE_FORTIFY_LEVEL == 3
#    define __fortified_attr_access(a, o, s) __attribute__ ((__access__ (a, o)))
#  else
#    define __fortified_attr_access(a, o, s) __attr_access ((a, o, s))
#  endif

Yes that is broken. Let me file the glibc issue.
Comment 6 Sergio Durigan Junior 2024-02-14 21:05:28 UTC
Thanks for the quick analysis.

It seems that the following glibc commit dropped size hints from access when FORTIFY_SOURCE=3:


I'll report a bug against glibc and mention this conversation.

Comment 7 Sergio Durigan Junior 2024-02-14 21:05:58 UTC
Ah, OK, I'll let you file the bug, then.  Thanks.
Comment 8 Andrew Pinski 2024-02-14 21:07:01 UTC
Moved to glibc issue: